Welcome in the second part of the series about creating own, custom captcha mechanism. In this article, we are going to prepare an environment for further work. As I mentioned in the previous post, the entire captcha will be written with TypeScript and React on the client-side.
If you want to skip reading, just download source code from git repository. Leave a star if you like the project. ⭐
pilotpirxie / devcaptcha
🤖 Open source captcha made with React, Node and TypeScript for DEV.to community
devcaptcha
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.git
cd devcaptcha/devcaptcha-server
yarn install
yarn 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
…Installation
So let's initialize the project with installing libraries. Install react, react-dom, styled-components, webpack and typescript. Then install types, eslint and utils plugins.
To install libs faster, just copy them from package.json below that I prepared. Then run yarn
and yarn upgrade --latest
to upgrade to the newest version.
{
"name": "devcaptcha",
"version": "1.0.0",
"main": "dist/devcaptcha.dist.js",
"devDependencies": {
"@types/react": "^16.9.35",
"@types/react-dom": "^16.9.8",
"@types/styled-components": "^5.1.0",
"@typescript-eslint/eslint-plugin": "^2.33.0",
"@typescript-eslint/parser": "^2.33.0",
"eslint": "^7.0.0",
"eslint-plugin-react": "^7.20.0",
"source-map-loader": "^0.2.4",
"ts-loader": "^7.0.4",
"typescript": "^3.9.2",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.11.0"
},
"dependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1",
"styled-components": "^5.1.0"
},
"scripts": {
"start": "webpack-dev-server --open --config webpack.development.config.js",
"build": "webpack --config webpack.production.config.js",
"eslint": "./node_modules/.bin/eslint .",
"fix": "./node_modules/.bin/eslint --fix ."
}
}
Dev server for hot reload
After installation, create directory public
and index.html
file and put inside:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello React!</title>
</head>
<body>
<div id="captcha"></div>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="main.js"></script>
</body>
</html>
This file will be served on the dev server. Before closing body tag it contains links to React on CDN, just for the development process. We want to have an independent file similar to Web Components (if you want, you can wrap this project and create custom element) to work in different situations.
Webpack
Create webpack.development.config.js
file for development like below. Configure port and public directory. This file also contains information about bindings in source maps between original and minified files. Make sure to install ts-loader
to be able to resolve and load typescript files.
module.exports = {
mode: "development",
devtool: "source-map",
devServer: {
contentBase: './public',
compress: false,
port: 8080,
},
resolve: {
extensions: [".ts", ".tsx", '.js', '.json']
},
module: {
rules: [{
test: /\.ts(x?)$/,
exclude: /node_modules/,
use: [{
loader: "ts-loader"
}]
}, {
enforce: "pre",
test: /\.js$/,
loader: "source-map-loader"
}]
},
externals: {
react: "React",
"react-dom": "ReactDOM",
}
};
Similarly, create production config for builds webpack.production.config.js
. It's very close to the previous, however it doesn't contain dev server configuration, different mode and externals. Externals are used to skip and create globals. In the dev mode, we are using CDN links to make hot reload faster. In the prod we want to bundle everything together.
module.exports = {
mode: "production",
devtool: "source-map",
output: {
filename: 'devcaptcha.dist.js'
},
resolve: {
extensions: [".ts", ".tsx", '.js', '.json']
},
module: {
rules: [{
test: /\.ts(x?)$/,
exclude: /node_modules/,
use: [{
loader: "ts-loader"
}]
}, {
enforce: "pre",
test: /\.js$/,
loader: "source-map-loader"
}]
},
};
Typescript
Create configuration for typescript tsconfig.json
. Parameter noImplicitAny
set to true disallow compilation when somewhere variable is untyped. Parameter jsx
specifies that we are using tsx
files. Library array contains different types of load by default. Entry dom
allow accessing to Web API and objects like window.document
.
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "CommonJS",
"jsx": "react",
"target": "es5",
"lib": [
"es6",
"dom"
]
}
}
Initial source code
Ok, almost ready. You need to create an entry point for typescript. With React we will be using .tsx
extension. It's like typescript with some additional sugar.
Create directory src
and index.tsx
inside. Inside import entire React and ReactDOM and create a class with a method for rendering/mounting captcha in the right place.
In my case, I am looking for root element by selector passed in the constructor. The class that I created implements interface ICaptcha with common properties for hypothetical, different captchas and DevCaptcha too.
Important is to assign the reference to DevCaptcha on window object to make access possible. However, in TypeScript, you cannot assign directly to a global object. Firstly declare an extended interface to the object.
import * as React from "react";
import * as ReactDOM from "react-dom";
import { App } from "./components/App";
interface ICaptcha {
_appendSelector: string
}
type CaptchaConfig = {
appendSelector: string
}
class DevCaptcha implements ICaptcha {
readonly _appendSelector : string;
public constructor(config : CaptchaConfig) {
this._appendSelector = config.appendSelector;
}
mount() {
ReactDOM.render(<App />, document.querySelector(this._appendSelector));
}
}
declare global {
interface Window { DevCaptcha: object; }
}
window.DevCaptcha = window.DevCaptcha || {};
window['DevCaptcha'] = DevCaptcha;
ESLint
Finally, configure eslint to quickly look for the code quality problems. You can configure it for you. If you have your own eslint config, just use it.
Create .eslintrc
with the following code:
module.exports = {
"env": {
"browser": true,
"commonjs": true,
"es6": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/eslint-recommended"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"sourceType": "module",
"ecmaFeatures": {
"jsx": true,
},
"ecmaVersion": 2018
},
"plugins": [
"react",
"@typescript-eslint"
],
"rules": {
"indent": ["error", 2]
}
};
and .eslintignore
with directories to exclude
node_modules
public
dist
You did it!
If you did everything well, you should be able to run dev server of this app.
yarn start
Open browser on localhost at the port which you set up previously. In my case, it's 8080, so open http://localhost:8080
. You should see Hello World setup for React, widget-based application.
Uff. That's how we prepared environment for future work on client-side of captcha. In the next article, we will start working on a first reverse-turing mechanism.
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
devcaptcha
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.git
cd devcaptcha/devcaptcha-server
yarn install
yarn 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
…If you want to be notified about the next part, follow me on DEV.to. 😉
Top comments (0)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.