In previous episode, we prepared an architecture of the project and environment for development. Today, we are going to write a client-side application for handling canvas and captcha in the browser.
PIXI.js
To control canvas we are going to use PIXI.js, so move to the project directory and install by running:
yarn add pixi.js
Then import in the main component of the canvas.
import * as PIXI from 'pixi.js';
To use the PIXI library, we need to create a PIXI Application and append view somewhere on the website. Because we are working on the widget-like tool, application view is going to be attached inside of the component. The application we will create on the first mounting with componentDidMount
method or even in the constructor. In my case, the second option is cleaner, because I won't be switching between different components.
export class App extends React.Component<any, IApp> { constructor(props : any) { super(props); this.state = { app: new PIXI.Application({ width: 480, height: 280, backgroundColor: 0xeeeeee, resolution: window.devicePixelRatio || 1, }), }; }// ...}
On the first line, you see that I'm telling that interface IApp is going to define how the state of the component is going to looks like. Now, just PIXI application under "app" key is fine.
interface IApp { app: PIXI.Application}
In the initial state, I created new PIXI Application instance with the width and height of the canvas and very bright colour in the background.
View for our application we can append in the previously mentioned componentDidMount like below:
componentDidMount() { document.getElementById('devcaptcha-container').appendChild(this.state.app.view);}
And inside render method we need to create HTML elemenet with devcaptcha-container id:
render() { return <div id={"devcaptcha-container"}/>; }
If you did everything well, you should be able to render rectangle somewhere in your application.
Canvas Elements
Now, we need to add canvas elements for captcha. My captcha will contain:
- instruction how to use captcha,
- white stripes on the top and the bottom as the background for text and button,
- button for submitting a captcha response,
- image background with a picture from the backend with a drawn puzzle,
- puzzle element to drag and drop to match with this from backend,
PIXI has various classes for representing canvas elements. For the background, we can use Sprite and alternative construction method, which as argument accept image URL.
const background = PIXI.Sprite.from('https://placeholderimg.jpg');
And then set some properties. In this case, we want to stretch the background on the entire canvas. Initial anchor point (position point) of the elements in PIXI is in the top-left corner. Co our background sprite should start at position 0,0 (top-left edge of the canvas) and be 100% width and height. We can use for that previously saved reference to the object of PIXI application, and view.
background.width = this.state.app.view.width;background.height = this.state.app.view.height;
And finally, we can append this background object inside view:
this.state.app.stage.addChild(background);
Awesome! At this point, you should see your image in the background. Now let add white, background stripes. We are going to use for this Graphics class, which is responsible for primitive, vector shapes. With this class, we can add two 32px stripes for top and the bottom and two 4px thin shadow lines.
// top stripe const stripes = new PIXI.Graphics(); stripes.beginFill(0xffffff); stripes.drawRect(0, 0, this.state.app.view.width, 32 ); stripes.endFill(); // bottom stripe stripes.beginFill(0xffffff); stripes.drawRect(0, this.state.app.view.height - 32, this.state.app.view.width, 32 ); // top shadow stripes.beginFill(0xdddddd, 0.5); stripes.drawRect(0, 32, this.state.app.view.width, 4 ); stripes.endFill(); // bottom shadow stripes.beginFill(0xdddddd, 0.5); stripes.drawRect(0, this.state.app.view.height - 36, this.state.app.view.width, 4 ); stripes.endFill(); this.state.app.stage.addChild(stripes);
We also need a button for submitting the captcha response. We will use the same class as previously. But this time, we will set properties for interactive and event listener.
// submit button const submitButton = new PIXI.Graphics(); submitButton.interactive = true; submitButton.buttonMode = true; submitButton.on('pointerdown', () => { // on mouse fire }); submitButton.beginFill(0x222222); submitButton.drawRect(this.state.app.view.width - 112, this.state.app.view.height - 64, 96, 48 ); submitButton.endFill(); this.state.app.stage.addChild(submitButton);
Text on the top will inform how to solve captcha:
// instruction const basicText = new PIXI.Text('Move the jigsaw to the correct position to solve captcha.', { fontFamily: 'Arial', fontSize: 16, fill: '#000000', }); basicText.x = 8; basicText.y = 8; this.state.app.stage.addChild(basicText);
And the second on the button:
// text on the submit button const submitButtonText = new PIXI.Text('Submit', { fontFamily: 'Arial', fontSize: 14, fill: '#ffffff', }); submitButtonText.x = this.state.app.view.width - 112 + 40; submitButtonText.y = this.state.app.view.height - 64 + 16; this.state.app.stage.addChild(submitButtonText);
To make this button look better, I added icon:
// icon on the submit button const submitButtonIcon = PIXI.Sprite.from('https://i.imgur.com/mgWUPWc.png'); submitButtonIcon.width = 24; submitButtonIcon.height = 24; submitButtonIcon.x = this.state.app.view.width - 112 + 12; submitButtonIcon.y = this.state.app.view.height - 64 + 12; this.state.app.stage.addChild(submitButtonIcon);
And finally, two more labels for Terms of Service and Privacy Policy:
// privacy policy const textPrivacy = new PIXI.Text('Privacy', { fontFamily: 'Arial', fontSize: 12, fill: '#777777', }); textPrivacy.interactive = true; textPrivacy.buttonMode = true; textPrivacy.on('pointerdown', () => { // pp }); textPrivacy.anchor.set(0.5, 0.5); textPrivacy.x = 24; textPrivacy.y = this.state.app.view.height - 16; this.state.app.stage.addChild(textPrivacy); // terms of service const textTerms = new PIXI.Text('Terms', { fontFamily: 'Arial', fontSize: 12, fill: '#777777', }); textTerms.interactive = true; textTerms.buttonMode = true; textTerms.on('pointerdown', () => { // tos }); textTerms.anchor.set(0.5, 0.5); textTerms.x = 72; textTerms.y = this.state.app.view.height - 16; this.state.app.stage.addChild(textTerms);
Puzzle
Now we need to add puzzle with drag and drop. Puzzle will be Sprite instance with interactive and buttonMode set to true. Also we need to bind event listeners to proper methods. And becuase we want to use our captcha on both mobile and pc we must ensure all input methods are supported.
// puzzle const puzzle = PIXI.Sprite.from('https://i.imgur.com/sNPmMi2.png'); puzzle.anchor.set(0.5, 0.5); puzzle.alpha = 0.5; puzzle.interactive = true; puzzle.buttonMode = true; puzzle.x = 64; puzzle.y = this.state.app.view.height / 2; puzzle.on('mousedown', this.onDragStart) .on('touchstart', this.onDragStart) .on('mouseup', this.onDragEnd) .on('mouseupoutside', this.onDragEnd) .on('touchend', this.onDragEnd) .on('touchendoutside', this.onDragEnd) .on('mousemove', this.onDragMove) .on('touchmove', this.onDragMove); this.setState(() => { return { puzzle } }); this.state.app.stage.addChild(puzzle);
Methods onDragStart, on dragEnd, onDragMove are required in the component class. On drag start, we are setting dragging flag in the component state to true, and on drag end to false. When moving cursor or finger above the canvas, onDragMove method will be fired, so we need to make sure we are dragging when holding puzzle piece. Event for onDragMove contains distance from the previous call. And it may be positive or negative.
onDragStart() { this.setState(() => { return { dragging: true, }; }); } onDragEnd() { this.setState(() => { return { dragging: false, }; }); } onDragMove(event : any) { if (this.state.dragging) { const puzzle = this.state.puzzle; puzzle.position.x += event.data.originalEvent.movementX; puzzle.position.y += event.data.originalEvent.movementY; } }
With this puzzle, we need to add to our state two more properties and bind three new methods to class::
interface IApp { app: PIXI.Application, dragging: boolean, puzzle: PIXI.Sprite,}export class App extends React.Component<any, IApp> { constructor(props : any) { super(props); this.state = { app: new PIXI.Application({ width: 480, height: 280, backgroundColor: 0xeeeeee, resolution: window.devicePixelRatio || 1, }), dragging: false, puzzle: null }; this.onDragEnd = this.onDragEnd.bind(this); this.onDragStart = this.onDragStart.bind(this); this.onDragMove = this.onDragMove.bind(this); }// ...}
You should be able to drag the puzzle over the canvas and click on the submit button and small text on the bottom of the canvas.
Congratulations! In the next episode I will explain backend side of the mechanism, so If you want to be notified about the next part, follow me on DEV.to. 😉
Meat Boy
Current source code is available on GitHub. Please, leave a star ⭐ if you like project.
pilotpirxie / devcaptcha
🤖 Open source captcha made with React, Node and TypeScript for DEV.to community
Open source captcha made with React, Node and TypeScript for DEV.to community
Features
- Fast and efficient, uses Redis as temp storage,
- Implements leading zero challenge,
- Requires image recognition to find coordinates on a background,
- Customizable, you can easily tailor to your needs,
- Simple integration in just few minutes,
- Written with Typescript, React, Node and Express,
Getting started
git clone https://github.com/pilotpirxie/devcaptcha.gitcd devcaptcha/devcaptcha-serveryarn installyarn start
Integration
Captcha should be configured equally on the client and backend side to works correctly.
const devcaptcha = new DevCaptcha({ appendSelector: '#captcha', promptText: 'Move the puzzle to the correct position to solve captcha', lockedText: 'Locked', savingText: 'Wait', privacyUrl: 'https://example.com', termsUrl: 'https://example.com', baseUrl: 'http://localhost:8081', puzzleAlpha: 0.9, canvasContainerId: 'devcaptcha-container', leadingZerosLength: 3, workerPath: './worker.js'});
Client Config Definition:
export type CaptchaConfig
…
FAQs
How do you implement custom Captcha in react JS? ›
- Installing react-google-recaptcha.
- Adding reCAPTCHA.
- Getting the response token.
- Resetting reCAPTCHA for subsequent checks.
- Verifying the token in the Node.js backend.
- Import all functions from react-simple-captcha. ...
- Place < LoadCanvasTemplate /> or < LoadCanvasTemplateNoReload /> (if you do not want 'Reload Captcha' functionality) in your render code.
- Paste loadCaptchaEnginge(6) (You can change 6 to number of captcha charcters you want) in componentDidMount.
ReactPixi is an open source library for rendering high-performant PixiJS applications in React. The library provides useful components that make writing PixiJS applications easier and faster using React's declarative style.
How do you add reCAPTCHA v3 in react? ›- Generate google reCAPTCHA v3 keys.
- Create a react application.
- Add google reCAPTCHA in component.
- Call a backend API to verify reCAPTCHA response.
- Visit the Google reCAPTCHA admin console.
- Click the '+' icon to register a new site/application.
- Select captcha version as reCAPTCHA v2 and type as invisible.
- Copy your site and private keys for further use.
- Add domain of your application in the allowed domains list.
Learning Pixi Table of contents Introduction Setting up Installing Pixi Creating the Pixi Application and stage Pixi sprites Loading images into the texture cache Displaying sprites Using aliases A little more about loading things Make a sprite from an ordinary JavaScript Image object or Canvas Assigning a name to a ...
What is Pixi legacy? ›pixi. js-legacy is a superset of pixi. js , including both WebGL and Canvas (in practice, installing the legacy one with npm automatically installs the other one, not sure what the minified versions do).
Does Phaser use Pixi? ›Phaser uses Pixi for rendering, albeit an older and heavily modified version of it. Current versions of Pixi may give you better performance, but you'll have to implement by hand what's readily available in Phaser. They are different by that Pixi is a rendering engine and Phaser is a game framework.
How is reCAPTCHA token generated? ›For web users, you can get the user's response token in one of three ways: g-recaptcha-response POST parameter when the user submits the form on your site. grecaptcha.getResponse(opt_widget_id) after the user completes the reCAPTCHA challenge.
How does react App implement reCAPTCHA? ›How To Implement reCAPTCHA In ReactJS - YouTube
What is the difference between reCAPTCHA v2 and v3? ›
reCAPTCHA v3 verifies requests with a score and gives you the ability to take action in the context of your site. reCAPTCHA v2 verifies if an interaction is legitimate with the “I am not a robot” checkbox and invisible reCAPTCHA badge challenges.
How does reCAPTCHA v3 works? ›reCAPTCHA v3 returns a score for each request without user friction. The score is based on interactions with your site and enables you to take an appropriate action for your site. Register reCAPTCHA v3 keys on the reCAPTCHA Admin console. This page explains how to enable and customize reCAPTCHA v3 on your webpage.
How do I use Google reCAPTCHA v3? ›Register your website and get Secret Key
Very first thing you need to do is register your website on Google reCAPTCHA to do that click here. Login to your Google account and create the app by filling the form. Select the reCAPTCHA v3 and in that select the “I am not a robot” checkbox option.
To develop and test your reCAPTCHA implementation locally, you'll need to have it served to your localhost. I do this by using Express, which requires Node and NPM. Now you should be able to open your browser and go to http://localhost:3000/your-page.html and see your reCAPTCHA token being logged out to the console.
How do I find the reCAPTCHA key? ›- In the Google Cloud console, go to the reCAPTCHA Enterprise page. Go to reCAPTCHA Enterprise.
- Verify that the name of your project appears in the resource selector at the top of the page. ...
- Click Create key.
- In the Display name field, enter a display name for the key.
- Create a site key for a website or mobile platform.
- Register with Google reCAPTCHA. Visit https://www.google.com/recaptcha/admin/create and register a new site. ...
- Install react-native-recaptchav3. Install the React Native Plugin with npm or yarn command as follows: # npm i @haskkor/react-native-recaptchav3. ...
- Usage in Code. ...
- Token Verification.
The invisible reCAPTCHA badge does not require the user to click on a checkbox, instead it is invoked directly when the user clicks on an existing button on your site or can be invoked via a JavaScript API call. The integration requires a JavaScript callback when reCAPTCHA verification is complete.
How do I add reCAPTCHA to contact form react? ›Within your terminal type yarn add react-google-recaptcha to add the package. After installation just head over to the FormStart. jsx file and import it. Now we'll add the component to the form, right before the submit button.
How is reCAPTCHA token generated? ›For web users, you can get the user's response token in one of three ways: g-recaptcha-response POST parameter when the user submits the form on your site. grecaptcha.getResponse(opt_widget_id) after the user completes the reCAPTCHA challenge.
How do I enable the key for Invisible Captcha? ›- Open this page and fill in the name of your website;
- Select the Invisible ReCaptcha option from the list of the available variants;
- Specify the domain of your website;
- Tick the Terms of Service checkbox;
- Hit the Register button.
What is the difference between reCAPTCHA v2 and v3? ›
reCAPTCHA v3 verifies requests with a score and gives you the ability to take action in the context of your site. reCAPTCHA v2 verifies if an interaction is legitimate with the “I am not a robot” checkbox and invisible reCAPTCHA badge challenges.
How do I use Google reCAPTCHA v3? ›- Placement on your website. ...
- Automatically bind the challenge to a button. ...
- Programmatically invoke the challenge. ...
- Interpreting the score. ...
- Actions. ...
- Site Verify Response.
In react code, we start with importing reCAPTCHA from react-google-recaptcha package. import ReCAPTCHA from 'react-google-recaptcha'; In the required component, we can add the reCAPTCHA just as any other tag with few props that are required to work properly such as the sitekey .
How do I find the reCAPTCHA key? ›- In the Google Cloud console, go to the reCAPTCHA Enterprise page. Go to reCAPTCHA Enterprise.
- Verify that the name of your project appears in the resource selector at the top of the page. ...
- Click Create key.
- In the Display name field, enter a display name for the key.
- Create a site key for a website or mobile platform.
reCAPTCHA is a free service that protects your website from spam and abuse. reCAPTCHA uses an advanced risk analysis engine and adaptive challenges to keep automated software from engaging in abusive activities on your site.
Do reCAPTCHA keys expire? ›Recaptcha Captcha
The keys shouldn't expire.
Add Google reCAPTCHA to a form
Click the pencil icon or Edit on the form or newsletter block. In the Storage tab, click Google reCAPTCHA. Switch the Use Google reCAPTCHA toggle on. Repeat these steps for all form blocks on your site where you want to add a reCAPTCHA.
reCAPTCHA v2 (Invisible reCAPTCHA badge)
The invisible reCAPTCHA badge does not require the user to click on a checkbox, instead it is invoked directly when the user clicks on an existing button on your site or can be invoked via a JavaScript API call.
- Make sure you have single Google Account sign-in. ...
- Download the Captcha for Forms apps script. ...
- Open your forms.
- Copy bundle. ...
- Once you are done with the script editor, go back to your form. ...
- Now you will see and click the add-on icon , then click Captcha for Forms > Start.
CAPTCHAs are tools you can use to differentiate between real users and automated users, such as bots. CAPTCHAs provide challenges that are difficult for computers to perform but relatively easy for humans. For example, identifying stretched letters or numbers, or clicking in a specific area.
Is v3 better than reCAPTCHA v2? ›
Is reCAPTCHA v3 better than v2? Neither of them is good at blocking bots. While reCAPTCHA v3 is less intrusive than v2 for a user, it places a significant burden on the webmaster to determine when to let users through and when to block or challenge them. There's no right answer to this.
Which reCAPTCHA is best? ›Conclusion: overall for your website site, we recommend using reCaptcha v2 invisble reCaptcha. And then if that still doesn't filter out the spam submissions, then use reCaptcha v2 (“I'm Not A Robot”).
Can bots beat CAPTCHA? ›Some bots can get past the text CAPTCHAs on their own. Researchers have demonstrated ways to write a program that beats the image recognition CAPTCHAs as well. In addition, attackers can use click farms to beat the tests: thousands of low-paid workers solving CAPTCHAs on behalf of bots.