FriendlyCaptcha / friendly-challenge

The widget and docs for the proof of work challenge used in Friendly Captcha. Protect your websites and online services from spam and abuse with Friendly Captcha, a privacy-first anti-bot solution.
https://friendlycaptcha.com
MIT License
412 stars 59 forks source link

Need some help getting started - widget isn't rendering #11

Closed S-u-m-u-n closed 3 years ago

S-u-m-u-n commented 3 years ago

Hi, I am trying to integrate the Friendly Captcha widget in my React web app. I tried to follow the tutorial https://docs.friendlycaptcha.com/#/installation, and have a few questions:

I'm grateful for any kind of advice you can give me. I also think the documentation would be better with a small working example in React. I would be willing to make a PR for it, if I manage to make it work.

S-u-m-u-n commented 3 years ago

Okay, I managed to make it work by loosely following the example code here: https://github.com/FriendlyCaptcha/friendly-challenge/issues/7.

Should I make a PR with a small working React example?

gzuidhof commented 3 years ago

Hi S-u-m-u-n,

I wrote up this example (now I see you got it to work, but I'll post it anyway :) )

import React from "react";
import ReactDOM from "react-dom";
import { WidgetInstance } from "friendly-challenge";

const FRIENDLYCAPTCHA_SITEKEY = "FCMGEMUD2KTDSQ5H";

class App extends React.Component {
  widget = undefined;

  constructor(props) {
    super(props);
    this.captchaWidgetRef = React.createRef();
    this.state = { solution: "No solution yet" };
  }

  componentDidMount() {
    const el = this.captchaWidgetRef.current;
    this.widget = new WidgetInstance(el, {
      doneCallback: (solution) => {
        // The captcha was completed
        this.setState({ solution: solution });
      }
    });
  }

  resetCaptchaWidget() {
    // Reset the widget (a solution can only be used once, so usually you do this after submitting it).
    if (this.widget) this.widget.reset();
  }

  render() {
    return (
      <div>
        <h1>Example in React</h1>
        <div
          class="frc-captcha"
          ref={this.captchaWidgetRef}
          data-sitekey={FRIENDLYCAPTCHA_SITEKEY}
        ></div>
        Solution: {this.state.solution}
        </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("container"));

Here's a playground link.

I haven't used React in years now so it's probably not very idiomatic.. A PR with an example would be fantastic!

S-u-m-u-n commented 3 years ago

Hey @gzuidhof. Thanks a lot for your example! I will make a PR with my version soon, I just have one final problem: After the CAPTCHA is finished with solving the puzzle, it immediately says "I'm not a robot" without waiting for validation, i.e. as soon as doneCallback() is called. Is this the intended behavior? Shouldn't it wait until the POST request confirms that the solution is correct before concluding that the user is human?

Anyways, I am trying to verify the CAPTCHA solution via a POST request to https://friendlycaptcha.com/api/v1/siteverify and keep getting a 400 error with no status text. I am providing my secret API key, so that shouldn't be the problem. Any ideas what could be wrong?

The documentation states: "In the form data sent to the server, there will be an extra text field called frc-captcha-solution. We will send this string to the FriendlyCaptcha servers to verify that the CAPTCHA was completed successfully." Does that mean I should first receive the data filled in the form including the frc-captcha-solution before validating the CAPTCHA solution? Isn't the idea that we first check whether the user submitting the form is a bot, and then send the form data only if the user isn't a bot?

Sorry for my many questions, I have never used CAPTCHAs before and am a bit overwhelmed.

gzuidhof commented 3 years ago

So how it works is that the user's computer solves a puzzle, after they are done it shows "I'm not a robot", this solution can be used as a "payment". Then when the user submits the form, or whatever other action you want to use the captcha for, you would send along the payment.

Does that mean I should first receive the data filled in the form including the frc-captcha-solution before validating the CAPTCHA solution? Isn't the idea that we first check whether the user submitting the form is a bot, and then send the form data only if the user isn't a bot?

Yes, that's how it works. Maybe it's counterintuitive, but the core problem here is that the user can't be trusted. They could change your javascript to just disable the check completely if it happened client side.

So on your server (not in the browser!) you would verify this solution by making the POST request. With the request you find out if it is valid and if it hasn't been used before. Then you decide to do something with the data the user has sent to you, or reject it.

S-u-m-u-n commented 3 years ago

Thanks a lot for your clarification! It makes a lot more sense now. I have made PR #12, if you want to include my example in the docs. Feel free to close this issue. :)