488 lines
17 KiB
Markdown
488 lines
17 KiB
Markdown
# ALTCHA
|
||
|
||
ALTCHA is a self-hosted, privacy-first security solution that protects your websites, APIs, and online services from spam and abuse through an innovative proof-of-work mechanism. Unlike traditional CAPTCHAs that depend on intrusive methods like cookies or fingerprinting, ALTCHA delivers robust protection while respecting user privacy.
|
||
|
||
ALTCHA is fully compliant with:
|
||
|
||
- **Global privacy regulations**: GDPR, HIPAA, CCPA, PIPEDA/CPPA, LGPD, DPDPA, and PIPL
|
||
- **Accessibility standards**: [WCAG 2.2 AA-level](https://altcha.org/docs/v2/compliance/wcag/) and the [European Accessibility Act](https://altcha.org/docs/v2/compliance/european-accessibility-act-2025/)
|
||
|
||
For more details, visit [altcha.org](https://altcha.org).
|
||
|
||
## Playground
|
||
|
||
Want to see it in action? Visit the official ALTCHA Playground to experiment with widget configurations, fine-tune the Proof-of-Work (PoW) settings, and see how the security mechanisms hold up in real-time.
|
||
|
||
[Open ALTCHA Playground](https://playground.altcha.org)
|
||
|
||
## Features
|
||
|
||
- **Frictionless Experience**: Eliminates frustrating visual puzzles by using background **Proof-of-Work (PoW)** for a seamless user journey.
|
||
- **Hardware-Resistant Security**: Leverages **Argon2 and Scrypt** memory-bound algorithms to neutralize hardware acceleration (ASICs/GPUs) and sophisticated bot farms.
|
||
- **Accessible Code Challenges**: Provides "Enter code from image" fallbacks with built-in **audio support** for visually impaired users.
|
||
- **Privacy by Design**: Fully **GDPR compliant** and cookie-free—no tracking, no fingerprinting, and no data collection.
|
||
- **Universal Accessibility**: Engineered to exceed **WCAG 2.2 AA** standards, ensuring compliance with the **European Accessibility Act (EAA)**.
|
||
- **Lightweight**: Minimal footprint, optimized for rapid page loads and high-performance environments.
|
||
- **100% Self-Hosted**: Maintain full sovereignty over your infrastructure with no reliance on third-party API availability.
|
||
|
||
## What’s New in v3
|
||
|
||
- **Next-Gen PoW**: Significant performance gains and reduced CPU overhead through an optimized verification mechanism.
|
||
- **Advanced Bot Defense**: Native support for **Argon2 and Scrypt**, raising the cost of attack for automated scripts and specialized hardware.
|
||
- **Modern UI**: Refined styling options, including a suite of new built-in themes and improved CSS custom property support.
|
||
- **Developer Experience**: Improved TypeScript support and streamlined integration.
|
||
|
||
### Migrating from v2
|
||
|
||
See [MIGRATION-v2.md](https://github.com/altcha-org/altcha/blob/v3/MIGRATION-v2.md).
|
||
|
||
## Examples
|
||
|
||
Explore starter templates for popular frameworks:
|
||
|
||
- [React](https://github.com/altcha-org/altcha-starter-react-ts)
|
||
- [Vue](https://github.com/altcha-org/altcha-starter-vue-ts)
|
||
- [Svelte](https://github.com/altcha-org/altcha-starter-svelte-ts)
|
||
- [Solid](https://github.com/altcha-org/altcha-starter-solid-ts)
|
||
- [Lit](https://github.com/altcha-org/altcha-starter-lit-ts)
|
||
- [Angular](https://github.com/altcha-org/altcha-starter-angular)
|
||
|
||
## Server Integrations
|
||
|
||
- [TypeScript](https://github.com/altcha-org/altcha-lib)
|
||
- [Dart](https://github.com/altcha-org/altcha-lib-dart)
|
||
- [PHP](https://github.com/altcha-org/altcha-lib-php)
|
||
- [Go](https://github.com/altcha-org/altcha-lib-go)
|
||
- [Python](https://github.com/altcha-org/altcha-lib-py)
|
||
- [Java](https://github.com/altcha-org/altcha-lib-java)
|
||
- [Ruby](https://github.com/altcha-org/altcha-lib-rb)
|
||
- [Elixir](https://github.com/altcha-org/altcha-lib-ex)
|
||
- [Rust](https://github.com/altcha-org/altcha-lib-rs)
|
||
- [C++](https://github.com/altcha-org/altcha-lib-cpp)
|
||
|
||
## Plugins & CMS
|
||
|
||
- [Libraries and plugins](https://altcha.org/docs/v2/libraries/)
|
||
|
||
## Usage
|
||
|
||
The ALTCHA widget is distributed as a **Web Component**.
|
||
|
||
### 1. Install ALTCHA
|
||
|
||
```sh
|
||
npm install altcha
|
||
```
|
||
|
||
Import in your main file:
|
||
|
||
```js
|
||
import 'altcha';
|
||
```
|
||
|
||
Or load via `<script>` tag:
|
||
|
||
```html
|
||
<script async defer src="/altcha.js" type="module"></script>
|
||
```
|
||
|
||
### 2. Add `<altcha-widget>` to Your Forms
|
||
|
||
```html
|
||
<form>
|
||
<altcha-widget challenge="https://..."></altcha-widget>
|
||
</form>
|
||
```
|
||
|
||
See [configuration options](#configuration) or the [website integration docs](https://altcha.org/docs/v2/widget-integration).
|
||
|
||
### 3. Integrate with Your Server
|
||
|
||
Refer to the [server documentation](https://altcha.org/docs/v2/server-integration) for implementation details.
|
||
|
||
## Supported Browsers
|
||
|
||
ALTCHA works on modern browsers with **Web Crypto API** support (specifically `crypto.subtle` - [caniuse.com](https://caniuse.com/?search=subtle)).
|
||
|
||
**Supported**:
|
||
|
||
- Chrome 67+ (desktop & Android)
|
||
- Edge 79+
|
||
- Firefox 63+ (desktop & Android)
|
||
- Safari 11+ (macOS & iOS)
|
||
- Any browser supporting Web Components + Web Crypto
|
||
|
||
**Not Supported**:
|
||
|
||
- Internet Explorer 11 (or older)
|
||
|
||
## Bundle Size
|
||
|
||
ALTCHA is optimized for performance:
|
||
|
||
| Distribution | Size (GZIPped) |
|
||
| ---------------------------- | -------------- |
|
||
| ALTCHA | 34 kB |
|
||
| ALTCHA with all translations | 52 kB |
|
||
| Cloudflare Turnstile | 85+ kB |
|
||
| hCaptcha | 250+ kB |
|
||
| reCAPTCHA | 300+ kB |
|
||
|
||
When GZIPped, it totals about 34 kB, making ALTCHA’s widget about ~90% smaller than reCAPTCHA.
|
||
|
||
## Content Security Policy (CSP)
|
||
|
||
The default bundle includes styles and workers in a single file. For strict CSP compliance, use scripts from `/dist/external`. Learn more in the [documentation](https://altcha.org/docs/v2/widget-integration).
|
||
|
||
## Configuration
|
||
|
||
### Programmatic Configuration
|
||
|
||
The widget provides a global `$altcha` object to manage defaults, register new algorithms, or add custom translations.
|
||
|
||
To update an existing widget instance, use the `.configure()` [method](). This is the preferred way to handle complex objects or functions that cannot be passed via HTML attributes.
|
||
|
||
```ts
|
||
// Set defaults for all future widget instances:
|
||
$altcha.defaults.set({
|
||
challenge: 'https://api.example.com/challenge',
|
||
debug: true
|
||
});
|
||
|
||
// Update a specific instance dynamically:
|
||
const widget = document.querySelector('altcha-widget');
|
||
widget.configure({
|
||
workers: 2,
|
||
language: 'fr'
|
||
});
|
||
```
|
||
|
||
### Attribute Configuration
|
||
|
||
For simple implementations, the widget supports a subset of configuration options directly as HTML attributes. For more advanced properties, use the programmatic approach above.
|
||
|
||
**Supported Attributes:**
|
||
|
||
```html
|
||
<altcha-widget
|
||
auto="off"
|
||
challenge="https://api.example.com/challenge"
|
||
configuration='{"minDuration": 1000}'
|
||
display="standard"
|
||
language="en"
|
||
name="altcha"
|
||
theme="default"
|
||
type="checkbox"
|
||
workers="4"
|
||
></altcha-widget>
|
||
```
|
||
|
||
> [!TIP]
|
||
> The `configuration` attribute accepts a JSON-encoded string, allowing you to pass complex settings directly in your HTML markup.
|
||
|
||
### Core Settings
|
||
|
||
- **`name`**: The `name` attribute of the hidden input field containing the payload. (Default: `"altcha"`)
|
||
- **`challenge`**: The challenge data or the URL to fetch a new challenge from.
|
||
- **`type`**: Visual style of the interaction element (`'native'`, `'checkbox'`, or `'switch'`).
|
||
- **`language`**: The ISO alpha-2 language code for localization (requires corresponding i18n file).
|
||
- **`workers`**: The number of Web Workers to spawn for proof-of-work calculations.
|
||
|
||
### Automation & Timing
|
||
|
||
- **`auto`**: Determines when verification triggers automatically (`'off'`, `'onfocus'`, `'onload'`, or `'onsubmit'`).
|
||
- **`minDuration`**: The minimum verification time in milliseconds; adds an artificial delay if the PoW is faster. (Default: `500`)
|
||
- **`retryOnOutOfMemoryError`**: Automatically attempts to restart verification with fewer workers if the browser runs out of memory (Argon2 and Scrypt only).
|
||
|
||
### UI & Display
|
||
|
||
- **`display`**: The visual layout mode (`'standard'`, `'bar'`, `'floating'`, `'overlay'`, or `'invisible'`).
|
||
- **`barPlacement`**: Vertical position of the widget when `display` is set to `bar` (`'bottom'` or `'top'`).
|
||
- **`hideLogo`**: Hides the ALTCHA logo icon.
|
||
- **`hideFooter`**: Hides the "ALTCHA" attribution link.
|
||
- **`validationMessage`**: Custom validation message for the HTML5 `setCustomValidity` API.
|
||
|
||
### Floating Widget Settings
|
||
|
||
- **`floatingAnchor`**: The element or CSS selector the floating UI attaches to. Defaults to the first submit button.
|
||
- **`floatingPlacement`**: Preferred position relative to the anchor (`'auto'`, `'bottom'`, or `'top'`).
|
||
- **`floatingOffset`**: Vertical offset in pixels between the UI and its anchor. (Default: `12`)
|
||
- **`floatingPersist`**: Whether the floating widget remains visible after successful verification.
|
||
- **`popoverPlacement`**: Preferred position of popovers relative to the widget (`'auto'`, `'bottom'`, or `'top'`).
|
||
|
||
### Modal & Challenge Settings
|
||
|
||
- **`codeChallengeDisplay`**: UI layout for the code-challenge modal (`'standard'`, `'overlay'`, or `'bottomsheet'`).
|
||
- **`overlayContent`**: CSS selector for an element to be mirrored inside the overlay modal.
|
||
- **`audioChallengeLanguage`**: Forces a specific language for audio-based challenges.
|
||
- **`disableAutoFocus`**: Prevents the code-challenge modal from stealing focus when opened.
|
||
|
||
### Advanced & Debugging
|
||
|
||
- **`debug`**: Enables verbose logging in the browser console.
|
||
- **`test`**: Mocks a successful verification for testing environments.
|
||
- **`mockError`**: Forces the widget into a failed state for UI testing.
|
||
- **`fetch`**: A custom `fetch` implementation for network requests.
|
||
- **`humanInteractionSignature`**: Whether the collector for HIS is enabled (Default: `true`).
|
||
- **`setCookie`**: When configured, sends the payload as a cookie.
|
||
- **`timeout`**: Verification timeout in milliseconds (Default: `90_000`).
|
||
- **`verifyFunction`**: A custom verification handler that overrides default network verification.
|
||
|
||
## Algorithms
|
||
|
||
ALTCHA supports multiple proof-of-work algorithms. `PBKDF2/*` and `SHA-*` are bundled with the main widget by default. `Argon2` and `Scrypt` are memory-bound algorithms that resist hardware acceleration (ASICs/GPUs) but require importing their workers separately.
|
||
|
||
**Supported algorithms:**
|
||
|
||
- `PBKDF2/SHA-256` (default, bundled)
|
||
- `PBKDF2/SHA-384` (bundled)
|
||
- `PBKDF2/SHA-512` (bundled)
|
||
- `SHA-256` (bundled)
|
||
- `SHA-384` (bundled)
|
||
- `SHA-512` (bundled)
|
||
- `ARGON2ID` (requires separate worker import)
|
||
- `SCRYPT` (requires separate worker import)
|
||
|
||
If you use `Argon2` or `Scrypt`, import their workers and register them via the `$altcha.algorithms` global before the widget initializes.
|
||
|
||
### Adding Argon2 / Scrypt Workers (Vite)
|
||
|
||
Works with both `altcha` and `altcha/external`:
|
||
|
||
```ts
|
||
import 'altcha'; // or 'altcha/external'
|
||
import Argon2idWorker from 'altcha/workers/argon2id?worker';
|
||
import ScryptWorker from 'altcha/workers/scrypt?worker';
|
||
|
||
$altcha.algorithms.set('ARGON2ID', () => new Argon2idWorker());
|
||
$altcha.algorithms.set('SCRYPT', () => new ScryptWorker());
|
||
```
|
||
|
||
### Without Bundler Worker Import Support
|
||
|
||
If your environment does not support `?worker` imports, load the prebuilt worker files directly:
|
||
|
||
```ts
|
||
import 'altcha';
|
||
|
||
$altcha.algorithms.set(
|
||
'ARGON2ID',
|
||
() => new Worker('/path/to/node_modules/altcha/dist/workers/argon2id.js')
|
||
);
|
||
$altcha.algorithms.set(
|
||
'SCRYPT',
|
||
() => new Worker('/path/to/node_modules/altcha/dist/workers/scrypt.js')
|
||
);
|
||
```
|
||
|
||
### Using `altcha/external`
|
||
|
||
`altcha/external` excludes all bundled workers, requiring you to register every algorithm explicitly. Use this for full control over which workers are loaded:
|
||
|
||
```ts
|
||
import 'altcha/external';
|
||
import Argon2idWorker from 'altcha/workers/argon2id?worker';
|
||
import Pbkdf2Worker from 'altcha/workers/pbkdf2?worker';
|
||
import ScryptWorker from 'altcha/workers/scrypt?worker';
|
||
import ShaWorker from 'altcha/workers/sha?worker';
|
||
|
||
$altcha.algorithms.set('PBKDF2/SHA-256', () => new Pbkdf2Worker());
|
||
$altcha.algorithms.set('PBKDF2/SHA-384', () => new Pbkdf2Worker());
|
||
$altcha.algorithms.set('PBKDF2/SHA-512', () => new Pbkdf2Worker());
|
||
$altcha.algorithms.set('SHA-256', () => new ShaWorker());
|
||
$altcha.algorithms.set('SHA-384', () => new ShaWorker());
|
||
$altcha.algorithms.set('SHA-512', () => new ShaWorker());
|
||
$altcha.algorithms.set('ARGON2ID', () => new Argon2idWorker());
|
||
$altcha.algorithms.set('SCRYPT', () => new ScryptWorker());
|
||
```
|
||
|
||
## Cookies
|
||
|
||
By default, the widget sends the ALTCHA payload as a form field by creating a hidden input. It can also be configured to send the payload via a cookie.
|
||
|
||
To enable this behavior, use the `setCookie` configuration option:
|
||
|
||
```ts
|
||
widget.configure({
|
||
setCookie: {
|
||
name: 'altcha',
|
||
path: '/'
|
||
}
|
||
});
|
||
```
|
||
|
||
`setCookie` accepts the following cookie options:
|
||
|
||
```ts
|
||
interface SetCookieOptions {
|
||
domain?: string;
|
||
name?: string;
|
||
maxAge?: number;
|
||
path?: string;
|
||
sameSite?: string;
|
||
secure?: boolean;
|
||
}
|
||
```
|
||
|
||
## Server Configuration
|
||
|
||
When the widget fetches a challenge from the server, the server can override widget configuration using either the `X-Altcha-Config` response header or the `configuration` property in the challenge response.
|
||
|
||
Example using the `configuration` property in the challenge JSON response to force cookie usage:
|
||
|
||
```json
|
||
{
|
||
"configuration": {
|
||
"setCookie": {
|
||
"name": "altcha",
|
||
"path": "/submit"
|
||
}
|
||
},
|
||
"parameters": {},
|
||
"signature": "..."
|
||
}
|
||
```
|
||
|
||
The `X-Altcha-Config` header must contain a JSON-encoded object with configuration options.
|
||
|
||
## Internationalization (i18n)
|
||
|
||
ALTCHA supports **50+ languages**. You can import individual language translations or a bundle that includes all of them.
|
||
|
||
### Importing Translations
|
||
|
||
To import all translations:
|
||
|
||
```js
|
||
import 'altcha/i18n/all';
|
||
```
|
||
|
||
To import specific languages only:
|
||
|
||
```js
|
||
import 'altcha/i18n/de';
|
||
import 'altcha/i18n/fr-fr';
|
||
```
|
||
|
||
Alternatively, you can import the combined bundle, which includes both the widget and all translations:
|
||
|
||
```js
|
||
import 'altcha/i18n';
|
||
```
|
||
|
||
### Language Detection
|
||
|
||
The widget automatically detects the language from:
|
||
|
||
- The `<html lang="...">` attribute
|
||
- The user's browser settings (`navigator.languages`)
|
||
|
||
To override the language manually, use the `language` attribute:
|
||
|
||
```html
|
||
<altcha-widget language="de"></altcha-widget>
|
||
```
|
||
|
||
### Customizing Translations
|
||
|
||
You can override default translations by updating the global `$altcha` registry (`globalThis.$altcha.i18n`):
|
||
|
||
```js
|
||
import 'altcha/i18n/de';
|
||
|
||
$altcha.i18n.set('de', {
|
||
...$altcha.i18n.get('de'),
|
||
label: 'Ich bin ein Mensch' // Custom label
|
||
});
|
||
```
|
||
|
||
## Code Challenges
|
||
|
||
For additional verification, ALTCHA supports **image/audio code challenges** (e.g., "Enter the code from the image"). This feature requires [ALTCHA Sentinel](https://altcha.org/docs/v2/sentinel) or a custom server implementation.
|
||
|
||
## Data Obfuscation
|
||
|
||
[Data obfuscation]() is supported via an official plugin, which must be imported alongside the widget. This is ideal for protecting sensitive information, such as email addresses, from scrapers until the challenge is solved.
|
||
|
||
To obfuscate data, run:
|
||
|
||
```sh
|
||
npx altcha-lib obfuscate [data]
|
||
```
|
||
|
||
### Programmatic Usage
|
||
|
||
The plugin exports `ObfuscationPlugin` with static methods `obfuscate` and `deobfuscate` for manual data handling:
|
||
|
||
```ts
|
||
import { ObfuscationPlugin } from 'altcha/plugins/obfuscation';
|
||
|
||
const obfuscatedData = await ObfuscationPlugin.obfuscate('mailto:hello@example.com');
|
||
```
|
||
|
||
### Widget Integration
|
||
|
||
To use the plugin with the widget, ensure `altcha/plugins/obfuscation` is imported before the main library. Use the `data-obfuscated` attribute to provide the Base64-encoded payload:
|
||
|
||
```html
|
||
<script>
|
||
import 'altcha/plugins/obfuscation';
|
||
import 'altcha';
|
||
</script>
|
||
|
||
<altcha-widget data-obfuscated="${obfuscatedData}" display="floating"></altcha-widget>
|
||
```
|
||
|
||
## Methods
|
||
|
||
- `configure(options)` - Configures the widget with the given options. See Configuration options above.
|
||
- `getConfiguration()` - Returns the current configuration.
|
||
- `getState()` - Returns the current `state` of the widget.
|
||
- `show()` - Displays the widget (used in some display modes).
|
||
- `hide()` - Hides the widget (used in some display modes).
|
||
- `reset(state?, err?)` - Resets the internal `state`, optionally with an error.
|
||
- `setState(state, err?)` - Manually sets the specified `state`, optionally with an error.
|
||
- `updateUI()` - Force UI update or reposition, for example for the floating display mode.
|
||
- `verify()` - Initiates the verification process.
|
||
|
||
## Events
|
||
|
||
- **codechallenge** - Triggers when code-challenge verification is requested.
|
||
- **expired** - Triggers when the challenge expires.
|
||
- **load** - Triggers when the widget loads. The exported methods become available after this event.
|
||
- **outofmemory** - Triggers when an Out-Of-Memory error is received (Argon2 and Scrypt only).
|
||
- **serververification** -Triggers upon a server verification.
|
||
- **statechange** - Triggers whenever an internal `state` changes.
|
||
- **verified** - Triggers when the challenge is verified.
|
||
|
||
```ts
|
||
enum State {
|
||
CODE = 'code',
|
||
ERROR = 'error',
|
||
VERIFIED = 'verified',
|
||
VERIFYING = 'verifying',
|
||
UNVERIFIED = 'unverified',
|
||
EXPIRED = 'expired'
|
||
}
|
||
```
|
||
|
||
Using events:
|
||
|
||
```js
|
||
document.querySelector('altcha-widget').addEventListener('statechange', (ev) => {
|
||
// See enum State above
|
||
console.log('state:', ev.detail.state);
|
||
});
|
||
```
|
||
|
||
> [!IMPORTANT]
|
||
> Both programmatic configuration and event listeners have to called/attached after the ALTCHA script loads, such as within `window.addEventListener('load', ...)`.
|
||
|
||
## Contributing
|
||
|
||
See [Contributing Guide](https://github.com/altcha-org/altcha/blob/main/CONTRIBUTING.md) and please follow our [Code of Conduct](https://github.com/altcha-org/altcha/blob/main/CODE_OF_CONDUCT.md).
|
||
|
||
## License
|
||
|
||
MIT
|