@prosopo/datasets 3.1.54 → 3.1.55
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/.turbo/turbo-build$colon$cjs.log +15 -13
- package/.turbo/turbo-build$colon$tsc.log +11 -11
- package/.turbo/turbo-build.log +17 -14
- package/CHANGELOG.md +14 -0
- package/dist/_virtual/_rolldown/runtime.js +3 -0
- package/dist/captcha/captcha.js +171 -168
- package/dist/captcha/dataset.js +64 -82
- package/dist/captcha/index.js +2 -24
- package/dist/captcha/merkle.js +93 -123
- package/dist/captcha/util.js +14 -20
- package/dist/cjs/captcha/captcha.cjs +173 -158
- package/dist/cjs/captcha/dataset.cjs +64 -79
- package/dist/cjs/captcha/index.cjs +25 -27
- package/dist/cjs/captcha/merkle.cjs +95 -124
- package/dist/cjs/captcha/util.cjs +14 -20
- package/dist/cjs/index.cjs +28 -30
- package/dist/cjs/tests/mocks/data/captchas.cjs +1026 -1040
- package/dist/index.js +4 -28
- package/dist/tests/mocks/data/captchas.js +1027 -1042
- package/package.json +9 -9
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/datasets@3.1.
|
|
2
|
+
> @prosopo/datasets@3.1.55 build:cjs
|
|
3
3
|
> NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
|
|
4
4
|
|
|
5
5
|
ViteCommonJSConfig: .
|
|
@@ -23,20 +23,22 @@ ViteCommonJSConfig: .
|
|
|
23
23
|
'@prosopo/util-crypto'
|
|
24
24
|
]
|
|
25
25
|
}
|
|
26
|
-
[
|
|
26
|
+
[33mThe plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the [1mresolve.tsconfigPaths[22m option. You can remove the plugin and set [1mresolve.tsconfigPaths: true[22m in your Vite config instead.[39m
|
|
27
|
+
[36mvite v8.1.5 [32mbuilding ssr environment for production...[36m[39m
|
|
27
28
|
Bundle build started
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
[32m✓[39m 7 modules transformed.
|
|
29
|
+
[2K
|
|
30
|
+
✓ 8 modules transformed.
|
|
31
31
|
rendering chunks...
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
computing gzip size...
|
|
33
|
+
dist/cjs/captcha/util.cjs 0.59 kB │ gzip: 0.36 kB
|
|
34
|
+
dist/cjs/captcha/index.cjs 1.58 kB │ gzip: 0.40 kB
|
|
35
|
+
dist/cjs/index.cjs 1.92 kB │ gzip: 0.49 kB
|
|
36
|
+
dist/cjs/captcha/dataset.cjs 3.22 kB │ gzip: 1.03 kB
|
|
37
|
+
dist/cjs/captcha/merkle.cjs 3.44 kB │ gzip: 1.10 kB
|
|
38
|
+
dist/cjs/captcha/captcha.cjs 7.89 kB │ gzip: 2.27 kB
|
|
39
|
+
dist/cjs/tests/mocks/data/captchas.cjs 41.00 kB │ gzip: 5.46 kB
|
|
40
|
+
|
|
41
|
+
[32m✓ built in 74ms[39m
|
|
40
42
|
[copy-plugin] copying /home/runner/work/captcha/captcha/packages/datasets/src/tests/mocks/data/captchas.json to /home/runner/work/captcha/captcha/packages/datasets/dist/tests/mocks/data/captchas.json
|
|
41
43
|
[copy-plugin] copying /home/runner/work/captcha/captcha/packages/datasets/src/tests/mocks/data/captchas1.json to /home/runner/work/captcha/captcha/packages/datasets/dist/tests/mocks/data/captchas1.json
|
|
42
44
|
[copy-plugin] copying /home/runner/work/captcha/captcha/packages/datasets/src/tests/mocks/data/captchas2.json to /home/runner/work/captcha/captcha/packages/datasets/dist/tests/mocks/data/captchas2.json
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/datasets@3.1.
|
|
2
|
+
> @prosopo/datasets@3.1.55 build:tsc
|
|
3
3
|
> tsc --build --verbose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
8:59:11 PM - Projects in this build:
|
|
6
6
|
* ../../dev/config/tsconfig.json
|
|
7
7
|
* ../locale/tsconfig.json
|
|
8
8
|
* ../util/tsconfig.json
|
|
@@ -12,21 +12,21 @@
|
|
|
12
12
|
* ../common/tsconfig.json
|
|
13
13
|
* tsconfig.json
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
8:59:11 PM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
8:59:11 PM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
8:59:11 PM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
8:59:11 PM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
8:59:11 PM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
8:59:11 PM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/provider/api.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
8:59:11 PM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/tests/utils/batches.unit.test.ts' is older than output '../common/tsconfig.tsbuildinfo'
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
8:59:11 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
8:59:11 PM - Building project '/home/runner/work/captcha/captcha/packages/datasets/tsconfig.json'...
|
|
32
32
|
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/datasets@3.1.
|
|
2
|
+
> @prosopo/datasets@3.1.55 build
|
|
3
3
|
> npm run build:cross-env -- --mode ${NODE_ENV:-development}
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @prosopo/datasets@3.1.
|
|
6
|
+
> @prosopo/datasets@3.1.55 build:cross-env
|
|
7
7
|
> vite build --config vite.esm.config.ts --mode production
|
|
8
8
|
|
|
9
9
|
ViteEsmConfig: .
|
|
@@ -27,20 +27,23 @@ ViteEsmConfig: .
|
|
|
27
27
|
'@prosopo/util-crypto'
|
|
28
28
|
]
|
|
29
29
|
}
|
|
30
|
-
[
|
|
30
|
+
[33mThe plugin "vite-tsconfig-paths" is detected. Vite now supports tsconfig paths resolution natively via the [1mresolve.tsconfigPaths[22m option. You can remove the plugin and set [1mresolve.tsconfigPaths: true[22m in your Vite config instead.[39m
|
|
31
|
+
[36mvite v8.1.5 [32mbuilding ssr environment for production...[36m[39m
|
|
31
32
|
Bundle build started
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
[32m✓[39m 7 modules transformed.
|
|
33
|
+
[2K
|
|
34
|
+
✓ 8 modules transformed.
|
|
35
35
|
rendering chunks...
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
computing gzip size...
|
|
37
|
+
dist/_virtual/_rolldown/runtime.js 0.04 kB │ gzip: 0.06 kB
|
|
38
|
+
dist/captcha/util.js 0.57 kB │ gzip: 0.36 kB
|
|
39
|
+
dist/captcha/index.js 1.00 kB │ gzip: 0.31 kB
|
|
40
|
+
dist/index.js 1.23 kB │ gzip: 0.37 kB
|
|
41
|
+
dist/captcha/dataset.js 2.99 kB │ gzip: 0.98 kB
|
|
42
|
+
dist/captcha/merkle.js 3.07 kB │ gzip: 1.06 kB
|
|
43
|
+
dist/captcha/captcha.js 7.19 kB │ gzip: 2.19 kB
|
|
44
|
+
dist/tests/mocks/data/captchas.js 40.94 kB │ gzip: 5.44 kB
|
|
45
|
+
|
|
46
|
+
[32m✓ built in 99ms[39m
|
|
44
47
|
[copy-plugin] copying /home/runner/work/captcha/captcha/packages/datasets/src/tests/mocks/data/captchas.json to /home/runner/work/captcha/captcha/packages/datasets/dist/tests/mocks/data/captchas.json
|
|
45
48
|
[copy-plugin] copying /home/runner/work/captcha/captcha/packages/datasets/src/tests/mocks/data/captchas1.json to /home/runner/work/captcha/captcha/packages/datasets/dist/tests/mocks/data/captchas1.json
|
|
46
49
|
[copy-plugin] copying /home/runner/work/captcha/captcha/packages/datasets/src/tests/mocks/data/captchas2.json to /home/runner/work/captcha/captcha/packages/datasets/dist/tests/mocks/data/captchas2.json
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @prosopo/datasets
|
|
2
2
|
|
|
3
|
+
## 3.1.55
|
|
4
|
+
### Patch Changes
|
|
5
|
+
|
|
6
|
+
- e14fce6: chore(deps): bump vite to 6.4.3 and mongoose to 8.24.1, and adjust types for the mongoose 8.24 Document/ObjectId changes
|
|
7
|
+
- Updated dependencies [2c47bb7]
|
|
8
|
+
- Updated dependencies [0e1171c]
|
|
9
|
+
- Updated dependencies [103318c]
|
|
10
|
+
- Updated dependencies [270a8d8]
|
|
11
|
+
- Updated dependencies [e14fce6]
|
|
12
|
+
- @prosopo/util@3.3.5
|
|
13
|
+
- @prosopo/types@4.10.0
|
|
14
|
+
- @prosopo/common@3.1.48
|
|
15
|
+
- @prosopo/logger@2.0.4
|
|
16
|
+
|
|
3
17
|
## 3.1.54
|
|
4
18
|
### Patch Changes
|
|
5
19
|
|
package/dist/captcha/captcha.js
CHANGED
|
@@ -1,195 +1,198 @@
|
|
|
1
|
+
import { downloadImage } from "./util.js";
|
|
1
2
|
import { isHex } from "@polkadot/util";
|
|
2
3
|
import { ProsopoDatasetError, ProsopoEnvError } from "@prosopo/common";
|
|
3
|
-
import {
|
|
4
|
+
import { CaptchaSolutionArraySchema, DatasetWithNumericSolutionSchema } from "@prosopo/types";
|
|
4
5
|
import { at } from "@prosopo/util";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import { hexHash, hexHashArray } from "@prosopo/util-crypto";
|
|
7
|
+
//#region src/captcha/captcha.ts
|
|
8
|
+
var NO_SOLUTION_VALUE = "NO_SOLUTION";
|
|
9
|
+
/**
|
|
10
|
+
* Parse a dataset
|
|
11
|
+
* @return {JSON} captcha dataset, stored in JSON
|
|
12
|
+
* @param datasetJSON
|
|
13
|
+
*/
|
|
8
14
|
function parseCaptchaDataset(datasetJSON) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
} catch (err) {
|
|
30
|
-
throw new ProsopoDatasetError("DATASET.DATASET_PARSE_ERROR", {
|
|
31
|
-
context: { error: err }
|
|
32
|
-
});
|
|
33
|
-
}
|
|
15
|
+
try {
|
|
16
|
+
const result = DatasetWithNumericSolutionSchema.parse(datasetJSON);
|
|
17
|
+
const result2 = {
|
|
18
|
+
format: result.format,
|
|
19
|
+
captchas: result.captchas.map((captcha) => {
|
|
20
|
+
return {
|
|
21
|
+
...captcha,
|
|
22
|
+
solution: captcha.solution ? matchItemsToSolutions(captcha.solution, captcha.items) : [],
|
|
23
|
+
unlabelled: captcha.unlabelled ? matchItemsToSolutions(captcha.unlabelled, captcha.items) : []
|
|
24
|
+
};
|
|
25
|
+
})
|
|
26
|
+
};
|
|
27
|
+
if (result.datasetId !== void 0) result2.datasetId = result.datasetId;
|
|
28
|
+
if (result.contentTree !== void 0) result2.contentTree = result.contentTree;
|
|
29
|
+
if (result.datasetContentId !== void 0) result2.datasetContentId = result.datasetContentId;
|
|
30
|
+
if (result.solutionTree !== void 0) result2.solutionTree = result.solutionTree;
|
|
31
|
+
return result2;
|
|
32
|
+
} catch (err) {
|
|
33
|
+
throw new ProsopoDatasetError("DATASET.DATASET_PARSE_ERROR", { context: { error: err } });
|
|
34
|
+
}
|
|
34
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Make sure captcha solutions are in the correct format
|
|
38
|
+
* @param {JSON} captchaJSON captcha solutions received from the api
|
|
39
|
+
* @return {CaptchaSolution[]} an array of parsed and sorted captcha solutions
|
|
40
|
+
*/
|
|
35
41
|
function parseAndSortCaptchaSolutions(captchaJSON) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
});
|
|
45
|
-
}
|
|
42
|
+
try {
|
|
43
|
+
return CaptchaSolutionArraySchema.parse(captchaJSON).map((captcha) => ({
|
|
44
|
+
...captcha,
|
|
45
|
+
solution: captcha.solution.sort()
|
|
46
|
+
}));
|
|
47
|
+
} catch (err) {
|
|
48
|
+
throw new ProsopoDatasetError("DATASET.SOLUTION_PARSE_ERROR", { context: { error: err } });
|
|
49
|
+
}
|
|
46
50
|
}
|
|
47
51
|
function captchaSort(a, b) {
|
|
48
|
-
|
|
52
|
+
return a.captchaId.localeCompare(b.captchaId);
|
|
49
53
|
}
|
|
50
54
|
function sortAndComputeHashes(received, stored) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
},
|
|
67
|
-
true,
|
|
68
|
-
true,
|
|
69
|
-
false
|
|
70
|
-
),
|
|
71
|
-
captchaId
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
);
|
|
55
|
+
received.sort(captchaSort);
|
|
56
|
+
stored.sort(captchaSort);
|
|
57
|
+
return stored.map(({ salt, items = [], target = "", captchaId, solved }, index) => {
|
|
58
|
+
const item = at(received, index);
|
|
59
|
+
if (captchaId !== item.captchaId) throw new ProsopoEnvError("CAPTCHA.ID_MISMATCH");
|
|
60
|
+
return {
|
|
61
|
+
hash: computeCaptchaHash({
|
|
62
|
+
solution: solved ? item.solution : [],
|
|
63
|
+
salt,
|
|
64
|
+
items,
|
|
65
|
+
target
|
|
66
|
+
}, true, true, false),
|
|
67
|
+
captchaId
|
|
68
|
+
};
|
|
69
|
+
});
|
|
75
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Take an array of CaptchaSolutions and Captchas and check if the solutions are the same for each pair
|
|
73
|
+
* @param {CaptchaSolution[]} received
|
|
74
|
+
* @param solutions
|
|
75
|
+
* @param totalImages
|
|
76
|
+
* @param {number} threshold the percentage of captchas that must be correct to return true
|
|
77
|
+
* @return {boolean}
|
|
78
|
+
*/
|
|
76
79
|
function compareCaptchaSolutions(received, solutions, totalImages, threshold) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
return received.every((captcha, index) => {
|
|
91
|
-
const sortedReceivedSolution = captcha.solution.sort();
|
|
92
|
-
const targetSolution = solutions[index]?.solution.sort();
|
|
93
|
-
if (!targetSolution) {
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
const incorrectCount = sortedReceivedSolution.filter(
|
|
97
|
-
(solution) => !targetSolution.includes(solution)
|
|
98
|
-
).length;
|
|
99
|
-
const missingCount = targetSolution.filter(
|
|
100
|
-
(solution) => !sortedReceivedSolution.includes(solution)
|
|
101
|
-
).length;
|
|
102
|
-
const totalIncorrect = incorrectCount + missingCount;
|
|
103
|
-
const percentageCorrect = 1 - totalIncorrect / totalImages;
|
|
104
|
-
return percentageCorrect >= threshold;
|
|
105
|
-
});
|
|
80
|
+
received.sort(captchaSort);
|
|
81
|
+
solutions.sort(captchaSort);
|
|
82
|
+
if (received.length !== solutions.length) return false;
|
|
83
|
+
if (received.length && solutions.length && received.length === solutions.length) {
|
|
84
|
+
if (received.some((captcha, index) => solutions[index] && captcha.captchaId !== solutions[index].captchaId)) return false;
|
|
85
|
+
}
|
|
86
|
+
return received.every((captcha, index) => {
|
|
87
|
+
const sortedReceivedSolution = captcha.solution.sort();
|
|
88
|
+
const targetSolution = solutions[index]?.solution.sort();
|
|
89
|
+
if (!targetSolution) return false;
|
|
90
|
+
return 1 - (sortedReceivedSolution.filter((solution) => !targetSolution.includes(solution)).length + targetSolution.filter((solution) => !sortedReceivedSolution.includes(solution)).length) / totalImages >= threshold;
|
|
91
|
+
});
|
|
106
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Compute the hash of various types of captcha
|
|
95
|
+
* @param {Captcha} captcha
|
|
96
|
+
* @param {boolean} includeSolution
|
|
97
|
+
* @param {boolean} includeSalt
|
|
98
|
+
* @param {boolean} sortItemHashes
|
|
99
|
+
* @return {string} the hex string hash
|
|
100
|
+
*/
|
|
107
101
|
function computeCaptchaHash(captcha, includeSolution, includeSalt, sortItemHashes) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
includeSalt ? captcha.salt : "",
|
|
126
|
-
sortItemHashes ? itemHashes.sort() : itemHashes
|
|
127
|
-
]);
|
|
128
|
-
} catch (err) {
|
|
129
|
-
throw new ProsopoDatasetError("DATASET.HASH_ERROR", {
|
|
130
|
-
context: { error: err }
|
|
131
|
-
});
|
|
132
|
-
}
|
|
102
|
+
try {
|
|
103
|
+
const itemHashes = captcha.items.map((item, index) => {
|
|
104
|
+
if (item.hash) return item.hash;
|
|
105
|
+
throw new ProsopoDatasetError("CAPTCHA.MISSING_ITEM_HASH", { context: {
|
|
106
|
+
computeCaptchaHashName: computeCaptchaHash.name,
|
|
107
|
+
index
|
|
108
|
+
} });
|
|
109
|
+
});
|
|
110
|
+
return hexHashArray([
|
|
111
|
+
captcha.target,
|
|
112
|
+
...includeSolution ? getSolutionValueToHash(captcha.solution) : [],
|
|
113
|
+
includeSalt ? captcha.salt : "",
|
|
114
|
+
sortItemHashes ? itemHashes.sort() : itemHashes
|
|
115
|
+
]);
|
|
116
|
+
} catch (err) {
|
|
117
|
+
throw new ProsopoDatasetError("DATASET.HASH_ERROR", { context: { error: err } });
|
|
118
|
+
}
|
|
133
119
|
}
|
|
120
|
+
/** Return the sorted solution value or ['NO_SOLUTION'] if there is no solution. Ensures that an empty array is a valid
|
|
121
|
+
* solution
|
|
122
|
+
* @param solution
|
|
123
|
+
*/
|
|
134
124
|
function getSolutionValueToHash(solution) {
|
|
135
|
-
|
|
125
|
+
return solution !== void 0 ? solution.sort() : [NO_SOLUTION_VALUE];
|
|
136
126
|
}
|
|
127
|
+
/** Compute the hash of a captcha item, downloading the image if necessary
|
|
128
|
+
* @param {Item} item
|
|
129
|
+
* @return {Promise<HashedItem>} the hex string hash of the item
|
|
130
|
+
*/
|
|
137
131
|
async function computeItemHash(item) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
132
|
+
if (item.type === "text") return {
|
|
133
|
+
...item,
|
|
134
|
+
hash: hexHash(item.data)
|
|
135
|
+
};
|
|
136
|
+
if (item.type === "image") return {
|
|
137
|
+
...item,
|
|
138
|
+
hash: hexHash(await downloadImage(item.data))
|
|
139
|
+
};
|
|
140
|
+
throw new ProsopoDatasetError("CAPTCHA.INVALID_ITEM_FORMAT");
|
|
145
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* Converts an indexed captcha solution to a hashed captcha solution or simply returns the hash if it is already hashed
|
|
144
|
+
* @return {HashedSolution[]}
|
|
145
|
+
* @param {RawSolution[] | HashedSolution[]} solutions
|
|
146
|
+
* @param {Item[]} items
|
|
147
|
+
*/
|
|
146
148
|
function matchItemsToSolutions(solutions, items) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
if (typeof solution === "number") {
|
|
158
|
-
const item = at(items, solution);
|
|
159
|
-
return item.hash;
|
|
160
|
-
}
|
|
161
|
-
throw new ProsopoDatasetError("CAPTCHA.INVALID_SOLUTION_TYPE");
|
|
162
|
-
});
|
|
149
|
+
if (!items) return [];
|
|
150
|
+
return solutions.map((solution) => {
|
|
151
|
+
if (typeof solution === "string" && isHex(solution)) {
|
|
152
|
+
if (!items?.some((item) => item.hash === solution)) throw new ProsopoDatasetError("CAPTCHA.INVALID_ITEM_HASH");
|
|
153
|
+
return solution;
|
|
154
|
+
}
|
|
155
|
+
if (typeof solution === "number") return at(items, solution).hash;
|
|
156
|
+
throw new ProsopoDatasetError("CAPTCHA.INVALID_SOLUTION_TYPE");
|
|
157
|
+
});
|
|
163
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Create a unique solution commitment
|
|
161
|
+
* @param {CaptchaSolution} captcha
|
|
162
|
+
* @return {string} the hex string hash
|
|
163
|
+
*/
|
|
164
164
|
function computeCaptchaSolutionHash(captcha) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
165
|
+
return hexHashArray([
|
|
166
|
+
captcha.captchaId,
|
|
167
|
+
captcha.captchaContentId,
|
|
168
|
+
[...captcha.solution].sort(),
|
|
169
|
+
captcha.salt
|
|
170
|
+
]);
|
|
171
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Compute hash for an array of captcha ids, userAccount, and salt, which serves as the identifier for a pending request
|
|
174
|
+
* @param {string[]} captchaIds
|
|
175
|
+
* @param {string} userAccount
|
|
176
|
+
* @param {string} salt
|
|
177
|
+
* @return {string}
|
|
178
|
+
*/
|
|
172
179
|
function computePendingRequestHash(captchaIds, userAccount, salt) {
|
|
173
|
-
|
|
180
|
+
return hexHashArray([
|
|
181
|
+
...captchaIds.sort(),
|
|
182
|
+
userAccount,
|
|
183
|
+
salt
|
|
184
|
+
]);
|
|
174
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* Parse the image items in a captcha and pass back a URI if they exist
|
|
188
|
+
* @param {Item} item
|
|
189
|
+
* @param {AssetsResolver} assetsResolver
|
|
190
|
+
*/
|
|
175
191
|
function parseCaptchaAssets(item, assetsResolver) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
192
|
+
return {
|
|
193
|
+
...item,
|
|
194
|
+
data: assetsResolver?.resolveAsset(item.data).getURL() || item.data
|
|
195
|
+
};
|
|
180
196
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
captchaSort,
|
|
184
|
-
compareCaptchaSolutions,
|
|
185
|
-
computeCaptchaHash,
|
|
186
|
-
computeCaptchaSolutionHash,
|
|
187
|
-
computeItemHash,
|
|
188
|
-
computePendingRequestHash,
|
|
189
|
-
getSolutionValueToHash,
|
|
190
|
-
matchItemsToSolutions,
|
|
191
|
-
parseAndSortCaptchaSolutions,
|
|
192
|
-
parseCaptchaAssets,
|
|
193
|
-
parseCaptchaDataset,
|
|
194
|
-
sortAndComputeHashes
|
|
195
|
-
};
|
|
197
|
+
//#endregion
|
|
198
|
+
export { NO_SOLUTION_VALUE, captchaSort, compareCaptchaSolutions, computeCaptchaHash, computeCaptchaSolutionHash, computeItemHash, computePendingRequestHash, getSolutionValueToHash, matchItemsToSolutions, parseAndSortCaptchaSolutions, parseCaptchaAssets, parseCaptchaDataset, sortAndComputeHashes };
|