Coder Social home page Coder Social logo

custom-slider-demo's Introduction

Custom Slider Captcha Demo

This demo code is made to demonstrate how 2Captcha API can be used to bypass custom slider captchas.

Concept

To solve the custom slider captcha we need to calculate the path where we should drag the slider. In most cases all we need is just two points: start and end, and the start point is usually static, so we can find it just once. The second point can be found by human workers of 2Captcha, we can show them an image and provide instructions describing which exact point they need to indicate, they will click the point and 2Captcha API will return the coordinates of this point. The API method we need is Coordinates.

Approach

To interact with the captcha we must use a browser and a framework that allows us to control the browser. In this example, we'll use Puppeteer as a browser automation framework. And we'll also use @2captcha/captcha-solver to interact with 2Captcha API.

Prepare the environment

Install the dependencies:

yarn add puppeteer @2captcha/captcha-solver

Set the API key as an environment variable:

export APIKEY=your_api_key_here

Code

As we use ES6 import statements in the code, let's add the following property to the package.json file:

"type": "module"

Create a file named index.js and let's start to add some code:

First of all, let's import the dependencies

import puppeteer from 'puppeteer'
import { Solver } from '@2captcha/captcha-solver'
import { readFile } from 'node:fs/promises'

Then let's create a new instance of Solver with our API key

const solver = new Solver(process.env.APIKEY)

We'll need to generate some random numbers, so let's add a simple one-liner that will do that job:

const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;

The rest of the code will be wrapped into a self-executing async function as it's much more convenient to call all Promise-based Puppeeter methods with async/await.

(async () => {
 // the rest of the code
})();

Let's launch a browser, get the opened tab and open the captcha demo page. We also define a variable success that will hold the captcha bypass process state.

const browser = await puppeteer.launch({
    devtools: true,
    slowMo: 11
})
const [page] = await browser.pages()

await page.goto('https://www.jqueryscript.net/demo/image-puzzle-slider-captcha/')

let success = false

There's never a 100% guarantee that we'll bypass the captcha from the 1st attempt, so let's start a loop. We'll exit the loop once the captcha is successfully solved.

The demo page shows a cookies consent modal window for some countries, so let's decline all cookies if the page asks us about it.

Let's also load the instruction image that will be shown to 2Captcha workers.

while (!success) {
    try {
        const consentButton = await page.waitForSelector('body > div.fc-consent-root > div.fc-dialog-container > div.fc-dialog.fc-choice-dialog > div.fc-footer-buttons-container > div.fc-footer-buttons > button.fc-button.fc-cta-do-not-consent.fc-secondary-button', { timeout: 3000 })
        if (consentButton) consentButton.click()
    } catch (e) { }

    const instruction = await readFile('./imginstructions.png', { encoding: 'base64' })

Then we need to grab the captcha image and send it to 2Captcha API using the Coordinates method. There's a chance that the image will fail to load, so we check the length of the data URL returned.

Once we have the image, we pass it to the corresponding method of the Solver instance. The result contains an array of point coordinates. In our case, there should be only one point. We use its x coordinate as a distance between the left image border and the center of the target puzzle piece.

const img = await page.evaluate(() => document.querySelector('canvas').toDataURL())
if (img.length < 2000) return

try {
    const res = await solver.coordinates({
        body: img,
        textinstructions: 'Puzzle center | Центр пазла',
        imginstructions: instruction
    })
    const offset = res.data[0].x       

Then we get the slider element and its coordinates and dimensions. We'll use its center as a starting point for our drag-and-drop action.

const slider = await page.$('div.slider')

const bb = await slider.boundingBox()

const init = {
    x: bb.x + bb.width / 2,
    y: bb.y + bb.height / 2
}

Then we calculate the coordinates of the final point: In our case the width of the square part of the puzzle piece is 40px, so we need to subtract half of it, as we expect to receive the center of the puzzle piece. We also use the y coordinate received just to avoid moving the pointer only horizontally, as we know that the captcha is tracking the path.

const target = {
    x: bb.x + bb.width / 2 + parseFloat(offset) - 20,
    y: res.data[0].y
}

Optionally we can draw a small box on the image to see the exact point clicked by the 2Captcha worker

await page.evaluate((coord) => {
    console.log(coord)
    const canvas = document.querySelector('#captcha > canvas')
    let ctx = canvas.getContext('2d')
    ctx.globalAlpha = 1
    ctx.fillStyle = 'red'
    ctx.fillRect(coord.x, coord.y, 3, 3)
}, {
    x: parseInt(res.data[0].x),
    y: parseInt(res.data[0].y)
})

Then we move the mouse pointer to the start point, click and hold the mouse button and move the pointer to the end point. When moving the slider we provide a random number of steps to make the path more complex because the captcha is tracking the mouse events.

await page.mouse.move(init.x, init.y)
await page.mouse.down()
await page.mouse.move(target.x, target.y, {
    steps: randomInt(50, 100)
})
await page.mouse.up()

Finally, we are trying to understand if we were able to bypass the captcha. In our case after the solution we are redirected to another page, so we are waiting for navigation. In the case of a successful solution, we exit the loop setting the success variable to true, reporting a correct answer to 2Captcha API, making a screenshot and closing the page and browser. In case of error (no navigation within 5 seconds) we report an incorrect answer and make one more attempt to solve the captcha.

try {
    await page.waitForNavigation({ timeout: 5000 })
    success = true
    await solver.goodReport(res.id)
    await page.screenshot({
        path: 'screenshot.png'
    })
    await new Promise(ok => setTimeout(() => ok(), 5000))
    await page.close()
    await browser.close()
} catch (e) {
    await solver.badReport(res.id)
}

As you may have noticed, the code starting from interaction with 2Captcha API is wrapped into a try/catch block, so we need to close this block with the catch as well as close our loop here.

    } catch (e) {
        console.log(`Failed to solve the captcha: ${e.err}`)
    }
}

Using this demo

You can just clone the repo, install the dependencies and run it:

git clone [email protected]:2captcha/custom-slider-demo.git
yarn #or npm i
yarn start #or npm start

That's it, folks!

custom-slider-demo's People

Contributors

kratzky avatar dzmitry-duboyski avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.