altcha
Version:
Privacy-first CAPTCHA widget, compliant with global regulations (GDPR/HIPAA/CCPA/LGDP/DPDPA/PIPL) and WCAG accessible. No tracking, self-verifying.
481 lines (476 loc) • 14.4 kB
TypeScript
// Generated by dts-bundle-generator v9.5.1
export interface AltchaGlobal {
algorithms: Map<string, () => Worker | Promise<Worker>>;
defaults: Store<Partial<Configuration>>;
i18n: Store<Record<string, Record<string, string>>>;
instances: Set<HTMLElement>;
plugins: Set<new (host: HTMLElement & WidgetMethods) => any>;
}
export declare enum AudioState {
ERROR = "error",
LOADING = "loading",
PLAYING = "playing",
PAUSED = "paused",
READY = "ready"
}
export interface Configuration {
/**
* Forces a specific language for audio-based challenges.
*/
audioChallengeLanguage: string;
/**
* Determines when verification triggers automatically.
* @default 'off'
*/
auto: "off" | "onfocus" | "onload" | "onsubmit";
/**
* Vertical position of the widget when `display` is set to `bar`.
*/
barPlacement: "bottom" | "top";
/**
* The challenge data or the URL to fetch a new challenge from.
*/
challenge: Challenge | string | null;
/**
* A specific code-challenge object. Overrides values provided in the `challenge` property.
*/
codeChallenge: CodeChallenge | null;
/**
* The UI layout used for the code-challenge modal.
*/
codeChallengeDisplay: "standard" | "overlay" | "bottomsheet";
/**
* Defines how credentials (cookies/auth headers) are handled during the challenge request.
*/
credentials: RequestCredentials | null;
/**
* Enables verbose logging in the browser console for debugging.
*/
debug: boolean;
/**
* Prevents the code-challenge modal from stealing focus when opened.
*/
disableAutoFocus: boolean;
/**
* The visual layout mode of the widget.
*/
display: "standard" | "bar" | "floating" | "overlay" | "invisible";
/**
* A custom `fetch` implementation for network requests.
*/
fetch: typeof fetch;
/**
* The element or CSS selector the floating UI attaches to.
* Defaults to the first `submit` button in the parent form.
*/
floatingAnchor: string | HTMLElement | null;
/**
* Vertical offset (in pixels) between the floating UI and its anchor.
* @default 12
*/
floatingOffset: number;
/**
* Controls whether the floating widget remains visible after successful verification.
*/
floatingPersist: boolean | "focus";
/**
* Preferred position of the floating widget relative to the anchor.
*/
floatingPlacement: "auto" | "bottom" | "top";
/**
* Hides the "ALTCHA" attribution link.
*/
hideFooter: boolean;
/**
* Hides the ALTCHA logo icon.
*/
hideLogo: boolean;
/**
* Enables the collection of pointer and scroll events for ALTCHA HIS mechanism (defaults to true).
*/
humanInteractionSignature: boolean;
/**
* The ISO alpha-2 language code for localization (requires corresponding i18n file).
*/
language: string;
/**
* The minimum verification time in milliseconds (adds an artificial delay if the PoW is faster).
* @default 500
*/
minDuration: number;
/**
* Forces the widget into a failed state with a mock error for UI testing.
*/
mockError: boolean;
/**
* The `name` attribute of the hidden input field containing the payload.
* @default 'altcha'
*/
name: string;
/**
* CSS selector for an element to be mirrored inside the overlay modal.
*/
overlayContent: string | null;
/**
* Configures the placement (top / bottom) for popovers. Defaults to 'auto'.
*/
popoverPlacement: "auto" | "bottom" | "top";
/**
* Automatically attempts to restart verification with fewer workers if the browser runs out of memory (Argon2 and Scrypt only).
*/
retryOnOutOfMemoryError: boolean;
/**
* Includes other form field values in the server-side verification request.
*/
serverVerificationFields: boolean;
/**
* Includes the user's time zone in the server-side verification request.
*/
serverVerificationTimeZone: boolean;
/**
* When set, the widget will set a configured cookie for the payload instead of sending it as form field.
*/
setCookie: SetCookieOptions | null;
/**
* Mocks a successful verification. Useful for testing environments without network access.
*/
test: boolean;
/**
* PoW verification timeout in milliseconds. Defaults to 90_000 ms.
*/
timeout: number;
/**
* The visual style of the interaction element.
*/
type: "native" | "checkbox" | "switch";
/**
* Custom validation message for the HTML5 `setCustomValidity` API.
*/
validationMessage: string;
/**
* A custom verification handler. Overrides the default network-based verification.
*/
verifyFunction: ((payload: string, code?: string) => Promise<ServerVerificationResult | null>) | null;
/**
* The endpoint URL for server-side verification.
*/
verifyUrl: string | null;
/**
* The number of Web Workers to spawn for proof-of-work calculations.
*/
workers: number;
}
export interface Challenge {
codeChallenge?: CodeChallenge;
parameters: ChallengeParameters;
signature?: string;
}
export interface ChallengeParameters {
algorithm: string;
nonce: string;
salt: string;
cost: number;
keyLength: number;
keyPrefix: string;
keySignature?: string;
memoryCost?: number;
parallelism?: number;
expiresAt?: number;
data?: Record<string, string | number | boolean | null>;
}
export interface ChallengeV1 {
algorithm: string;
challenge: string;
codeChallenge?: CodeChallenge;
salt: string;
maxnumber?: number;
maxNumber?: number;
signature: string;
}
export interface CodeChallenge {
image: string;
audio?: string;
length?: number;
}
export interface CreateChallengeOptions {
algorithm: string;
counter?: number;
counterMode?: "uint32" | "string";
cost: number;
data?: Record<string, string | number | boolean | null>;
deriveKey: DeriveKeyFunction;
expiresAt?: number | Date;
hmacAlgorithm?: HmacAlgorithm;
hmacKeySignatureSecret?: string;
hmacSignatureSecret?: string;
keyLength?: number;
keyPrefix?: string;
keyPrefixLength?: number;
memoryCost?: number;
parallelism?: number;
}
export interface CSSVariables {
"--altcha-border-color": string;
"--altcha-border-width": string;
"--altcha-border-radius": string;
"--altcha-color-base": string;
"--altcha-color-base-content": string;
"--altcha-color-error": string;
"--altcha-color-error-content": string;
"--altcha-color-neutral": string;
"--altcha-color-neutral-content": string;
"--altcha-color-primary": string;
"--altcha-color-primary-content": string;
"--altcha-color-success": string;
"--altcha-color-success-content": string;
"--altcha-checkbox-border-color": string;
"--altcha-checkbox-border-radius": string;
"--altcha-checkbox-border-width": string;
"--altcha-checkbox-outline": string;
"--altcha-checkbox-outline-offset": string;
"--altcha-checkbox-size": string;
"--altcha-checkbox-transition-duration": string;
"--altcha-input-background-color": string;
"--altcha-input-border-radius": string;
"--altcha-input-border-width": string;
"--altcha-max-width": string;
"--altcha-padding": string;
"--altcha-popover-arrow-size": string;
"--altcha-popover-color": string;
"--altcha-shadow": string;
"--altcha-spinner-color": string;
"--altcha-switch-background-color": string;
"--altcha-switch-border-radius": string;
"--altcha-switch-height": string;
"--altcha-switch-padding": string;
"--altcha-switch-width": string;
"--altcha-switch-toggle-border-radius": string;
"--altcha-switch-toggle-color": string;
"--altcha-switch-toggle-size": string;
"--altcha-transition-duration": string;
"--altcha-z-index": string | number;
"--altcha-z-index-popover": string | number;
}
export type DeriveKeyFunction = (parameters: ChallengeParameters, salt: Uint8Array, password: Uint8Array) => Promise<DeriveKeyFunctionResult>;
export interface DeriveKeyFunctionResult {
parameters?: Partial<ChallengeParameters>;
derivedKey: Uint8Array;
}
export declare enum HmacAlgorithm {
SHA_256 = "SHA-256",
SHA_384 = "SHA-384",
SHA_512 = "SHA-512"
}
export interface Payload {
challenge: Omit<Challenge, "codeChallenge">;
solution: Solution;
}
export interface PayloadV1 {
algorithm: string;
challenge: string;
number: number;
salt: string;
signature?: string;
took: number;
}
export interface SetCookieOptions {
domain?: string;
name?: string;
maxAge?: number;
path?: string;
sameSite?: string;
secure?: boolean;
}
export type ServerClassification = "BAD" | "GOOD" | "NEUTRAL";
export interface ServerSignaturePayload {
algorithm: string;
apiKey?: string;
id?: string;
signature: string;
verificationData: string;
verified: boolean;
}
export interface ServerSignatureVerificationData {
[key: string]: string | unknown;
classification?: ServerClassification;
email?: string;
expire?: number;
fields?: string[];
fieldsHash?: string;
id?: string;
ipAddress?: string;
reasons?: string[];
score?: number;
time?: number;
verified?: boolean;
}
export interface ServerVerificationResult {
algorithm?: string;
apiKey?: string;
id?: string;
payload?: string;
reason?: string;
score?: number;
signature?: string;
verificationData?: string;
verified?: boolean;
}
export interface SolveChallengeOptions {
challenge: Challenge;
controller?: AbortController;
counterStart?: number;
counterStep?: number;
counterMode?: "uint32" | "string";
deriveKey: DeriveKeyFunction;
timeout?: number;
}
export interface Strings {
ariaLinkLabel: string;
enterCode: string;
enterCodeAria: string;
error: string;
expired: string;
footer: string;
getAudioChallenge: string;
label: string;
loading: string;
reload: string;
verify: string;
verificationRequired: string;
verified: string;
verifying: string;
waitAlert: string;
}
export declare enum State {
CODE = "code",
ERROR = "error",
VERIFIED = "verified",
VERIFYING = "verifying",
UNVERIFIED = "unverified",
EXPIRED = "expired"
}
export interface Solution {
counter: number;
derivedKey: string;
time?: number;
}
export type Store<T extends object, K extends keyof T = keyof T> = {
get: (name: K) => T[K];
set: <N extends K>(name: N | T, value?: T[N]) => void;
store: Writable<T>;
};
export interface VerifyOptions {
concurrency?: number;
controller?: AbortController;
minDuration?: number;
}
export interface VerifyResult {
challenge?: Challenge;
payload: string;
solution?: Solution;
}
export interface VerifyServerSignatureResult extends VerifySolutionResult {
verificationData?: ServerSignatureVerificationData | null;
}
export interface VerifySolutionOptions {
challenge: Challenge;
counterMode?: "uint32" | "string";
deriveKey: DeriveKeyFunction;
hmacAlgorithm?: HmacAlgorithm;
hmacKeySignatureSecret?: string;
hmacSignatureSecret: string;
solution: Solution;
}
export interface VerifySolutionResult {
expired: boolean;
invalidSignature: boolean | null;
invalidSolution: boolean | null;
time: number;
verified: boolean;
}
export interface WidgetAttributes extends Partial<Pick<Configuration, "auto" | "display" | "language" | "name" | "type">> {
challenge?: string;
configuration?: string;
}
export interface WidgetMethods {
configure: (config: Partial<Configuration>) => Promise<void>;
getConfiguration: () => Configuration;
getState: () => State;
hide: () => void;
reset: (newState?: State, err?: string | null) => void;
setState: (newState: State, err?: string | null) => void;
show: () => void;
updateUI: () => void;
verify: (options?: VerifyOptions) => Promise<VerifyResult | null>;
}
export type Writable<T = Record<string, Record<string, string>>> = {
set(this: void, value: T): void;
update(this: void, updater: (value: T) => T): void;
subscribe(this: void, run: (value: T) => void, invalidate?: () => void): () => void;
};
declare function deriveKey(parameters: ChallengeParameters, salt: Uint8Array, password: Uint8Array): Promise<DeriveKeyFunctionResult>;
declare function deriveKey$1(parameters: ChallengeParameters, salt: Uint8Array, password: Uint8Array): Promise<DeriveKeyFunctionResult>;
declare function deriveKey$2(parameters: ChallengeParameters, salt: Uint8Array, password: Uint8Array): Promise<DeriveKeyFunctionResult>;
declare function deriveKey$3(parameters: ChallengeParameters, salt: Uint8Array, password: Uint8Array): Promise<DeriveKeyFunctionResult>;
/**
* Creates a new proof-of-work challenge.
*
* Generates random nonce and salt, optionally pre-computes a key prefix
* from a known counter value, and optionally signs the challenge with HMAC.
*/
export declare function createChallenge(options: CreateChallengeOptions): Promise<Challenge>;
/**
* Solves a challenge by brute-forcing counter values until the derived key
* starts with the required prefix. Returns the solution or null on timeout/abort.
*/
export declare function solveChallenge(options: SolveChallengeOptions): Promise<Solution | null>;
/**
* Solves a challenge using multiple Web Workers in parallel.
* Each worker tests a different subset of counter values (interleaved by concurrency).
* Automatically retries with fewer workers on out-of-memory errors.
*/
export declare function solveChallengeWorkers(options: Omit<SolveChallengeOptions, "deriveKey"> & {
concurrency: number;
createWorker: (algorithm: string) => Worker | Promise<Worker>;
onOutOfMemory?: (concurrency: number) => number | void;
}): Promise<Solution | null>;
/**
* Verifies a submitted solution against a challenge.
*
* Checks (in order):
* 1. Whether the challenge has expired.
* 2. Whether the challenge has signature parameter.
* 3. Whether the challenge signature is valid (tamper check).
* 4. Whether the derived key matches — either via key signature or by re-deriving.
*/
export declare function verifySolution(options: VerifySolutionOptions): Promise<VerifySolutionResult>;
export declare function parseVerificationData(data: string, convertToArray?: string[]): ServerSignatureVerificationData | null;
export declare function verifyFieldsHash(options: {
formData: FormData | Record<string, unknown>;
fields: string[];
fieldsHash: string;
algorithm?: string;
}): Promise<boolean>;
export declare function verifyServerSignature(options: {
payload: ServerSignaturePayload;
hmacSecret: string;
}): Promise<VerifyServerSignatureResult>;
declare namespace sha {
export { deriveKey$3 as deriveKey };
}
declare namespace argon2id {
export { deriveKey };
}
declare namespace pbkdf2 {
export { deriveKey$1 as deriveKey };
}
declare namespace scrypt {
export { deriveKey$2 as deriveKey };
}
export {
argon2id,
pbkdf2,
scrypt,
sha,
};
export {};