Skip to content

cluion/turing

Repository files navigation

Turing

CI npm Packagist License: MIT

English · 繁體中文 · 📖 Documentation

A signed challenge the server issues, a client widget that solves it in the browser with native Web Crypto, and a token the enclosing form submits for the server to verify. No external service, no tracking. Three layers: a framework-agnostic PHP Core, framework integrations (Laravel first), and a JS client stack.

Install

Laravel (PHP)

composer require cluion/turing
php artisan vendor:publish --tag=turing-config   # then set TURING_SECRET

JavaScript

Package Install Use
@cluion/turing-core pnpm add @cluion/turing-core Headless core (plain / any framework)
@cluion/turing-element pnpm add @cluion/turing-element <turing-captcha> Web Component
@cluion/turing-vue pnpm add @cluion/turing-vue <Turing> Vue 3 component
@cluion/turing-react pnpm add @cluion/turing-react <Turing/> React component

Plain HTML via CDN — pin an exact version and add Subresource Integrity:

<script
  src="https://cdn.jsdelivr.net/npm/@cluion/turing-core@1.0.0/dist/turing.global.js"
  integrity="sha384-Yr0+3DwmN0hpeaF/LmMvcDSdUptv057stCTNWChQQjcYU/L7JbZFBkbe2BEg6/1D"
  crossorigin="anonymous"
  defer></script>

Usage

Laravel — one line to show, one line to verify

<form method="post" action="/submit">
  @csrf
  <x-turing type="pow" />
  <button type="submit">Send</button>
</form>
$request->validate(['turing_token' => 'required|turing']);
// or: Turing::verifyRequest($request);

The <x-turing/> component renders a CSP-safe container the client widget mounts onto. The widget fetches the challenge from data-turing-url, solves the PoW with native Web Crypto (no WASM), and injects a hidden turing_token for the form to submit.

JavaScript

import '@cluion/turing-core'; // auto-mounts every [data-turing] container

A runnable plain-HTML page is in examples/plain-html/index.html. Framework guides: Laravel · Plain HTML · Vue · React · Security.

Core

Framework-agnostic PHP core under php/src/Core. Token = base64url(payload).base64url(signature) with canonical (sorted-key) JSON. HMAC-SHA256 default signing (Ed25519 opt-in). Challenge types: math, text, pow (PBKDF2-SHA256 default, SHA-256 leading-zero-bit opt-in). Stateless by default; single-use via a Store.

Cross-language vectors

php/tests/vectors/ is the wire contract — the authoritative wire-contract reference quotes them verbatim (a docs build guard fails on drift). Language ports MUST reproduce these fixtures exactly (token bytes, PoW counters, answer hashes). Binary payload fields (e.g. keySignature) are always base64url of the raw bytes.

Development

composer install
vendor/bin/phpunit                 # PHP: Core + Laravel suites (Laravel 10–13 in CI)

cd js && pnpm install
pnpm -r build && pnpm -r test      # JS: 4 packages (build before test)
pnpm -r typecheck

cd ../docs && pnpm docs:build      # docs site + vector drift guard
cd ../e2e  && pnpm exec playwright test   # browser round-trip (needs chromium)

License

MIT.

About

Modern captcha for the web — stateless tokens, CSP-safe, Laravel + JavaScript

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors