ribaunt 0.1.2 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,258 @@
1
+ # Ribaunt
2
+
3
+ [![npm version](https://img.shields.io/npm/v/ribaunt.svg)](https://www.npmjs.com/package/ribaunt)
4
+ [![license: GPL-3.0-only](https://img.shields.io/badge/license-GPL--3.0--only-blue.svg)](./LICENSE)
5
+
6
+ Ribaunt is a stateless proof-of-work CAPTCHA library for Node.js and modern browsers. It issues signed JWT challenges from your server, solves them in the browser, and verifies the submitted proof before you accept a form, sign-up, comment, or other sensitive action.
7
+
8
+ - Website: [ribaunt.com](https://ribaunt.com)
9
+ - Package: [npmjs.com/package/ribaunt](https://www.npmjs.com/package/ribaunt)
10
+ - Docs: [GitHub docs](https://github.com/ribaunt/ribaunt/tree/main/docs)
11
+ - Context7: [context7.com/ribaunt/ribaunt](https://context7.com/ribaunt/ribaunt)
12
+
13
+ ## Features
14
+
15
+ - Stateless challenge tokens signed with your `RIBAUNT_SECRET`
16
+ - Browser widget for plain HTML apps
17
+ - React and Next.js-friendly wrapper via `ribaunt/widget-react`
18
+ - Server helpers for creating, solving, and verifying PoW challenges
19
+ - Default process-local replay protection with support for remote replay stores
20
+ - CSS custom properties for theming
21
+ - TypeScript types included
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ npm install ribaunt
27
+ ```
28
+
29
+ ```bash
30
+ yarn add ribaunt
31
+ ```
32
+
33
+ ```bash
34
+ pnpm add ribaunt
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ Set a strong secret in your server environment. Keep this server-only.
40
+
41
+ ```env
42
+ RIBAUNT_SECRET="replace-with-a-long-random-secret"
43
+ ```
44
+
45
+ Create two endpoints: one to issue challenges and one to verify solutions.
46
+
47
+ ```ts
48
+ import 'dotenv/config';
49
+ import express from 'express';
50
+ import { createChallenge, verifySolution } from 'ribaunt';
51
+
52
+ const app = express();
53
+
54
+ app.use(express.json());
55
+
56
+ app.get('/api/captcha/challenge', (_req, res) => {
57
+ const challenges = createChallenge(5, 4, 120);
58
+ res.json({ challenges });
59
+ });
60
+
61
+ app.post('/api/captcha/verify', async (req, res) => {
62
+ const { tokens, solutions } = req.body;
63
+ const valid = await verifySolution(tokens, solutions);
64
+
65
+ if (!valid) {
66
+ return res.status(400).json({ success: false, error: 'Invalid CAPTCHA solution' });
67
+ }
68
+
69
+ return res.json({ success: true });
70
+ });
71
+
72
+ app.listen(3000);
73
+ ```
74
+
75
+ Add the widget to your frontend.
76
+
77
+ ```html
78
+ <script type="module" src="/node_modules/ribaunt/dist/widget-browser.js"></script>
79
+
80
+ <ribaunt-widget
81
+ challenge-endpoint="/api/captcha/challenge"
82
+ verify-endpoint="/api/captcha/verify"
83
+ auto-verify="true"
84
+ solve-timeout="15000"
85
+ ></ribaunt-widget>
86
+
87
+ <script>
88
+ const widget = document.querySelector('ribaunt-widget');
89
+
90
+ widget.addEventListener('verify', (event) => {
91
+ console.log('Verified:', event.detail.solutions);
92
+ });
93
+
94
+ widget.addEventListener('error', (event) => {
95
+ console.error('Verification failed:', event.detail.error);
96
+ });
97
+ </script>
98
+ ```
99
+
100
+ Browser solving requires a secure context. Use HTTPS in production or `http://localhost` during development.
101
+
102
+ ## React Usage
103
+
104
+ ```tsx
105
+ 'use client';
106
+
107
+ import RibauntWidget from 'ribaunt/widget-react';
108
+
109
+ export function ContactFormCaptcha() {
110
+ return (
111
+ <RibauntWidget
112
+ challengeEndpoint="/api/captcha/challenge"
113
+ verifyEndpoint="/api/captcha/verify"
114
+ autoVerify={true}
115
+ solveTimeout={15000}
116
+ onVerify={(detail) => console.log('Verified:', detail.solutions)}
117
+ onError={(detail) => console.error('CAPTCHA failed:', detail.error)}
118
+ />
119
+ );
120
+ }
121
+ ```
122
+
123
+ For Next.js App Router, keep the widget in a client component. Do not expose `RIBAUNT_SECRET` with a `NEXT_PUBLIC_` prefix.
124
+
125
+ ## API
126
+
127
+ ### `createChallenge(difficulty, amount, ttlSeconds)`
128
+
129
+ Creates signed challenge tokens.
130
+
131
+ ```ts
132
+ const challenges = createChallenge(5, 4, 120);
133
+ ```
134
+
135
+ | Parameter | Default | Description |
136
+ | --- | --- | --- |
137
+ | `difficulty` | `5` | Number of leading zeros required in the SHA-256 hash. Higher values increase solve time. |
138
+ | `amount` | `4` | Number of challenges to create. |
139
+ | `ttlSeconds` | `30` | Challenge token lifetime in seconds. |
140
+
141
+ Validate user- or config-controlled values before passing them to `createChallenge()`. Invalid values throw.
142
+
143
+ ### `verifySolution(tokens, solutions, options?)`
144
+
145
+ Verifies submitted solutions and returns `Promise<boolean>`.
146
+
147
+ ```ts
148
+ const valid = await verifySolution(tokens, solutions, {
149
+ onWarning: (warning) => {
150
+ console.log('captcha warning', warning.reason, warning.message);
151
+ },
152
+ });
153
+ ```
154
+
155
+ Replay prevention defaults to `local`, which blocks token reuse in the current process. For serverless or horizontally scaled deployments, use `replayPrevention: 'remote'` with an atomic distributed store.
156
+
157
+ ```ts
158
+ const valid = await verifySolution(tokens, solutions, {
159
+ replayPrevention: 'remote',
160
+ replayStore: {
161
+ consume: async (jti, expiresAt) => {
162
+ // Implement with Redis/Valkey using atomic set-if-not-exists plus expiry.
163
+ return true;
164
+ },
165
+ },
166
+ });
167
+ ```
168
+
169
+ ### `solveChallenge(token, options?)`
170
+
171
+ Solves challenges synchronously. This is mainly useful for tests and debugging.
172
+
173
+ ```ts
174
+ const solutions = solveChallenge(challenges, {
175
+ maxDurationMs: 2000,
176
+ maxIterations: 500_000,
177
+ });
178
+ ```
179
+
180
+ ## Widget Configuration
181
+
182
+ ```html
183
+ <ribaunt-widget
184
+ challenge-endpoint="/api/captcha/challenge"
185
+ verify-endpoint="/api/captcha/verify"
186
+ auto-verify="true"
187
+ show-warning="false"
188
+ warning-message="Verification may take longer on this device."
189
+ solve-timeout="15000"
190
+ disabled="false"
191
+ ></ribaunt-widget>
192
+ ```
193
+
194
+ | HTML attribute | React prop | Description |
195
+ | --- | --- | --- |
196
+ | `challenge-endpoint` | `challengeEndpoint` | Endpoint that returns `{ challenges: string[] }`. |
197
+ | `verify-endpoint` | `verifyEndpoint` | Endpoint that accepts `{ tokens, solutions }`. |
198
+ | `auto-verify` | `autoVerify` | Starts verification when the widget loads. |
199
+ | `show-warning` | `showWarning` | Shows a warning banner. |
200
+ | `warning-message` | `warningMessage` | Custom warning text. |
201
+ | `solve-timeout` | `solveTimeout` | Optional solve timeout in milliseconds. |
202
+ | `disabled` | `disabled` | Blocks user interaction and automatic verification. |
203
+
204
+ The recommended challenge response shape is:
205
+
206
+ ```json
207
+ { "challenges": ["jwt-token-1", "jwt-token-2"] }
208
+ ```
209
+
210
+ The widget also accepts `{ "tokens": [...] }` and raw string arrays for compatibility.
211
+
212
+ ## Theming
213
+
214
+ Customize the widget with CSS custom properties.
215
+
216
+ ```css
217
+ ribaunt-widget {
218
+ --ribaunt-background: #ffffff;
219
+ --ribaunt-border-color: #d8dee4;
220
+ --ribaunt-border-radius: 10px;
221
+ --ribaunt-color: #111827;
222
+ --ribaunt-widget-width: 260px;
223
+ --ribaunt-spinner-color: #111827;
224
+ }
225
+ ```
226
+
227
+ See [theming docs](https://github.com/ribaunt/ribaunt/blob/main/docs/theming.md) for the full variable list.
228
+
229
+ ## Documentation
230
+
231
+ - [Quick start](https://github.com/ribaunt/ribaunt/blob/main/docs/quick-start.md)
232
+ - [Configuration](https://github.com/ribaunt/ribaunt/blob/main/docs/configuration.md)
233
+ - [Events](https://github.com/ribaunt/ribaunt/blob/main/docs/events.md)
234
+ - [HTML integration](https://github.com/ribaunt/ribaunt/blob/main/docs/integrations/html.md)
235
+ - [React integration](https://github.com/ribaunt/ribaunt/blob/main/docs/integrations/react.md)
236
+ - [Next.js integration](https://github.com/ribaunt/ribaunt/blob/main/docs/integrations/nextjs.md)
237
+ - [Vue integration](https://github.com/ribaunt/ribaunt/blob/main/docs/integrations/vue.md)
238
+ - [Express server example](https://github.com/ribaunt/ribaunt/blob/main/docs/server/express.md)
239
+ - [Next.js route handlers](https://github.com/ribaunt/ribaunt/blob/main/docs/server/nextjs-api.md)
240
+ - [Testing](https://github.com/ribaunt/ribaunt/blob/main/docs/testing.md)
241
+
242
+ You can also ask documentation-aware tools to use the Context7 library ID:
243
+
244
+ ```text
245
+ /ribaunt/ribaunt
246
+ ```
247
+
248
+ ## Development
249
+
250
+ ```bash
251
+ npm install
252
+ npm test
253
+ npm run build
254
+ ```
255
+
256
+ ## License
257
+
258
+ GPL-3.0-only. See [LICENSE](./LICENSE).
package/context7.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "url": "https://context7.com/ribaunt/ribaunt",
3
+ "public_key": "pk_0hOWdNLxagQvIBshSH0ZZ"
4
+ }
@@ -3,10 +3,35 @@ export interface ChallengeSolution {
3
3
  nonce: string;
4
4
  hash: string;
5
5
  }
6
+ export interface ReplayStore {
7
+ consume(jti: string, expiresAt: number): Promise<boolean>;
8
+ }
9
+ export type ReplayPreventionMode = 'disabled' | 'local' | 'remote';
10
+ export interface VerifySolutionOptions {
11
+ replayPrevention?: ReplayPreventionMode;
12
+ replayStore?: ReplayStore;
13
+ debug?: boolean;
14
+ onWarning?: (warning: VerifyWarning) => void;
15
+ }
16
+ export type VerifyWarningReason = 'invalid-token' | 'expired-token' | 'invalid-solution' | 'replay-detected' | 'configuration-error';
17
+ export interface VerifyWarning {
18
+ reason: VerifyWarningReason;
19
+ message: string;
20
+ error?: unknown;
21
+ }
22
+ export interface SolveChallengeOptions {
23
+ maxIterations?: number;
24
+ maxDurationMs?: number;
25
+ }
26
+ export declare class LocalReplayStore implements ReplayStore {
27
+ private usedTokens;
28
+ consume(jti: string, expiresAt: number): Promise<boolean>;
29
+ private cleanup;
30
+ }
6
31
  /**
7
32
  * Creates one or more PoW challenges and returns them as signed JWT tokens.
8
33
  *
9
- * @param difficulty - Number of leading zeros required in the hash (default 6)
34
+ * @param difficulty - Number of leading zeros required in the hash (default 5)
10
35
  * @param amount - Number of challenges to create (default 4)
11
36
  * @param ttlSeconds - Time to live for each challenge in seconds (default 30)
12
37
  * @returns An array of JWT challenge tokens
@@ -16,10 +41,13 @@ export declare function createChallenge(difficulty?: number, amount?: number, tt
16
41
  * Solves one or more PoW challenges encoded in JWT tokens.
17
42
  *
18
43
  * @param token - The JWT challenge token or an array of tokens
44
+ * @param options - Optional guardrails for test/debug usage (`maxIterations`, `maxDurationMs`)
19
45
  * @returns The nonce/hash pair for single input or an array of them for multiple tokens
20
46
  */
21
47
  export declare function solveChallenge(token: ChallengeToken): ChallengeSolution | undefined;
48
+ export declare function solveChallenge(token: ChallengeToken, options?: SolveChallengeOptions): ChallengeSolution | undefined;
22
49
  export declare function solveChallenge(token: ChallengeToken[]): ChallengeSolution[] | undefined;
50
+ export declare function solveChallenge(token: ChallengeToken[], options?: SolveChallengeOptions): ChallengeSolution[] | undefined;
23
51
  /**
24
52
  * Verifies a PoW solution returned by the client.
25
53
  *
@@ -27,5 +55,5 @@ export declare function solveChallenge(token: ChallengeToken[]): ChallengeSoluti
27
55
  * @param nonce - The nonce/answer submitted by the client (single nonce, array of nonces, or array of solution objects)
28
56
  * @returns true only if every provided solution is valid; otherwise false
29
57
  */
30
- export declare function verifySolution(token: ChallengeToken | ChallengeToken[], nonce: number | string | Array<number | string> | ChallengeSolution | ChallengeSolution[]): boolean;
58
+ export declare function verifySolution(token: ChallengeToken | ChallengeToken[], nonce: number | string | Array<number | string> | ChallengeSolution | ChallengeSolution[], options?: VerifySolutionOptions): Promise<boolean>;
31
59
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAyED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,UAAU,GAAE,MAAU,EACtB,MAAM,GAAE,MAAU,EAClB,UAAU,GAAE,MAAW,GACtB,cAAc,EAAE,CAUlB;AAoDD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,GAAG,iBAAiB,GAAG,SAAS,CAAC;AACrF,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,iBAAiB,EAAE,GAAG,SAAS,CAAC;AAuBzF;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,cAAc,GAAG,cAAc,EAAE,EACxC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,iBAAiB,GAAG,iBAAiB,EAAE,GACxF,OAAO,CAqDT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3D;AAED,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEnE,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;CAC9C;AAED,MAAM,MAAM,mBAAmB,GAC3B,eAAe,GACf,eAAe,GACf,kBAAkB,GAClB,iBAAiB,GACjB,qBAAqB,CAAC;AAE1B,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAa,gBAAiB,YAAW,WAAW;IAClD,OAAO,CAAC,UAAU,CAA6B;IAEzC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAW/D,OAAO,CAAC,OAAO;CAShB;AAoMD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,UAAU,GAAE,MAAU,EACtB,MAAM,GAAE,MAAU,EAClB,UAAU,GAAE,MAAW,GACtB,cAAc,EAAE,CAUlB;AA0FD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,GAAG,iBAAiB,GAAG,SAAS,CAAC;AACrF,wBAAgB,cAAc,CAC5B,KAAK,EAAE,cAAc,EACrB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,iBAAiB,GAAG,SAAS,CAAC;AACjC,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,iBAAiB,EAAE,GAAG,SAAS,CAAC;AACzF,wBAAgB,cAAc,CAC5B,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,iBAAiB,EAAE,GAAG,SAAS,CAAC;AAwBnC;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,cAAc,GAAG,cAAc,EAAE,EACxC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,iBAAiB,GAAG,iBAAiB,EAAE,EACzF,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,OAAO,CAAC,CAuDlB"}
package/dist/cjs/index.js CHANGED
@@ -3,11 +3,36 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.LocalReplayStore = void 0;
6
7
  exports.createChallenge = createChallenge;
7
8
  exports.solveChallenge = solveChallenge;
8
9
  exports.verifySolution = verifySolution;
9
10
  const crypto_1 = __importDefault(require("crypto"));
10
11
  const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
12
+ class LocalReplayStore {
13
+ constructor() {
14
+ this.usedTokens = new Map();
15
+ }
16
+ async consume(jti, expiresAt) {
17
+ this.cleanup();
18
+ if (this.usedTokens.has(jti)) {
19
+ return false;
20
+ }
21
+ this.usedTokens.set(jti, expiresAt);
22
+ return true;
23
+ }
24
+ cleanup() {
25
+ const now = Math.floor(Date.now() / 1000);
26
+ for (const [jti, expiresAt] of this.usedTokens.entries()) {
27
+ if (expiresAt < now) {
28
+ this.usedTokens.delete(jti);
29
+ }
30
+ }
31
+ }
32
+ }
33
+ exports.LocalReplayStore = LocalReplayStore;
34
+ const defaultLocalReplayStore = new LocalReplayStore();
35
+ const DEFAULT_SOLVE_MAX_DURATION_MS = 30000;
11
36
  function generateChallenge(length = 8) {
12
37
  const buffer = crypto_1.default.randomBytes(length);
13
38
  return buffer.toString('base64').slice(0, length);
@@ -17,14 +42,101 @@ function createChallengePayload(difficulty, ttlSeconds) {
17
42
  challenge: generateChallenge(),
18
43
  difficulty,
19
44
  expires: Math.floor(Date.now() / 1000) + ttlSeconds,
45
+ jti: crypto_1.default.randomUUID(),
20
46
  };
21
47
  }
48
+ let cachedSecret;
22
49
  function getSecret() {
23
50
  const secret = process.env.RIBAUNT_SECRET;
24
51
  if (!secret) {
52
+ cachedSecret = undefined;
25
53
  throw new Error('RIBAUNT_SECRET environment variable is not set!');
26
54
  }
27
- return secret;
55
+ if (cachedSecret === secret) {
56
+ return cachedSecret;
57
+ }
58
+ cachedSecret = secret;
59
+ return cachedSecret;
60
+ }
61
+ function shouldDebugVerifyErrors(options) {
62
+ if (options?.debug !== undefined) {
63
+ return options.debug;
64
+ }
65
+ return process.env.NODE_ENV === 'development';
66
+ }
67
+ function logVerifyWarning(message, options, error) {
68
+ const warning = {
69
+ reason: classifyVerifyWarningReason(error),
70
+ message,
71
+ error,
72
+ };
73
+ options?.onWarning?.(warning);
74
+ if (!shouldDebugVerifyErrors(options)) {
75
+ return;
76
+ }
77
+ const details = error instanceof Error ? error.message : error;
78
+ console.warn(`[ribaunt] ${message}`, details ?? '');
79
+ }
80
+ function emitVerifyWarning(reason, message, options) {
81
+ options?.onWarning?.({ reason, message });
82
+ if (!shouldDebugVerifyErrors(options)) {
83
+ return;
84
+ }
85
+ console.warn(`[ribaunt] ${message}`, '');
86
+ }
87
+ function classifyVerifyWarningReason(error) {
88
+ if (error && typeof error === 'object' && 'name' in error) {
89
+ const name = String(error.name);
90
+ if (name === 'TokenExpiredError') {
91
+ return 'expired-token';
92
+ }
93
+ if (name === 'JsonWebTokenError' || name === 'NotBeforeError') {
94
+ return 'invalid-token';
95
+ }
96
+ }
97
+ if (error instanceof Error && error.message.includes('replayStore')) {
98
+ return 'configuration-error';
99
+ }
100
+ return 'invalid-token';
101
+ }
102
+ function normalizeMaxIterations(options) {
103
+ if (options?.maxIterations === undefined) {
104
+ return undefined;
105
+ }
106
+ if (!Number.isFinite(options.maxIterations)) {
107
+ return undefined;
108
+ }
109
+ const normalized = Math.floor(options.maxIterations);
110
+ if (normalized < 1) {
111
+ return 1;
112
+ }
113
+ return normalized;
114
+ }
115
+ function normalizeMaxDurationMs(options) {
116
+ if (options?.maxDurationMs === undefined) {
117
+ return DEFAULT_SOLVE_MAX_DURATION_MS;
118
+ }
119
+ if (!Number.isFinite(options.maxDurationMs)) {
120
+ return DEFAULT_SOLVE_MAX_DURATION_MS;
121
+ }
122
+ const normalized = Math.floor(options.maxDurationMs);
123
+ if (normalized < 1) {
124
+ return 1;
125
+ }
126
+ return normalized;
127
+ }
128
+ function getReplayStore(options) {
129
+ const mode = options?.replayPrevention ?? 'local';
130
+ if (mode === 'disabled') {
131
+ return undefined;
132
+ }
133
+ if (mode === 'local') {
134
+ return defaultLocalReplayStore;
135
+ }
136
+ if (!options?.replayStore) {
137
+ throw new Error('A replayStore is required when replayPrevention is set to "remote"');
138
+ }
139
+ return options.replayStore;
28
140
  }
29
141
  function signChallenge(payload) {
30
142
  return jsonwebtoken_1.default.sign(payload, getSecret());
@@ -66,7 +178,7 @@ function createSingleChallenge(difficulty, ttlSeconds) {
66
178
  /**
67
179
  * Creates one or more PoW challenges and returns them as signed JWT tokens.
68
180
  *
69
- * @param difficulty - Number of leading zeros required in the hash (default 6)
181
+ * @param difficulty - Number of leading zeros required in the hash (default 5)
70
182
  * @param amount - Number of challenges to create (default 4)
71
183
  * @param ttlSeconds - Time to live for each challenge in seconds (default 30)
72
184
  * @returns An array of JWT challenge tokens
@@ -78,15 +190,24 @@ function createChallenge(difficulty = 5, amount = 4, ttlSeconds = 30) {
78
190
  const challenges = Array.from({ length: normalizedAmount }, () => createSingleChallenge(normalizedDifficulty, normalizedTtl));
79
191
  return challenges;
80
192
  }
81
- function solveSingleChallenge(token) {
193
+ function solveSingleChallenge(token, options) {
82
194
  try {
83
195
  const payload = jsonwebtoken_1.default.decode(token);
84
196
  if (!payload)
85
197
  return undefined;
86
198
  const { challenge, difficulty } = payload;
87
199
  const prefix = '0'.repeat(difficulty);
200
+ const maxIterations = normalizeMaxIterations(options);
201
+ const maxDurationMs = normalizeMaxDurationMs(options);
202
+ const startedAt = Date.now();
88
203
  let nonce = 0;
89
204
  while (true) {
205
+ if (maxIterations !== undefined && nonce >= maxIterations) {
206
+ return undefined;
207
+ }
208
+ if (Date.now() - startedAt >= maxDurationMs) {
209
+ return undefined;
210
+ }
90
211
  const hash = crypto_1.default
91
212
  .createHash('sha256')
92
213
  .update(`${challenge}${nonce}`)
@@ -101,32 +222,49 @@ function solveSingleChallenge(token) {
101
222
  return undefined;
102
223
  }
103
224
  }
104
- function verifySingleSolution(token, nonce) {
225
+ async function verifySingleSolution(token, nonce, options) {
105
226
  if (nonce === undefined || nonce === null) {
227
+ emitVerifyWarning('invalid-solution', 'verifySolution received an empty nonce', options);
106
228
  return false;
107
229
  }
108
230
  try {
231
+ const replayStore = getReplayStore(options);
109
232
  const payload = jsonwebtoken_1.default.verify(token, getSecret());
110
233
  const now = Math.floor(Date.now() / 1000);
111
- if (payload.expires < now)
234
+ if (payload.expires < now) {
235
+ emitVerifyWarning('expired-token', 'verifySolution rejected an expired challenge token', options);
112
236
  return false;
237
+ }
113
238
  const nonceValue = typeof nonce === 'number' ? String(nonce) : nonce;
114
239
  const hash = crypto_1.default
115
240
  .createHash('sha256')
116
241
  .update(`${payload.challenge}${nonceValue}`)
117
242
  .digest('hex');
118
243
  const prefix = '0'.repeat(payload.difficulty);
119
- return hash.startsWith(prefix);
244
+ const isValid = hash.startsWith(prefix);
245
+ if (!isValid) {
246
+ emitVerifyWarning('invalid-solution', 'verifySolution rejected an invalid nonce', options);
247
+ return false;
248
+ }
249
+ if (replayStore && payload.jti) {
250
+ const consumed = await replayStore.consume(payload.jti, payload.expires);
251
+ if (!consumed) {
252
+ emitVerifyWarning('replay-detected', 'verifySolution rejected a replayed token', options);
253
+ return false;
254
+ }
255
+ }
256
+ return true;
120
257
  }
121
258
  catch (err) {
259
+ logVerifyWarning('verifySolution rejected a token or nonce', options, err);
122
260
  return false;
123
261
  }
124
262
  }
125
- function solveChallenge(token) {
263
+ function solveChallenge(token, options) {
126
264
  if (Array.isArray(token)) {
127
265
  const solutions = [];
128
266
  for (const singleToken of token) {
129
- const solution = solveSingleChallenge(singleToken);
267
+ const solution = solveSingleChallenge(singleToken, options);
130
268
  if (!solution) {
131
269
  return undefined;
132
270
  }
@@ -134,7 +272,7 @@ function solveChallenge(token) {
134
272
  }
135
273
  return solutions;
136
274
  }
137
- const solution = solveSingleChallenge(token);
275
+ const solution = solveSingleChallenge(token, options);
138
276
  return solution;
139
277
  }
140
278
  /**
@@ -144,12 +282,12 @@ function solveChallenge(token) {
144
282
  * @param nonce - The nonce/answer submitted by the client (single nonce, array of nonces, or array of solution objects)
145
283
  * @returns true only if every provided solution is valid; otherwise false
146
284
  */
147
- function verifySolution(token, nonce) {
285
+ function verifySolution(token, nonce, options) {
148
286
  if (Array.isArray(token)) {
149
287
  let nonces;
150
288
  if (Array.isArray(nonce)) {
151
289
  if (nonce.length !== token.length) {
152
- return false;
290
+ return Promise.resolve(false);
153
291
  }
154
292
  if (nonce.length > 0 && typeof nonce[0] === 'object' && 'nonce' in nonce[0]) {
155
293
  nonces = nonce.map(s => s.nonce);
@@ -159,24 +297,26 @@ function verifySolution(token, nonce) {
159
297
  }
160
298
  }
161
299
  else {
162
- return false;
300
+ return Promise.resolve(false);
163
301
  }
164
- for (let index = 0; index < token.length; index++) {
165
- const challengeToken = token[index];
166
- const nonceEntry = nonces[index];
167
- if (challengeToken === undefined || nonceEntry === undefined) {
168
- return false;
169
- }
170
- if (!verifySingleSolution(challengeToken, nonceEntry)) {
171
- return false;
302
+ return (async () => {
303
+ for (let index = 0; index < token.length; index++) {
304
+ const challengeToken = token[index];
305
+ const nonceEntry = nonces[index];
306
+ if (challengeToken === undefined || nonceEntry === undefined) {
307
+ return false;
308
+ }
309
+ if (!await verifySingleSolution(challengeToken, nonceEntry, options)) {
310
+ return false;
311
+ }
172
312
  }
173
- }
174
- return true;
313
+ return true;
314
+ })();
175
315
  }
176
316
  let effectiveNonce;
177
317
  if (Array.isArray(nonce)) {
178
318
  if (nonce.length === 0) {
179
- return false;
319
+ return Promise.resolve(false);
180
320
  }
181
321
  if (typeof nonce[0] === 'object' && 'nonce' in nonce[0]) {
182
322
  effectiveNonce = nonce[0].nonce;
@@ -185,16 +325,15 @@ function verifySolution(token, nonce) {
185
325
  effectiveNonce = nonce[0];
186
326
  }
187
327
  }
188
- else if (typeof nonce === 'object' && 'nonce' in nonce) {
328
+ else if (nonce && typeof nonce === 'object' && 'nonce' in nonce) {
189
329
  effectiveNonce = nonce.nonce;
190
330
  }
191
331
  else {
192
332
  effectiveNonce = nonce;
193
333
  }
194
334
  if (effectiveNonce === undefined) {
195
- return false;
335
+ return Promise.resolve(false);
196
336
  }
197
- const result = verifySingleSolution(token, effectiveNonce);
198
- return result;
337
+ return verifySingleSolution(token, effectiveNonce, options);
199
338
  }
200
339
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}