$ show prosopo/captcha
Prosopo is a privacy-focused, self-hosted CAPTCHA alternative that provides multiple challenge typesβimage selection, puzzle (image jigsaw), proof-of-work, and frictionless (behavioral bot detection). The system comprises an Express-based provider API (with MongoDB and Redis for persistence and caching), a CLI for administrative tasks, client-side embeddable widgets (vanilla JS bundle, React/Angular/Vue/Svelte wrappers), and a suite of supporting libraries for cryptography, locale, datasets, and native Rust modules (JA4 TLS fingerprinting, Merkle tree acceleration, puzzle rendering). Bot detection is multi-layered: client-side behavioral data (mouse/keyboard/touch events, SIMD readings) is collected and server-side scored, combined with JA4 TLS fingerprint analysis, IP reputation (ipapi.is + MaxMind), DNS asymmetry detection, spam email heuristics, and custom decision machines per site key. The architecture is a monorepo with ~70 workspaces, leveraging Vite for bundling, Vitest for unit/integration tests, and Cypress for E2E visual regression testing. The provider enforces access policies (allow/block/restrict) via a Redis-backed rules engine and maintains usage counters for rate limiting. Asset sealing (AES-256-GCM) protects image CDN URLs, and puzzle difficulty is sampled with a CSPRNG-stratified ladder to frustrate solver calibration.
The LLM identified 6 files worth highlighting for reuse:
Reactive state store with observable subscriptions and microtask-coalesced render scheduling. Allows partial state updates, in-place mutation, and safe subscription removal mid-iteration. Could be extracted as a lightweight state library for DOM-based widgets.
Provides an `anew` helper that constructs an object and automatically calls its async `ctor` method. Solves the problem of async initialization in constructor-based classes cleanly, avoiding the need for factory functions or `init()` methods. Minimal and reusable.
Exports `chunkIntoBatches` for splitting arrays into fixed-size batches. Generic, zero-dependency utility that handles error cases (non-array, negative chunk size). Immediately reusable in any TypeScript project.
Implements a deep merge function with array handling (atomic replacement or element-wise merge). Handles nested objects, null/undefined values, and type mismatches. Useful for merging configuration objects recursively. Self-contained.
Merkle tree construction for browser fingerprint components, enabling selective disclosure proofs. Uses SHA-256 hashing. Can be extracted for generic Merkle proof generation with minimal dependencies (@noble/hashes).
Load-balancer that fetches and caches a provider list (dual-stack IPv4/IPv6), selects a random provider by weight, and excludes failed providers. Handles network errors gracefully and supports single-fetch caching. Pattern is reusable for any service that needs to distribute load across a list of endpoints.