Skip to content

saqqdy/captcha-pro

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

54 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

captcha-pro

A lightweight, framework-agnostic behavioral captcha library

Slider Puzzle · Click Verification · Invisible Captcha · Popup Mode

NPM version Codacy Badge Test coverage npm download gzip License

Sonar

Online Demo

Multi-Platform Support

Captcha Pro supports 10+ platforms with consistent APIs:

Platform Package Description
Web (Vanilla JS) captcha-pro Core package, works everywhere
Vue 2 captcha-pro-vue2 Options API + Mixins
Vue 3 captcha-pro-vue3 Composition API + Composables
React captcha-pro-react Hooks-based components
WeChat Mini-Program captcha-pro-mp WXML/WXSS/JS
uni-app captcha-pro-mp Vue cross-platform
Taro 3 captcha-pro-mp React cross-platform
Flutter captcha_pro Dart widgets
Android captcha-sdk Native Kotlin SDK
Android Compose captcha-compose Jetpack Compose
iOS CaptchaPro Swift SDK (UIKit + SwiftUI)

See PLATFORM_ROADMAP.md for detailed implementation.

Quick Start

# Install
pnpm add captcha-pro

# Use
import { SliderCaptcha } from 'captcha-pro'

new SliderCaptcha({
  el: '#captcha',
  onSuccess: () => console.log('Passed!')
})

Features

Captcha Types

  • 🧩 Slider Captcha - Puzzle verification with random shapes (square/triangle/trapezoid/pentagon), decoy holes with random rotation
  • 🖱️ Click Captcha - Text click verification with 200+ Chinese vocabulary support, no duplicate characters per word, random decoy characters, prompt images for anti-bot
  • 👻 Invisible Captcha - Risk-based invisible verification, behavior tracking and analysis
  • 📦 Popup Captcha - Modal popup wrapper for slider and click captcha, trigger by element click or programmatically

Verification Modes

  • 🎯 Frontend Mode - Pure frontend verification, no backend required
  • 🌐 Backend Mode - Server-side verification with image generation

Security Features

  • 🔐 Data Encryption - AES-GCM encryption to prevent data tampering
  • ⏱️ Timestamp Validation - Prevent replay attacks
  • 🚦 Rate Limiting - Prevent API abuse (60 requests/min by default)
  • 🚫 IP Blacklist - Block malicious IPs with temporary/permanent blocking
  • 🛡️ Brute-Force Protection - Detect and block brute-force attacks

Other Features

  • 📊 Statistics API - Track verification success rates, timing, and distances
  • 🌍 i18n Support - Built-in internationalization (zh-CN, en-US), auto-detect browser language
  • 🚀 Framework Agnostic - Works with Vue, React, Angular, or vanilla JS
  • 📦 Lightweight - ~35KB minified, no dependencies
  • 🖼️ Custom Images - Support custom background and slider images
  • 📱 Mobile Friendly - Full touch events support
  • Accessibility - ARIA attributes, keyboard navigation support
  • 🌐 IE11+ Support - Requires Promise polyfill

Installing

# Core package (Web/Vanilla JS)
$ pnpm add captcha-pro

# Vue 2
$ pnpm add captcha-pro-vue2

# Vue 3
$ pnpm add captcha-pro-vue3

# React
$ pnpm add captcha-pro-react

# Mini-program (WeChat/uni-app/Taro)
$ pnpm add captcha-pro-mp

# Flutter - add to pubspec.yaml
captcha_pro: ^1.1.0

# Android - add to build.gradle
implementation 'com.captcha.pro:captcha-sdk:1.1.0'

# iOS - CocoaPods
pod 'CaptchaPro', '~> 1.1.0'

Framework Usage

Vue 3

<template>
  <SliderCaptcha
    :width="300"
    :height="170"
    @success="onSuccess"
    @fail="onFail"
  />
</template>

<script setup lang="ts">
import { SliderCaptcha } from 'captcha-pro-vue3'

const onSuccess = () => console.log('Passed!')
</script>

React

import { SliderCaptcha } from 'captcha-pro-react'

function App() {
  return (
    <SliderCaptcha
      width={300}
      height={170}
      onSuccess={() => console.log('Passed!')}
    />
  )
}

Flutter

import 'package:captcha_pro/captcha_pro.dart';

SliderCaptcha(
  width: 300,
  height: 170,
  onSuccess: () => print('Passed!'),
)

Usage

Slider Captcha

<div id="slider-captcha"></div>

<script type="module">
  import { SliderCaptcha } from 'captcha-pro'

  const captcha = new SliderCaptcha({
    el: '#slider-captcha',
    width: 300,
    height: 170,
    precision: 5,
    showRefresh: true,
    onSuccess: () => console.log('Verification passed!'),
    onFail: () => console.log('Verification failed!')
  })

  // Get captcha data
  const data = captcha.getData()
  console.log('Target position:', data.target)

  // Get statistics
  const stats = captcha.getStatistics()
  console.log('Success rate:', stats.successRate + '%')

  // Reset or destroy
  captcha.reset()
  captcha.destroy()
</script>

Click Captcha

<div id="click-captcha"></div>

<script type="module">
  import { ClickCaptcha } from 'captcha-pro'

  const captcha = new ClickCaptcha({
    el: '#click-captcha',
    width: 300,
    height: 170,
    count: 3,
    onSuccess: () => console.log('Verification passed!')
  })

  // Get clicked points
  const points = captcha.getClickPoints()
</script>

Popup Captcha

<button id="submit-btn">Submit</button>

<script type="module">
  import { PopupCaptcha } from 'captcha-pro'

  const popup = new PopupCaptcha({
    trigger: '#submit-btn',
    type: 'slider', // 'slider' | 'click'
    modal: {
      title: 'Security Verification',
      maskClosable: true,    // Click mask to close
      escClosable: true,     // Press ESC to close
      showClose: true,       // Show close button
    },
    captchaOptions: {
      width: 300,
      height: 170,
      precision: 5,
    },
    autoClose: true,
    closeDelay: 500,
    onSuccess: () => console.log('Verification passed!'),
    onOpen: () => console.log('Popup opened'),
    onClose: () => console.log('Popup closed')
  })

  // Programmatic control
  popup.show()         // Show popup
  popup.hide()         // Hide popup
  popup.isVisible()    // Get visibility state
  popup.getCaptcha()   // Get inner captcha instance
</script>

Invisible Captcha

<button id="submit-btn">Submit</button>

<script type="module">
  import { InvisibleCaptcha } from 'captcha-pro'

  const captcha = new InvisibleCaptcha({
    el: '#submit-btn',
    trigger: 'click',
    riskAssessment: {
      threshold: 0.7, // Show challenge if risk score > 0.7
      behaviorCheck: {
        minInteractionTime: 500,
        trackAnalysis: true
      }
    },
    challengeType: 'slider', // 'slider' | 'click'
    onChallenge: () => console.log('Showing captcha challenge...'),
    onSuccess: () => form.submit(),
    onFail: () => console.log('Verification failed')
  })

  // Get risk score
  const score = captcha.getRiskScore()
</script>

Security Features

import { SliderCaptcha, decryptCaptchaData } from 'captcha-pro'

// With AES-GCM encryption for backend verification
const captcha = new SliderCaptcha({
  el: '#captcha',
  security: {
    secretKey: 'your-secret-key',  // Shared with backend
    enableSign: true,
    timestampTolerance: 60000      // 60 seconds
  },
  onSuccess: async () => {
    // Get encrypted data for backend verification
    const encryptedData = await captcha.getSignedData()
    // encryptedData contains: type, target, timestamp, nonce, encrypted data

    // Send to backend
    await fetch('/api/verify', {
      method: 'POST',
      body: JSON.stringify(encryptedData)
    })
  }
})

// Backend verification example (Node.js)
import { decryptCaptchaData, validateTimestamp } from 'captcha-pro'

async function verifyCaptcha(encryptedData, secretKey) {
  try {
    // Decrypt data
    const data = await decryptCaptchaData(encryptedData.signature, secretKey)

    // Check timestamp
    if (!validateTimestamp(data.timestamp, 60000)) {
      return { valid: false, error: 'Timestamp expired' }
    }

    return { valid: true, data }
  } catch (error) {
    return { valid: false, error: 'Invalid encrypted data' }
  }
}

Backend Verification Mode

import { SliderCaptcha } from 'captcha-pro'

const captcha = new SliderCaptcha({
  el: '#captcha',
  verifyMode: 'backend', // 'frontend' (default) or 'backend'
  backendVerify: {
    getCaptcha: '/api/captcha/get',
    verify: '/api/captcha/verify',
    headers: {
      'X-Requested-With': 'XMLHttpRequest'
    },
    timeout: 10000
  },
  onSuccess: () => console.log('Backend verification passed!'),
  onFail: () => console.log('Verification failed')
})

Statistics API

const captcha = new SliderCaptcha({ el: '#captcha' })

// After some verifications...
const stats = captcha.getStatistics()
console.log({
  totalAttempts: stats.totalAttempts,
  successCount: stats.successCount,
  failCount: stats.failCount,
  successRate: stats.successRate + '%',
  avgVerifyTime: stats.avgVerifyTime + 'ms',
  avgDragTime: stats.avgDragTime + 'ms',
  avgDragDistance: stats.avgDragDistance + 'px'
})

// Reset statistics
captcha.resetStatistics()

Custom Images

import { SliderCaptcha } from 'captcha-pro'

const captcha = new SliderCaptcha({
  el: '#captcha',
  bgImage: '/path/to/background.jpg',
  sliderImage: '/path/to/slider.png', // Optional, auto-generated if not provided
  width: 300,
  height: 200,
  sliderWidth: 60,
  sliderHeight: 60,
  onSuccess: () => console.log('Verification passed!')
})

Factory Functions

import {
  createSliderCaptcha,
  createClickCaptcha,
  createInvisibleCaptcha,
  createPopupCaptcha
} from 'captcha-pro'

const slider = createSliderCaptcha({ el: '#slider' })
const click = createClickCaptcha({ el: '#click' })
const invisible = createInvisibleCaptcha({ el: '#btn' })
const popup = createPopupCaptcha({ type: 'slider' })

Internationalization (i18n)

captcha-pro supports internationalization with built-in Chinese (zh-CN) and English (en-US) translations.

import { SliderCaptcha, setLocale, getLocale, t } from 'captcha-pro'

// Set language globally
setLocale('en-US')

// Get current locale
console.log(getLocale()) // 'en-US'

// Or set locale per component
const captcha = new SliderCaptcha({
  el: '#captcha',
  locale: 'en-US',  // Component-level locale
})

// Get translated text
console.log(t('slider.success')) // 'Verification passed'

By default, captcha-pro auto-detects browser language. Chinese browsers show Chinese text, others show English.

Browser Direct Import (IIFE)

<head>
  <!-- IE11 needs Promise polyfill -->
  <!--[if IE]>
  <script src="https://cdn.jsdelivr.net/npm/core-js-bundle/minified.js"></script>
  <![endif]-->
  <script src="https://unpkg.com/captcha-pro/dist/index.global.min.js"></script>
</head>
<body>
  <div id="captcha"></div>
  <script>
    const captcha = new CaptchaPro.SliderCaptcha({
      el: '#captcha',
      onSuccess: () => alert('Success!')
    })
  </script>
</body>

Backend Server Demos

Demo implementations are provided in the server/ directory to help you integrate captcha-pro with your backend:

Directory Framework Port Description
server/node Express 5 3001 Node.js backend demo
server/java Spring Boot 3 8080 Java backend demo
server/go Gin 8082 Go backend demo

Note: These are reference implementations, not published packages. Copy the code you need into your own backend project.

Quick Start (Node.js Demo)

cd server/node
pnpm install
pnpm dev

Server runs at http://localhost:3001. See each server directory's README for more details.

API Endpoints

Method Endpoint Description
GET /api/captcha Generate captcha image
POST /api/captcha/verify Verify captcha
GET /api/health Health check
GET /api/info Server info

Generate Captcha

GET /api/captcha?type=slider&width=300&height=170

Query Parameters:

Parameter Type Default Description
type string slider Captcha type: slider or click
width number 300 Image width
height number 170 Image height
precision number 5 Verification precision
clickCount number 3 Click count (for click type)

Response:

{
  "success": true,
  "data": {
    "captchaId": "uuid-string",
    "type": "slider",
    "bgImage": "data:image/png;base64,...",
    "sliderImage": "data:image/png;base64,...",
    "sliderY": 42,
    "width": 300,
    "height": 170,
    "expiresAt": 1700000000000
  }
}

Click Captcha Response

For click captcha type, the response includes:

{
  "success": true,
  "data": {
    "captchaId": "uuid-string",
    "type": "click",
    "bgImage": "data:image/png;base64,...",
    "clickTexts": ["", "", ""],
    "clickCharImages": ["data:image/png;base64,...", ...],
    "width": 300,
    "height": 170,
    "expiresAt": 1700000000000
  }
}

Verify Captcha

POST /api/captcha/verify

Request Body:

{
  "captchaId": "uuid-string",
  "type": "slider",
  "target": [123]
}

Response:

{
  "success": true,
  "message": "Verification successful",
  "data": { "verifiedAt": 1700000000000 }
}

Security Endpoints

Method Endpoint Description
GET /api/security/status/:ip Get IP security status
GET /api/security/blacklist Get blacklist entries
POST /api/security/blacklist Add IP to blacklist
DELETE /api/security/blacklist/:ip Remove IP from blacklist

Environment Variables (Demo Servers)

Variable Default Description
PORT 3001 (Node.js) / 8080 (Java) / 8082 (Go) Server port
HOST localhost Server host
SECRET_KEY captcha-pro-secret-key AES-GCM encryption key
EXPIRE_TIME 60000 Captcha expire time (ms)
TIMESTAMP_TOLERANCE 60000 Timestamp tolerance (ms)

Frontend Integration with Backend

import { SliderCaptcha } from 'captcha-pro'

const captcha = new SliderCaptcha({
  el: '#captcha',
  verifyMode: 'backend',
  backendVerify: {
    getCaptcha: 'http://localhost:3001/api/captcha?type=slider',
    verify: 'http://localhost:3001/api/captcha/verify'
  },
  onSuccess: () => console.log('Backend verification passed!')
})

API Reference

SliderCaptcha Options

Option Type Default Description
el string | HTMLElement - Container element or selector
bgImage string - Background image URL
sliderImage string - Slider image URL
width number 300 Container width
height number 170 Container height
sliderWidth number 42 Slider piece width
sliderHeight number 42 Slider piece height
precision number 5 Verification precision (px)
showRefresh boolean true Show refresh button
className string 'captcha-slider' Custom class name
verifyMode 'frontend' | 'backend' 'frontend' Verification mode
backendVerify BackendVerifyOptions - Backend verification config
security SecurityOptions - Security options
onSuccess () => void - Success callback
onFail () => void - Fail callback
onRefresh () => void - Refresh callback

ClickCaptcha Options

Option Type Default Description
el string | HTMLElement - Container element or selector
width number 300 Container width
height number 170 Container height
count number 3 Number of click points
showRefresh boolean true Show refresh button
className string 'captcha-click' Custom class name
verifyMode 'frontend' | 'backend' 'frontend' Verification mode
backendVerify BackendVerifyOptions - Backend verification config
security SecurityOptions - Security options
onSuccess () => void - Success callback
onFail () => void - Fail callback
onRefresh () => void - Refresh callback

InvisibleCaptcha Options

Option Type Default Description
el string | HTMLElement - Trigger element or selector
trigger 'click' | 'submit' | 'focus' 'click' Trigger event
riskAssessment RiskAssessmentOptions - Risk assessment config
challengeType 'slider' | 'click' 'slider' Challenge captcha type
challengeOptions object - Options for challenge captcha
onChallenge () => void - Called when challenge is shown
onSuccess () => void - Success callback
onFail () => void - Fail callback

PopupCaptcha Options

Option Type Default Description
trigger string | HTMLElement - Trigger element or selector
type 'slider' | 'click' 'slider' Captcha type
captchaOptions object - Options for inner captcha
modal PopupModalOptions - Modal options
autoClose boolean true Auto close on success
closeDelay number 500 Delay before close (ms)
onOpen () => void - Called when popup opens
onClose () => void - Called when popup closes
onSuccess () => void - Success callback
onFail () => void - Fail callback

PopupModalOptions

Option Type Default Description
title string - Modal title
maskClosable boolean true Click mask to close
escClosable boolean true Press ESC to close
showClose boolean true Show close button

SecurityOptions

Option Type Default Description
secretKey string - Secret key for AES-GCM encryption
enableSign boolean false Enable data signing
timestampTolerance number 60000 Timestamp tolerance (ms)

BackendVerifyOptions

Option Type Default Description
getCaptcha string | Function - URL or function to get captcha
verify string | Function - URL or function to verify captcha
headers object - Request headers
timeout number 10000 Request timeout (ms)

Instance Methods

Method Description
verify(data) Manually verify captcha
reset() Reset captcha state
refresh() Generate new captcha
destroy() Destroy captcha instance
getData() Get captcha data
getSignedData() Get signed data for backend verification
getStatistics() Get verification statistics
resetStatistics() Reset statistics

PopupCaptcha Instance Methods

Method Description
show() Show popup modal
hide() Hide popup modal
isVisible() Get visibility state
getCaptcha() Get inner captcha instance
destroy() Destroy popup instance

InvisibleCaptcha Instance Methods

Method Description
getRiskScore() Get current risk score (0-1)
showChallenge() Manually show challenge
destroy() Destroy instance

Build Outputs

File Format Size Use Case
index.mjs ESM 35KB Bundlers (webpack, vite, rollup)
index.cjs CommonJS 36KB Node.js, older bundlers
index.global.js IIFE 57KB Browser (development)
index.global.min.js IIFE 34KB Browser (production)

Browser Support

Chrome Firefox Safari Opera IE
Chrome ✓ Firefox ✓ Safari ✓ Opera ✓ IE 11+ ✓

Note for IE11: Requires Promise polyfill.

Development

# Clone and install
git clone https://github.com/saqqdy/captcha-pro.git
cd captcha-pro
pnpm install

# Build, test, lint
pnpm build
pnpm test
pnpm lint

# Run backend server
cd server/node && pnpm dev

License

MIT

Sponsor this project

Packages

 
 
 

Contributors