altcha-lib 0.4.0 → 0.5.0
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 +24 -11
- package/cjs/dist/index.d.ts +62 -2
- package/cjs/dist/index.js +86 -11
- package/cjs/dist/types.d.ts +5 -1
- package/dist/index.d.ts +62 -2
- package/dist/index.js +84 -10
- package/dist/types.d.ts +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -86,6 +86,30 @@ Parameters:
|
|
|
86
86
|
|
|
87
87
|
Returns: `Promise<boolean>`
|
|
88
88
|
|
|
89
|
+
### `verifyServerSignature(payload, hmacKey)`
|
|
90
|
+
|
|
91
|
+
Verifies the server signature returned by the API. The payload can be a Base64-encoded JSON payload or an object.
|
|
92
|
+
|
|
93
|
+
Parameters:
|
|
94
|
+
|
|
95
|
+
- `payload: string | ServerSignaturePayload`
|
|
96
|
+
- `hmacKey: string`
|
|
97
|
+
|
|
98
|
+
Returns: `Promise<{ verificationData: ServerSignatureVerificationData | null, verified: boolean }>`
|
|
99
|
+
|
|
100
|
+
### `verifyFieldsHash(formData, fields, fieldsHash, algorithm?)`
|
|
101
|
+
|
|
102
|
+
Verifies the hash of form fields returned by the Spam Filter.
|
|
103
|
+
|
|
104
|
+
Parameters:
|
|
105
|
+
|
|
106
|
+
- `formData: FormData | Record<string, unknown>`
|
|
107
|
+
- `fields: string[]`
|
|
108
|
+
- `fieldsHash: string`
|
|
109
|
+
- `algorithm: Algorithm = 'SHA-256'`
|
|
110
|
+
|
|
111
|
+
Returns: `Promise<boolean>`
|
|
112
|
+
|
|
89
113
|
### `solveChallenge(challenge, salt, algorithm?, max?, start?)`
|
|
90
114
|
|
|
91
115
|
Finds a solution to the given challenge.
|
|
@@ -100,17 +124,6 @@ Parameters:
|
|
|
100
124
|
|
|
101
125
|
Returns: `{ controller: AbortController, promise: Promise<Solution | null> }`
|
|
102
126
|
|
|
103
|
-
### `verifyServerSignature(payload, hmacKey)`
|
|
104
|
-
|
|
105
|
-
Verifies the server signature returned by the API. The payload can be a Base64-encoded JSON payload or an object.
|
|
106
|
-
|
|
107
|
-
Parameters:
|
|
108
|
-
|
|
109
|
-
- `payload: string | ServerSignaturePayload`
|
|
110
|
-
- `hmacKey: string`
|
|
111
|
-
|
|
112
|
-
Returns: `Promise<{ verificationData: ServerSignatureVerificationData | null, verified: boolean }>`
|
|
113
|
-
|
|
114
127
|
### `solveChallengeWorkers(workerScript, concurrency, challenge, salt, algorithm?, max?, start?)`
|
|
115
128
|
|
|
116
129
|
Finds a solution to the given challenge with [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker) running concurrently.
|
package/cjs/dist/index.d.ts
CHANGED
|
@@ -1,23 +1,83 @@
|
|
|
1
|
-
import type { Challenge, ChallengeOptions, Payload, ServerSignaturePayload, ServerSignatureVerificationData, Solution } from './types.js';
|
|
1
|
+
import type { Algorithm, Challenge, ChallengeOptions, Payload, ServerSignaturePayload, ServerSignatureVerificationData, Solution } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a challenge for the client to solve.
|
|
4
|
+
*
|
|
5
|
+
* @param {ChallengeOptions} options - Options for creating the challenge.
|
|
6
|
+
* @returns {Promise<Challenge>} The created challenge.
|
|
7
|
+
*/
|
|
2
8
|
export declare function createChallenge(options: ChallengeOptions): Promise<Challenge>;
|
|
9
|
+
/**
|
|
10
|
+
* Extracts parameters from the payload.
|
|
11
|
+
*
|
|
12
|
+
* @param {string | Payload | Challenge} payload - The payload from which to extract parameters.
|
|
13
|
+
* @returns {Record<string, string>} The extracted parameters.
|
|
14
|
+
*/
|
|
3
15
|
export declare function extractParams(payload: string | Payload | Challenge): {
|
|
4
16
|
[k: string]: string;
|
|
5
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* Verifies the solution provided by the client.
|
|
20
|
+
*
|
|
21
|
+
* @param {string | Payload} payload - The payload to verify.
|
|
22
|
+
* @param {string} hmacKey - The HMAC key used for verification.
|
|
23
|
+
* @param {boolean} [checkExpires=true] - Whether to check if the challenge has expired.
|
|
24
|
+
* @returns {Promise<boolean>} Whether the solution is valid.
|
|
25
|
+
*/
|
|
6
26
|
export declare function verifySolution(payload: string | Payload, hmacKey: string, checkExpires?: boolean): Promise<boolean>;
|
|
27
|
+
/**
|
|
28
|
+
* Verifies the hash of form fields.
|
|
29
|
+
*
|
|
30
|
+
* @param {FormData | Record<string, unknown>} formData - The form data to verify.
|
|
31
|
+
* @param {string[]} fields - The fields to include in the hash.
|
|
32
|
+
* @param {string} fieldsHash - The expected hash of the fields.
|
|
33
|
+
* @param {string} [algorithm=DEFAULT_ALG] - The hash algorithm to use.
|
|
34
|
+
* @returns {Promise<boolean>} Whether the fields hash is valid.
|
|
35
|
+
*/
|
|
36
|
+
export declare function verifyFieldsHash(formData: FormData | Record<string, unknown>, fields: string[], fieldsHash: string, algorithm?: Algorithm): Promise<boolean>;
|
|
37
|
+
/**
|
|
38
|
+
* Verifies the server's signature.
|
|
39
|
+
*
|
|
40
|
+
* @param {string | ServerSignaturePayload} payload - The payload to verify.
|
|
41
|
+
* @param {string} hmacKey - The HMAC key used for verification.
|
|
42
|
+
* @returns {Promise<{verificationData: ServerSignatureVerificationData | null, verified: boolean}>} The verification result.
|
|
43
|
+
*/
|
|
7
44
|
export declare function verifyServerSignature(payload: string | ServerSignaturePayload, hmacKey: string): Promise<{
|
|
8
45
|
verificationData: ServerSignatureVerificationData | null;
|
|
9
|
-
verified: boolean
|
|
46
|
+
verified: boolean;
|
|
10
47
|
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Solves a challenge by brute force.
|
|
50
|
+
*
|
|
51
|
+
* @param {string} challenge - The challenge to solve.
|
|
52
|
+
* @param {string} salt - The salt used in the challenge.
|
|
53
|
+
* @param {string} [algorithm='SHA-256'] - The hash algorithm used.
|
|
54
|
+
* @param {number} [max=1e6] - The maximum number to try.
|
|
55
|
+
* @param {number} [start=0] - The starting number.
|
|
56
|
+
* @returns {{promise: Promise<Solution | null>, controller: AbortController}} The solution promise and abort controller.
|
|
57
|
+
*/
|
|
11
58
|
export declare function solveChallenge(challenge: string, salt: string, algorithm?: string, max?: number, start?: number): {
|
|
12
59
|
promise: Promise<Solution | null>;
|
|
13
60
|
controller: AbortController;
|
|
14
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* Solves a challenge using web workers for parallel computation.
|
|
64
|
+
*
|
|
65
|
+
* @param {string | URL | (() => Worker)} workerScript - The worker script or function to create a worker.
|
|
66
|
+
* @param {number} concurrency - The number of workers to use.
|
|
67
|
+
* @param {string} challenge - The challenge to solve.
|
|
68
|
+
* @param {string} salt - The salt used in the challenge.
|
|
69
|
+
* @param {string} [algorithm='SHA-256'] - The hash algorithm used.
|
|
70
|
+
* @param {number} [max=1e6] - The maximum number to try.
|
|
71
|
+
* @param {number} [startNumber=0] - The starting number.
|
|
72
|
+
* @returns {Promise<Solution | null>} The solution, or null if not found.
|
|
73
|
+
*/
|
|
15
74
|
export declare function solveChallengeWorkers(workerScript: string | URL | (() => Worker), concurrency: number, challenge: string, salt: string, algorithm?: string, max?: number, startNumber?: number): Promise<Solution | null>;
|
|
16
75
|
declare const _default: {
|
|
17
76
|
createChallenge: typeof createChallenge;
|
|
18
77
|
extractParams: typeof extractParams;
|
|
19
78
|
solveChallenge: typeof solveChallenge;
|
|
20
79
|
solveChallengeWorkers: typeof solveChallengeWorkers;
|
|
80
|
+
verifyFieldsHash: typeof verifyFieldsHash;
|
|
21
81
|
verifyServerSignature: typeof verifyServerSignature;
|
|
22
82
|
verifySolution: typeof verifySolution;
|
|
23
83
|
};
|
package/cjs/dist/index.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.solveChallengeWorkers = exports.solveChallenge = exports.verifyServerSignature = exports.verifySolution = exports.extractParams = exports.createChallenge = void 0;
|
|
3
|
+
exports.solveChallengeWorkers = exports.solveChallenge = exports.verifyServerSignature = exports.verifyFieldsHash = exports.verifySolution = exports.extractParams = exports.createChallenge = void 0;
|
|
4
4
|
const helpers_js_1 = require("./helpers.js");
|
|
5
5
|
const DEFAULT_MAX_NUMBER = 1e6;
|
|
6
6
|
const DEFAULT_SALT_LEN = 12;
|
|
7
7
|
const DEFAULT_ALG = 'SHA-256';
|
|
8
|
+
/**
|
|
9
|
+
* Creates a challenge for the client to solve.
|
|
10
|
+
*
|
|
11
|
+
* @param {ChallengeOptions} options - Options for creating the challenge.
|
|
12
|
+
* @returns {Promise<Challenge>} The created challenge.
|
|
13
|
+
*/
|
|
8
14
|
async function createChallenge(options) {
|
|
9
15
|
const algorithm = options.algorithm || DEFAULT_ALG;
|
|
10
16
|
const maxnumber = options.maxnumber || options.maxNumber || DEFAULT_MAX_NUMBER;
|
|
@@ -29,6 +35,12 @@ async function createChallenge(options) {
|
|
|
29
35
|
};
|
|
30
36
|
}
|
|
31
37
|
exports.createChallenge = createChallenge;
|
|
38
|
+
/**
|
|
39
|
+
* Extracts parameters from the payload.
|
|
40
|
+
*
|
|
41
|
+
* @param {string | Payload | Challenge} payload - The payload from which to extract parameters.
|
|
42
|
+
* @returns {Record<string, string>} The extracted parameters.
|
|
43
|
+
*/
|
|
32
44
|
function extractParams(payload) {
|
|
33
45
|
if (typeof payload === 'string') {
|
|
34
46
|
payload = JSON.parse(atob(payload));
|
|
@@ -36,9 +48,22 @@ function extractParams(payload) {
|
|
|
36
48
|
return Object.fromEntries(new URLSearchParams(payload.salt.split('?')?.[1] || ''));
|
|
37
49
|
}
|
|
38
50
|
exports.extractParams = extractParams;
|
|
51
|
+
/**
|
|
52
|
+
* Verifies the solution provided by the client.
|
|
53
|
+
*
|
|
54
|
+
* @param {string | Payload} payload - The payload to verify.
|
|
55
|
+
* @param {string} hmacKey - The HMAC key used for verification.
|
|
56
|
+
* @param {boolean} [checkExpires=true] - Whether to check if the challenge has expired.
|
|
57
|
+
* @returns {Promise<boolean>} Whether the solution is valid.
|
|
58
|
+
*/
|
|
39
59
|
async function verifySolution(payload, hmacKey, checkExpires = true) {
|
|
40
60
|
if (typeof payload === 'string') {
|
|
41
|
-
|
|
61
|
+
try {
|
|
62
|
+
payload = JSON.parse(atob(payload));
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
42
67
|
}
|
|
43
68
|
const params = extractParams(payload);
|
|
44
69
|
const expires = params.expires || params.expire;
|
|
@@ -58,9 +83,42 @@ async function verifySolution(payload, hmacKey, checkExpires = true) {
|
|
|
58
83
|
check.signature === payload.signature);
|
|
59
84
|
}
|
|
60
85
|
exports.verifySolution = verifySolution;
|
|
86
|
+
/**
|
|
87
|
+
* Verifies the hash of form fields.
|
|
88
|
+
*
|
|
89
|
+
* @param {FormData | Record<string, unknown>} formData - The form data to verify.
|
|
90
|
+
* @param {string[]} fields - The fields to include in the hash.
|
|
91
|
+
* @param {string} fieldsHash - The expected hash of the fields.
|
|
92
|
+
* @param {string} [algorithm=DEFAULT_ALG] - The hash algorithm to use.
|
|
93
|
+
* @returns {Promise<boolean>} Whether the fields hash is valid.
|
|
94
|
+
*/
|
|
95
|
+
async function verifyFieldsHash(formData, fields, fieldsHash, algorithm = DEFAULT_ALG) {
|
|
96
|
+
const data = formData instanceof FormData ? Object.fromEntries(formData) : formData;
|
|
97
|
+
const lines = [];
|
|
98
|
+
for (const field of fields) {
|
|
99
|
+
lines.push(String(data[field] || ''));
|
|
100
|
+
}
|
|
101
|
+
return (await (0, helpers_js_1.hashHex)(algorithm, lines.join('\n'))) === fieldsHash;
|
|
102
|
+
}
|
|
103
|
+
exports.verifyFieldsHash = verifyFieldsHash;
|
|
104
|
+
/**
|
|
105
|
+
* Verifies the server's signature.
|
|
106
|
+
*
|
|
107
|
+
* @param {string | ServerSignaturePayload} payload - The payload to verify.
|
|
108
|
+
* @param {string} hmacKey - The HMAC key used for verification.
|
|
109
|
+
* @returns {Promise<{verificationData: ServerSignatureVerificationData | null, verified: boolean}>} The verification result.
|
|
110
|
+
*/
|
|
61
111
|
async function verifyServerSignature(payload, hmacKey) {
|
|
62
112
|
if (typeof payload === 'string') {
|
|
63
|
-
|
|
113
|
+
try {
|
|
114
|
+
payload = JSON.parse(atob(payload));
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return {
|
|
118
|
+
verificationData: null,
|
|
119
|
+
verified: false,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
64
122
|
}
|
|
65
123
|
const signature = await (0, helpers_js_1.hmacHex)(payload.algorithm, await (0, helpers_js_1.hash)(payload.algorithm, payload.verificationData), hmacKey);
|
|
66
124
|
let verificationData = null;
|
|
@@ -84,13 +142,22 @@ async function verifyServerSignature(payload, hmacKey) {
|
|
|
84
142
|
return {
|
|
85
143
|
verificationData,
|
|
86
144
|
verified: payload.verified === true &&
|
|
87
|
-
verificationData &&
|
|
88
|
-
verificationData.verified === true &&
|
|
145
|
+
verificationData?.verified === true &&
|
|
89
146
|
verificationData.expire > Math.floor(Date.now() / 1000) &&
|
|
90
147
|
payload.signature === signature,
|
|
91
148
|
};
|
|
92
149
|
}
|
|
93
150
|
exports.verifyServerSignature = verifyServerSignature;
|
|
151
|
+
/**
|
|
152
|
+
* Solves a challenge by brute force.
|
|
153
|
+
*
|
|
154
|
+
* @param {string} challenge - The challenge to solve.
|
|
155
|
+
* @param {string} salt - The salt used in the challenge.
|
|
156
|
+
* @param {string} [algorithm='SHA-256'] - The hash algorithm used.
|
|
157
|
+
* @param {number} [max=1e6] - The maximum number to try.
|
|
158
|
+
* @param {number} [start=0] - The starting number.
|
|
159
|
+
* @returns {{promise: Promise<Solution | null>, controller: AbortController}} The solution promise and abort controller.
|
|
160
|
+
*/
|
|
94
161
|
function solveChallenge(challenge, salt, algorithm = 'SHA-256', max = 1e6, start = 0) {
|
|
95
162
|
const controller = new AbortController();
|
|
96
163
|
const startTime = Date.now();
|
|
@@ -115,14 +182,21 @@ function solveChallenge(challenge, salt, algorithm = 'SHA-256', max = 1e6, start
|
|
|
115
182
|
};
|
|
116
183
|
}
|
|
117
184
|
exports.solveChallenge = solveChallenge;
|
|
185
|
+
/**
|
|
186
|
+
* Solves a challenge using web workers for parallel computation.
|
|
187
|
+
*
|
|
188
|
+
* @param {string | URL | (() => Worker)} workerScript - The worker script or function to create a worker.
|
|
189
|
+
* @param {number} concurrency - The number of workers to use.
|
|
190
|
+
* @param {string} challenge - The challenge to solve.
|
|
191
|
+
* @param {string} salt - The salt used in the challenge.
|
|
192
|
+
* @param {string} [algorithm='SHA-256'] - The hash algorithm used.
|
|
193
|
+
* @param {number} [max=1e6] - The maximum number to try.
|
|
194
|
+
* @param {number} [startNumber=0] - The starting number.
|
|
195
|
+
* @returns {Promise<Solution | null>} The solution, or null if not found.
|
|
196
|
+
*/
|
|
118
197
|
async function solveChallengeWorkers(workerScript, concurrency, challenge, salt, algorithm = 'SHA-256', max = 1e6, startNumber = 0) {
|
|
119
198
|
const workers = [];
|
|
120
|
-
|
|
121
|
-
throw new Error('Wrong number of workers configured.');
|
|
122
|
-
}
|
|
123
|
-
if (concurrency > 16) {
|
|
124
|
-
throw new Error('Too many workers. Max. 16 allowed workers.');
|
|
125
|
-
}
|
|
199
|
+
concurrency = Math.min(1, Math.max(16, concurrency));
|
|
126
200
|
for (let i = 0; i < concurrency; i++) {
|
|
127
201
|
if (typeof workerScript === 'function') {
|
|
128
202
|
workers.push(workerScript());
|
|
@@ -170,6 +244,7 @@ exports.default = {
|
|
|
170
244
|
extractParams,
|
|
171
245
|
solveChallenge,
|
|
172
246
|
solveChallengeWorkers,
|
|
247
|
+
verifyFieldsHash,
|
|
173
248
|
verifyServerSignature,
|
|
174
249
|
verifySolution,
|
|
175
250
|
};
|
package/cjs/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type Algorithm = 'SHA-1' | 'SHA-256' | 'SHA-512';
|
|
2
|
+
export type Classification = 'BAD' | 'GOOD' | 'NEUTRAL';
|
|
2
3
|
export interface Challenge {
|
|
3
4
|
algorithm: Algorithm;
|
|
4
5
|
challenge: string;
|
|
@@ -31,11 +32,14 @@ export interface ServerSignaturePayload {
|
|
|
31
32
|
verified: boolean;
|
|
32
33
|
}
|
|
33
34
|
export interface ServerSignatureVerificationData {
|
|
34
|
-
classification?:
|
|
35
|
+
classification?: Classification;
|
|
36
|
+
country?: string;
|
|
37
|
+
detectedLanguage?: string;
|
|
35
38
|
email?: string;
|
|
36
39
|
expire: number;
|
|
37
40
|
fields?: string[];
|
|
38
41
|
fieldsHash?: string;
|
|
42
|
+
ipAddress?: string;
|
|
39
43
|
reasons?: string[];
|
|
40
44
|
score?: number;
|
|
41
45
|
time: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,23 +1,83 @@
|
|
|
1
|
-
import type { Challenge, ChallengeOptions, Payload, ServerSignaturePayload, ServerSignatureVerificationData, Solution } from './types.js';
|
|
1
|
+
import type { Algorithm, Challenge, ChallengeOptions, Payload, ServerSignaturePayload, ServerSignatureVerificationData, Solution } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a challenge for the client to solve.
|
|
4
|
+
*
|
|
5
|
+
* @param {ChallengeOptions} options - Options for creating the challenge.
|
|
6
|
+
* @returns {Promise<Challenge>} The created challenge.
|
|
7
|
+
*/
|
|
2
8
|
export declare function createChallenge(options: ChallengeOptions): Promise<Challenge>;
|
|
9
|
+
/**
|
|
10
|
+
* Extracts parameters from the payload.
|
|
11
|
+
*
|
|
12
|
+
* @param {string | Payload | Challenge} payload - The payload from which to extract parameters.
|
|
13
|
+
* @returns {Record<string, string>} The extracted parameters.
|
|
14
|
+
*/
|
|
3
15
|
export declare function extractParams(payload: string | Payload | Challenge): {
|
|
4
16
|
[k: string]: string;
|
|
5
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* Verifies the solution provided by the client.
|
|
20
|
+
*
|
|
21
|
+
* @param {string | Payload} payload - The payload to verify.
|
|
22
|
+
* @param {string} hmacKey - The HMAC key used for verification.
|
|
23
|
+
* @param {boolean} [checkExpires=true] - Whether to check if the challenge has expired.
|
|
24
|
+
* @returns {Promise<boolean>} Whether the solution is valid.
|
|
25
|
+
*/
|
|
6
26
|
export declare function verifySolution(payload: string | Payload, hmacKey: string, checkExpires?: boolean): Promise<boolean>;
|
|
27
|
+
/**
|
|
28
|
+
* Verifies the hash of form fields.
|
|
29
|
+
*
|
|
30
|
+
* @param {FormData | Record<string, unknown>} formData - The form data to verify.
|
|
31
|
+
* @param {string[]} fields - The fields to include in the hash.
|
|
32
|
+
* @param {string} fieldsHash - The expected hash of the fields.
|
|
33
|
+
* @param {string} [algorithm=DEFAULT_ALG] - The hash algorithm to use.
|
|
34
|
+
* @returns {Promise<boolean>} Whether the fields hash is valid.
|
|
35
|
+
*/
|
|
36
|
+
export declare function verifyFieldsHash(formData: FormData | Record<string, unknown>, fields: string[], fieldsHash: string, algorithm?: Algorithm): Promise<boolean>;
|
|
37
|
+
/**
|
|
38
|
+
* Verifies the server's signature.
|
|
39
|
+
*
|
|
40
|
+
* @param {string | ServerSignaturePayload} payload - The payload to verify.
|
|
41
|
+
* @param {string} hmacKey - The HMAC key used for verification.
|
|
42
|
+
* @returns {Promise<{verificationData: ServerSignatureVerificationData | null, verified: boolean}>} The verification result.
|
|
43
|
+
*/
|
|
7
44
|
export declare function verifyServerSignature(payload: string | ServerSignaturePayload, hmacKey: string): Promise<{
|
|
8
45
|
verificationData: ServerSignatureVerificationData | null;
|
|
9
|
-
verified: boolean
|
|
46
|
+
verified: boolean;
|
|
10
47
|
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Solves a challenge by brute force.
|
|
50
|
+
*
|
|
51
|
+
* @param {string} challenge - The challenge to solve.
|
|
52
|
+
* @param {string} salt - The salt used in the challenge.
|
|
53
|
+
* @param {string} [algorithm='SHA-256'] - The hash algorithm used.
|
|
54
|
+
* @param {number} [max=1e6] - The maximum number to try.
|
|
55
|
+
* @param {number} [start=0] - The starting number.
|
|
56
|
+
* @returns {{promise: Promise<Solution | null>, controller: AbortController}} The solution promise and abort controller.
|
|
57
|
+
*/
|
|
11
58
|
export declare function solveChallenge(challenge: string, salt: string, algorithm?: string, max?: number, start?: number): {
|
|
12
59
|
promise: Promise<Solution | null>;
|
|
13
60
|
controller: AbortController;
|
|
14
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* Solves a challenge using web workers for parallel computation.
|
|
64
|
+
*
|
|
65
|
+
* @param {string | URL | (() => Worker)} workerScript - The worker script or function to create a worker.
|
|
66
|
+
* @param {number} concurrency - The number of workers to use.
|
|
67
|
+
* @param {string} challenge - The challenge to solve.
|
|
68
|
+
* @param {string} salt - The salt used in the challenge.
|
|
69
|
+
* @param {string} [algorithm='SHA-256'] - The hash algorithm used.
|
|
70
|
+
* @param {number} [max=1e6] - The maximum number to try.
|
|
71
|
+
* @param {number} [startNumber=0] - The starting number.
|
|
72
|
+
* @returns {Promise<Solution | null>} The solution, or null if not found.
|
|
73
|
+
*/
|
|
15
74
|
export declare function solveChallengeWorkers(workerScript: string | URL | (() => Worker), concurrency: number, challenge: string, salt: string, algorithm?: string, max?: number, startNumber?: number): Promise<Solution | null>;
|
|
16
75
|
declare const _default: {
|
|
17
76
|
createChallenge: typeof createChallenge;
|
|
18
77
|
extractParams: typeof extractParams;
|
|
19
78
|
solveChallenge: typeof solveChallenge;
|
|
20
79
|
solveChallengeWorkers: typeof solveChallengeWorkers;
|
|
80
|
+
verifyFieldsHash: typeof verifyFieldsHash;
|
|
21
81
|
verifyServerSignature: typeof verifyServerSignature;
|
|
22
82
|
verifySolution: typeof verifySolution;
|
|
23
83
|
};
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,12 @@ import { ab2hex, hash, hashHex, hmacHex, randomBytes, randomInt, } from './helpe
|
|
|
2
2
|
const DEFAULT_MAX_NUMBER = 1e6;
|
|
3
3
|
const DEFAULT_SALT_LEN = 12;
|
|
4
4
|
const DEFAULT_ALG = 'SHA-256';
|
|
5
|
+
/**
|
|
6
|
+
* Creates a challenge for the client to solve.
|
|
7
|
+
*
|
|
8
|
+
* @param {ChallengeOptions} options - Options for creating the challenge.
|
|
9
|
+
* @returns {Promise<Challenge>} The created challenge.
|
|
10
|
+
*/
|
|
5
11
|
export async function createChallenge(options) {
|
|
6
12
|
const algorithm = options.algorithm || DEFAULT_ALG;
|
|
7
13
|
const maxnumber = options.maxnumber || options.maxNumber || DEFAULT_MAX_NUMBER;
|
|
@@ -25,15 +31,34 @@ export async function createChallenge(options) {
|
|
|
25
31
|
signature: await hmacHex(algorithm, challenge, options.hmacKey),
|
|
26
32
|
};
|
|
27
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Extracts parameters from the payload.
|
|
36
|
+
*
|
|
37
|
+
* @param {string | Payload | Challenge} payload - The payload from which to extract parameters.
|
|
38
|
+
* @returns {Record<string, string>} The extracted parameters.
|
|
39
|
+
*/
|
|
28
40
|
export function extractParams(payload) {
|
|
29
41
|
if (typeof payload === 'string') {
|
|
30
42
|
payload = JSON.parse(atob(payload));
|
|
31
43
|
}
|
|
32
44
|
return Object.fromEntries(new URLSearchParams(payload.salt.split('?')?.[1] || ''));
|
|
33
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Verifies the solution provided by the client.
|
|
48
|
+
*
|
|
49
|
+
* @param {string | Payload} payload - The payload to verify.
|
|
50
|
+
* @param {string} hmacKey - The HMAC key used for verification.
|
|
51
|
+
* @param {boolean} [checkExpires=true] - Whether to check if the challenge has expired.
|
|
52
|
+
* @returns {Promise<boolean>} Whether the solution is valid.
|
|
53
|
+
*/
|
|
34
54
|
export async function verifySolution(payload, hmacKey, checkExpires = true) {
|
|
35
55
|
if (typeof payload === 'string') {
|
|
36
|
-
|
|
56
|
+
try {
|
|
57
|
+
payload = JSON.parse(atob(payload));
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
37
62
|
}
|
|
38
63
|
const params = extractParams(payload);
|
|
39
64
|
const expires = params.expires || params.expire;
|
|
@@ -52,9 +77,41 @@ export async function verifySolution(payload, hmacKey, checkExpires = true) {
|
|
|
52
77
|
return (check.challenge === payload.challenge &&
|
|
53
78
|
check.signature === payload.signature);
|
|
54
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Verifies the hash of form fields.
|
|
82
|
+
*
|
|
83
|
+
* @param {FormData | Record<string, unknown>} formData - The form data to verify.
|
|
84
|
+
* @param {string[]} fields - The fields to include in the hash.
|
|
85
|
+
* @param {string} fieldsHash - The expected hash of the fields.
|
|
86
|
+
* @param {string} [algorithm=DEFAULT_ALG] - The hash algorithm to use.
|
|
87
|
+
* @returns {Promise<boolean>} Whether the fields hash is valid.
|
|
88
|
+
*/
|
|
89
|
+
export async function verifyFieldsHash(formData, fields, fieldsHash, algorithm = DEFAULT_ALG) {
|
|
90
|
+
const data = formData instanceof FormData ? Object.fromEntries(formData) : formData;
|
|
91
|
+
const lines = [];
|
|
92
|
+
for (const field of fields) {
|
|
93
|
+
lines.push(String(data[field] || ''));
|
|
94
|
+
}
|
|
95
|
+
return (await hashHex(algorithm, lines.join('\n'))) === fieldsHash;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Verifies the server's signature.
|
|
99
|
+
*
|
|
100
|
+
* @param {string | ServerSignaturePayload} payload - The payload to verify.
|
|
101
|
+
* @param {string} hmacKey - The HMAC key used for verification.
|
|
102
|
+
* @returns {Promise<{verificationData: ServerSignatureVerificationData | null, verified: boolean}>} The verification result.
|
|
103
|
+
*/
|
|
55
104
|
export async function verifyServerSignature(payload, hmacKey) {
|
|
56
105
|
if (typeof payload === 'string') {
|
|
57
|
-
|
|
106
|
+
try {
|
|
107
|
+
payload = JSON.parse(atob(payload));
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return {
|
|
111
|
+
verificationData: null,
|
|
112
|
+
verified: false,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
58
115
|
}
|
|
59
116
|
const signature = await hmacHex(payload.algorithm, await hash(payload.algorithm, payload.verificationData), hmacKey);
|
|
60
117
|
let verificationData = null;
|
|
@@ -78,12 +135,21 @@ export async function verifyServerSignature(payload, hmacKey) {
|
|
|
78
135
|
return {
|
|
79
136
|
verificationData,
|
|
80
137
|
verified: payload.verified === true &&
|
|
81
|
-
verificationData &&
|
|
82
|
-
verificationData.verified === true &&
|
|
138
|
+
verificationData?.verified === true &&
|
|
83
139
|
verificationData.expire > Math.floor(Date.now() / 1000) &&
|
|
84
140
|
payload.signature === signature,
|
|
85
141
|
};
|
|
86
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* Solves a challenge by brute force.
|
|
145
|
+
*
|
|
146
|
+
* @param {string} challenge - The challenge to solve.
|
|
147
|
+
* @param {string} salt - The salt used in the challenge.
|
|
148
|
+
* @param {string} [algorithm='SHA-256'] - The hash algorithm used.
|
|
149
|
+
* @param {number} [max=1e6] - The maximum number to try.
|
|
150
|
+
* @param {number} [start=0] - The starting number.
|
|
151
|
+
* @returns {{promise: Promise<Solution | null>, controller: AbortController}} The solution promise and abort controller.
|
|
152
|
+
*/
|
|
87
153
|
export function solveChallenge(challenge, salt, algorithm = 'SHA-256', max = 1e6, start = 0) {
|
|
88
154
|
const controller = new AbortController();
|
|
89
155
|
const startTime = Date.now();
|
|
@@ -107,14 +173,21 @@ export function solveChallenge(challenge, salt, algorithm = 'SHA-256', max = 1e6
|
|
|
107
173
|
controller,
|
|
108
174
|
};
|
|
109
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Solves a challenge using web workers for parallel computation.
|
|
178
|
+
*
|
|
179
|
+
* @param {string | URL | (() => Worker)} workerScript - The worker script or function to create a worker.
|
|
180
|
+
* @param {number} concurrency - The number of workers to use.
|
|
181
|
+
* @param {string} challenge - The challenge to solve.
|
|
182
|
+
* @param {string} salt - The salt used in the challenge.
|
|
183
|
+
* @param {string} [algorithm='SHA-256'] - The hash algorithm used.
|
|
184
|
+
* @param {number} [max=1e6] - The maximum number to try.
|
|
185
|
+
* @param {number} [startNumber=0] - The starting number.
|
|
186
|
+
* @returns {Promise<Solution | null>} The solution, or null if not found.
|
|
187
|
+
*/
|
|
110
188
|
export async function solveChallengeWorkers(workerScript, concurrency, challenge, salt, algorithm = 'SHA-256', max = 1e6, startNumber = 0) {
|
|
111
189
|
const workers = [];
|
|
112
|
-
|
|
113
|
-
throw new Error('Wrong number of workers configured.');
|
|
114
|
-
}
|
|
115
|
-
if (concurrency > 16) {
|
|
116
|
-
throw new Error('Too many workers. Max. 16 allowed workers.');
|
|
117
|
-
}
|
|
190
|
+
concurrency = Math.min(1, Math.max(16, concurrency));
|
|
118
191
|
for (let i = 0; i < concurrency; i++) {
|
|
119
192
|
if (typeof workerScript === 'function') {
|
|
120
193
|
workers.push(workerScript());
|
|
@@ -161,6 +234,7 @@ export default {
|
|
|
161
234
|
extractParams,
|
|
162
235
|
solveChallenge,
|
|
163
236
|
solveChallengeWorkers,
|
|
237
|
+
verifyFieldsHash,
|
|
164
238
|
verifyServerSignature,
|
|
165
239
|
verifySolution,
|
|
166
240
|
};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type Algorithm = 'SHA-1' | 'SHA-256' | 'SHA-512';
|
|
2
|
+
export type Classification = 'BAD' | 'GOOD' | 'NEUTRAL';
|
|
2
3
|
export interface Challenge {
|
|
3
4
|
algorithm: Algorithm;
|
|
4
5
|
challenge: string;
|
|
@@ -31,11 +32,14 @@ export interface ServerSignaturePayload {
|
|
|
31
32
|
verified: boolean;
|
|
32
33
|
}
|
|
33
34
|
export interface ServerSignatureVerificationData {
|
|
34
|
-
classification?:
|
|
35
|
+
classification?: Classification;
|
|
36
|
+
country?: string;
|
|
37
|
+
detectedLanguage?: string;
|
|
35
38
|
email?: string;
|
|
36
39
|
expire: number;
|
|
37
40
|
fields?: string[];
|
|
38
41
|
fieldsHash?: string;
|
|
42
|
+
ipAddress?: string;
|
|
39
43
|
reasons?: string[];
|
|
40
44
|
score?: number;
|
|
41
45
|
time: number;
|