Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spam protection using HoneyPot field #276

Open
martinpesout opened this issue Jan 14, 2025 · 3 comments
Open

Spam protection using HoneyPot field #276

martinpesout opened this issue Jan 14, 2025 · 3 comments
Assignees
Labels
question Further information is requested

Comments

@martinpesout
Copy link

martinpesout commented Jan 14, 2025

I'm trying to create a form with spam protection using the HoneyPot field. So my code is something like this:

const contactFormDefaultValues = { email: "", message: "", somethingSweet: "" }

export const contactFormSchema = z.object({
  message: z
    .string()
    .min(1, "Please enter some message.")
    .min(10, "Can you be more specific?"),
  email: z
    .string()
    .min(1, "Please enter your e-mail.")
    .email("Please enter a valid e-mail."),
  somethingSweet: z // bot honey trap
    .string()
    .max(0, "Please leave this field empty."),
})

const [contactForm, { Form, Field }] = useForm<ContactForm, ResponseData>({
  loader: { value: contactFormDefaultValues },
  action: useFormAction(),
  validate: zodForm$(contactFormSchema),
})

return (
  <Form id="contact">
    <Field name="message">
      {(field, props) => (
        <input
          {...props}
          value={field.value}
          aria-invalid={!!field.error}
          placeholder="Your message"
          required
        />
      )}
    </Field>

    <Field name="email">
      {(field, props) => (
        <input
          {...props}
          value={field.value}
          aria-invalid={!!field.error}
          type="email"
          placeholder="[email protected]"
          required
        />
      )}
    </Field>

    <Field name="somethingSweet">
      {(field, props) => (
        <input
          {...props}
          value={field.value}
          aria-invalid={!!field.error}
          type="text"
        />
      )}
    </Field>
  </Form>
)

When I use only keyboard interaction, everything works (even validation of somethingSweet field is ok). However, this is useless to me in protecting against spam. Spam is still coming. I'll try to simulate filling the value of the field with id somethingSweet using JavaScript. For example, in DevTools I use $('#somethingSweet').value = 'test' or manually change the DOM again using DevTools. When I do this, validation isn't triggered because whole form frameworks isn't able to recognise that some value has been entered. How I can do HoneyPot spam protection using Modular Forms? Is that possible? Or am I doing something wrong?

I also tried to check values present in useFormAction() method, but I'm getting the same situation. When I fill in the value using $('#somethingSweet').value = 'test' in my browser, this field looks still as unchanged.

@martinpesout
Copy link
Author

I'm a bit worried that the problem is caused by the nature of the Field component https://github.com/fabian-hiller/modular-forms/blob/main/packages/qwik/src/components/Field.tsx because it seems to me, that an external update of the text input value (e.g. by $('#somethingSweet').value = 'test') doesn't trigger necessary update in the Field to store new field value.

@fabian-hiller
Copy link
Owner

How about checking if the honeypot contains an input after submitting? You could access the element directly and check if it contains an input.

@fabian-hiller fabian-hiller self-assigned this Jan 14, 2025
@fabian-hiller fabian-hiller added the question Further information is requested label Jan 14, 2025
@martinpesout
Copy link
Author

martinpesout commented Jan 14, 2025

@fabian-hiller Interesting idea. If I want to do that how I can directly access the element in useFormAction()? I think that I have to create something like const honeyPotRef = useSignal<HTMLInputElement>() referencing the HTML input field. But how I can pass this const into defined action? My action method looks like this:

export const useFormAction = formAction$<ContactForm, ResponseData>(
  async (values, event) => {

  .... some code ...

  },
  zodForm$(contactFormSchema)
)

To clarify the context... I'm switching to Qwik from React, and I'm still struggling a bit with how to pass extra information like this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants