@prosopo/datasets 3.0.42 → 3.0.43

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.
Files changed (72) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/captcha/captcha.js +173 -154
  3. package/dist/captcha/dataset.js +83 -69
  4. package/dist/captcha/index.js +27 -5
  5. package/dist/captcha/merkle.js +112 -109
  6. package/dist/captcha/util.js +19 -18
  7. package/dist/cjs/captcha/captcha.cjs +195 -0
  8. package/dist/cjs/captcha/dataset.cjs +94 -0
  9. package/dist/cjs/captcha/index.cjs +27 -0
  10. package/dist/cjs/captcha/merkle.cjs +128 -0
  11. package/dist/cjs/captcha/util.cjs +23 -0
  12. package/dist/cjs/index.cjs +31 -0
  13. package/dist/cjs/tests/mocks/data/captchas.cjs +1044 -0
  14. package/dist/index.js +31 -3
  15. package/dist/tests/mocks/data/captchas.js +1039 -1033
  16. package/dist/tests/mocks/data/captchas.json +886 -886
  17. package/dist/tests/mocks/data/captchas1.json +132 -132
  18. package/dist/tests/mocks/data/captchas2.json +175 -175
  19. package/dist/tests/mocks/data/captchas3.json +133 -133
  20. package/dist/tests/mocks/data/captchas4.json +132 -132
  21. package/package.json +7 -7
  22. package/coverage/base.css +0 -224
  23. package/coverage/block-navigation.js +0 -87
  24. package/coverage/clover.xml +0 -493
  25. package/coverage/coverage-final.json +0 -7
  26. package/coverage/favicon.png +0 -0
  27. package/coverage/index.html +0 -131
  28. package/coverage/prettify.css +0 -1
  29. package/coverage/prettify.js +0 -2
  30. package/coverage/sort-arrow-sprite.png +0 -0
  31. package/coverage/sorter.js +0 -210
  32. package/coverage/src/captcha/captcha.ts.html +0 -1093
  33. package/coverage/src/captcha/dataset.ts.html +0 -490
  34. package/coverage/src/captcha/index.html +0 -176
  35. package/coverage/src/captcha/index.ts.html +0 -136
  36. package/coverage/src/captcha/merkle.ts.html +0 -610
  37. package/coverage/src/captcha/util.ts.html +0 -187
  38. package/coverage/src/index.html +0 -116
  39. package/coverage/src/index.ts.html +0 -139
  40. package/dist/captcha/captcha.d.ts +0 -21
  41. package/dist/captcha/captcha.d.ts.map +0 -1
  42. package/dist/captcha/captcha.js.map +0 -1
  43. package/dist/captcha/dataset.d.ts +0 -8
  44. package/dist/captcha/dataset.d.ts.map +0 -1
  45. package/dist/captcha/dataset.js.map +0 -1
  46. package/dist/captcha/index.d.ts +0 -5
  47. package/dist/captcha/index.d.ts.map +0 -1
  48. package/dist/captcha/index.js.map +0 -1
  49. package/dist/captcha/merkle.d.ts +0 -20
  50. package/dist/captcha/merkle.d.ts.map +0 -1
  51. package/dist/captcha/merkle.js.map +0 -1
  52. package/dist/captcha/util.d.ts +0 -2
  53. package/dist/captcha/util.d.ts.map +0 -1
  54. package/dist/captcha/util.js.map +0 -1
  55. package/dist/index.d.ts +0 -3
  56. package/dist/index.d.ts.map +0 -1
  57. package/dist/index.js.map +0 -1
  58. package/dist/tests/captcha.unit.test.d.ts +0 -2
  59. package/dist/tests/captcha.unit.test.d.ts.map +0 -1
  60. package/dist/tests/captcha.unit.test.js +0 -357
  61. package/dist/tests/captcha.unit.test.js.map +0 -1
  62. package/dist/tests/dataset.unit.test.d.ts +0 -2
  63. package/dist/tests/dataset.unit.test.d.ts.map +0 -1
  64. package/dist/tests/dataset.unit.test.js +0 -126
  65. package/dist/tests/dataset.unit.test.js.map +0 -1
  66. package/dist/tests/merkle.unit.test.d.ts +0 -2
  67. package/dist/tests/merkle.unit.test.d.ts.map +0 -1
  68. package/dist/tests/merkle.unit.test.js +0 -171
  69. package/dist/tests/merkle.unit.test.js.map +0 -1
  70. package/dist/tests/mocks/data/captchas.d.ts +0 -24
  71. package/dist/tests/mocks/data/captchas.d.ts.map +0 -1
  72. package/dist/tests/mocks/data/captchas.js.map +0 -1
@@ -2,124 +2,127 @@ import { ProsopoError } from "@prosopo/common";
2
2
  import { at } from "@prosopo/util";
3
3
  import { hexHashArray } from "@prosopo/util-crypto";
4
4
  class MerkleNode {
5
- constructor(hash) {
6
- this.hash = hash;
7
- this.parent = null;
8
- }
5
+ constructor(hash) {
6
+ this.hash = hash;
7
+ this.parent = null;
8
+ }
9
9
  }
10
- export class CaptchaMerkleTree {
11
- constructor() {
12
- this.leaves = [];
13
- this.layers = [];
14
- }
15
- getRoot() {
16
- if (this.root === undefined) {
17
- throw new ProsopoError("DATASET.MERKLE_ERROR", {
18
- context: {
19
- error: "root undefined",
20
- failedFuncName: this.getRoot.name,
21
- },
22
- });
10
+ class CaptchaMerkleTree {
11
+ constructor() {
12
+ this.leaves = [];
13
+ this.layers = [];
14
+ }
15
+ getRoot() {
16
+ if (this.root === void 0) {
17
+ throw new ProsopoError("DATASET.MERKLE_ERROR", {
18
+ context: {
19
+ error: "root undefined",
20
+ failedFuncName: this.getRoot.name
23
21
  }
24
- return this.root;
22
+ });
25
23
  }
26
- build(leaves) {
27
- if (this.layers.length) {
28
- this.layers = [];
29
- }
30
- const layerZero = [];
31
- for (const leaf of leaves) {
32
- const node = new MerkleNode(leaf);
33
- this.leaves.push(node);
34
- layerZero.push(node.hash);
35
- }
36
- this.layers.push(layerZero);
37
- this.root = this.buildMerkleTree(this.leaves)[0];
24
+ return this.root;
25
+ }
26
+ build(leaves) {
27
+ if (this.layers.length) {
28
+ this.layers = [];
38
29
  }
39
- buildMerkleTree(leaves) {
40
- const numLeaves = leaves.length;
41
- if (numLeaves === 1) {
42
- return leaves;
43
- }
44
- const parents = [];
45
- let leafIndex = 0;
46
- const newLayer = [];
47
- while (leafIndex < numLeaves) {
48
- const leftChild = leaves[leafIndex];
49
- if (leftChild === undefined) {
50
- throw new ProsopoError("DEVELOPER.GENERAL", {
51
- context: { error: "leftChild undefined" },
52
- });
53
- }
54
- const rightChild = leafIndex + 1 < numLeaves ? at(leaves, leafIndex + 1) : leftChild;
55
- const parentNode = this.createParent(leftChild, rightChild);
56
- newLayer.push(parentNode.hash);
57
- parents.push(parentNode);
58
- leafIndex += 2;
59
- }
60
- this.layers.push(newLayer);
61
- return this.buildMerkleTree(parents);
30
+ const layerZero = [];
31
+ for (const leaf of leaves) {
32
+ const node = new MerkleNode(leaf);
33
+ this.leaves.push(node);
34
+ layerZero.push(node.hash);
62
35
  }
63
- createParent(leftChild, rightChild) {
64
- const parent = new MerkleNode(hexHashArray([leftChild.hash, rightChild.hash]));
65
- leftChild.parent = parent.hash;
66
- rightChild.parent = parent.hash;
67
- return parent;
36
+ this.layers.push(layerZero);
37
+ this.root = this.buildMerkleTree(this.leaves)[0];
38
+ }
39
+ buildMerkleTree(leaves) {
40
+ const numLeaves = leaves.length;
41
+ if (numLeaves === 1) {
42
+ return leaves;
68
43
  }
69
- proof(leafHash) {
70
- const proofTree = [];
71
- let layerNum = 0;
72
- while (layerNum < this.layers.length - 1) {
73
- const layer = this.layers[layerNum];
74
- if (layer === undefined) {
75
- throw new ProsopoError("DATASET.MERKLE_ERROR", {
76
- context: {
77
- error: "layer undefined",
78
- failedFuncName: this.proof.name,
79
- layerNum,
80
- },
81
- });
82
- }
83
- const leafIndex = layer.indexOf(leafHash);
84
- let partnerIndex = leafIndex % 2 && leafIndex > 0 ? leafIndex - 1 : leafIndex + 1;
85
- if (partnerIndex > layer.length - 1) {
86
- partnerIndex = leafIndex;
87
- }
88
- const pair = [leafHash];
89
- const partner = at(layer, partnerIndex);
90
- if (partnerIndex > leafIndex) {
91
- pair.push(partner);
92
- }
93
- else {
94
- pair.unshift(partner);
95
- }
96
- proofTree.push([at(pair, 0), at(pair, 1)]);
97
- layerNum += 1;
98
- leafHash = hexHashArray(pair);
99
- }
100
- const last = at(this.layers, this.layers.length - 1);
101
- return [...proofTree, [at(last, 0)]];
44
+ const parents = [];
45
+ let leafIndex = 0;
46
+ const newLayer = [];
47
+ while (leafIndex < numLeaves) {
48
+ const leftChild = leaves[leafIndex];
49
+ if (leftChild === void 0) {
50
+ throw new ProsopoError("DEVELOPER.GENERAL", {
51
+ context: { error: "leftChild undefined" }
52
+ });
53
+ }
54
+ const rightChild = leafIndex + 1 < numLeaves ? at(leaves, leafIndex + 1) : leftChild;
55
+ const parentNode = this.createParent(leftChild, rightChild);
56
+ newLayer.push(parentNode.hash);
57
+ parents.push(parentNode);
58
+ leafIndex += 2;
59
+ }
60
+ this.layers.push(newLayer);
61
+ return this.buildMerkleTree(parents);
62
+ }
63
+ createParent(leftChild, rightChild) {
64
+ const parent = new MerkleNode(
65
+ hexHashArray([leftChild.hash, rightChild.hash])
66
+ );
67
+ leftChild.parent = parent.hash;
68
+ rightChild.parent = parent.hash;
69
+ return parent;
70
+ }
71
+ proof(leafHash) {
72
+ const proofTree = [];
73
+ let layerNum = 0;
74
+ while (layerNum < this.layers.length - 1) {
75
+ const layer = this.layers[layerNum];
76
+ if (layer === void 0) {
77
+ throw new ProsopoError("DATASET.MERKLE_ERROR", {
78
+ context: {
79
+ error: "layer undefined",
80
+ failedFuncName: this.proof.name,
81
+ layerNum
82
+ }
83
+ });
84
+ }
85
+ const leafIndex = layer.indexOf(leafHash);
86
+ let partnerIndex = leafIndex % 2 && leafIndex > 0 ? leafIndex - 1 : leafIndex + 1;
87
+ if (partnerIndex > layer.length - 1) {
88
+ partnerIndex = leafIndex;
89
+ }
90
+ const pair = [leafHash];
91
+ const partner = at(layer, partnerIndex);
92
+ if (partnerIndex > leafIndex) {
93
+ pair.push(partner);
94
+ } else {
95
+ pair.unshift(partner);
96
+ }
97
+ proofTree.push([at(pair, 0), at(pair, 1)]);
98
+ layerNum += 1;
99
+ leafHash = hexHashArray(pair);
102
100
  }
101
+ const last = at(this.layers, this.layers.length - 1);
102
+ return [...proofTree, [at(last, 0)]];
103
+ }
103
104
  }
104
- export function verifyProof(leaf, proof) {
105
- try {
106
- if (at(proof, 0).indexOf(leaf) === -1) {
107
- return false;
108
- }
109
- for (const [layerIndex, layer] of proof.entries()) {
110
- leaf = hexHashArray(layer);
111
- if (at(proof, layerIndex + 1).indexOf(leaf) === -1) {
112
- return false;
113
- }
114
- const last = at(proof, proof.length - 1);
115
- if (leaf === at(last, 0)) {
116
- return true;
117
- }
118
- }
119
- return false;
105
+ function verifyProof(leaf, proof) {
106
+ try {
107
+ if (at(proof, 0).indexOf(leaf) === -1) {
108
+ return false;
120
109
  }
121
- catch (err) {
110
+ for (const [layerIndex, layer] of proof.entries()) {
111
+ leaf = hexHashArray(layer);
112
+ if (at(proof, layerIndex + 1).indexOf(leaf) === -1) {
122
113
  return false;
114
+ }
115
+ const last = at(proof, proof.length - 1);
116
+ if (leaf === at(last, 0)) {
117
+ return true;
118
+ }
123
119
  }
120
+ return false;
121
+ } catch (err) {
122
+ return false;
123
+ }
124
124
  }
125
- //# sourceMappingURL=merkle.js.map
125
+ export {
126
+ CaptchaMerkleTree,
127
+ verifyProof
128
+ };
@@ -1,22 +1,23 @@
1
1
  import { ProsopoDatasetError, ProsopoEnvError } from "@prosopo/common";
2
- export async function downloadImage(url) {
3
- try {
4
- const response = await fetch(url);
5
- if (!response.ok) {
6
- throw new ProsopoDatasetError("API.BAD_REQUEST", {
7
- context: {
8
- error: `Network response was not ok, status: ${response.status}`,
9
- url,
10
- },
11
- });
2
+ async function downloadImage(url) {
3
+ try {
4
+ const response = await fetch(url);
5
+ if (!response.ok) {
6
+ throw new ProsopoDatasetError("API.BAD_REQUEST", {
7
+ context: {
8
+ error: `Network response was not ok, status: ${response.status}`,
9
+ url
12
10
  }
13
- const buffer = await response.arrayBuffer();
14
- return new Uint8Array(buffer);
15
- }
16
- catch (err) {
17
- throw new ProsopoEnvError("DATABASE.IMAGE_GET_FAILED", {
18
- context: { error: err },
19
- });
11
+ });
20
12
  }
13
+ const buffer = await response.arrayBuffer();
14
+ return new Uint8Array(buffer);
15
+ } catch (err) {
16
+ throw new ProsopoEnvError("DATABASE.IMAGE_GET_FAILED", {
17
+ context: { error: err }
18
+ });
19
+ }
21
20
  }
22
- //# sourceMappingURL=util.js.map
21
+ export {
22
+ downloadImage
23
+ };
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const util$2 = require("@polkadot/util");
4
+ const common = require("@prosopo/common");
5
+ const types = require("@prosopo/types");
6
+ const util = require("@prosopo/util");
7
+ const utilCrypto = require("@prosopo/util-crypto");
8
+ const util$1 = require("./util.cjs");
9
+ const NO_SOLUTION_VALUE = "NO_SOLUTION";
10
+ function parseCaptchaDataset(datasetJSON) {
11
+ try {
12
+ const result = types.DatasetWithNumericSolutionSchema.parse(datasetJSON);
13
+ const result2 = {
14
+ format: result.format,
15
+ captchas: result.captchas.map((captcha) => {
16
+ return {
17
+ ...captcha,
18
+ solution: captcha.solution ? matchItemsToSolutions(captcha.solution, captcha.items) : [],
19
+ unlabelled: captcha.unlabelled ? matchItemsToSolutions(captcha.unlabelled, captcha.items) : []
20
+ };
21
+ })
22
+ };
23
+ if (result.datasetId !== void 0) result2.datasetId = result.datasetId;
24
+ if (result.contentTree !== void 0)
25
+ result2.contentTree = result.contentTree;
26
+ if (result.datasetContentId !== void 0)
27
+ result2.datasetContentId = result.datasetContentId;
28
+ if (result.solutionTree !== void 0)
29
+ result2.solutionTree = result.solutionTree;
30
+ return result2;
31
+ } catch (err) {
32
+ throw new common.ProsopoDatasetError("DATASET.DATASET_PARSE_ERROR", {
33
+ context: { error: err }
34
+ });
35
+ }
36
+ }
37
+ function parseAndSortCaptchaSolutions(captchaJSON) {
38
+ try {
39
+ return types.CaptchaSolutionArraySchema.parse(captchaJSON).map((captcha) => ({
40
+ ...captcha,
41
+ solution: captcha.solution.sort()
42
+ }));
43
+ } catch (err) {
44
+ throw new common.ProsopoDatasetError("DATASET.SOLUTION_PARSE_ERROR", {
45
+ context: { error: err }
46
+ });
47
+ }
48
+ }
49
+ function captchaSort(a, b) {
50
+ return a.captchaId.localeCompare(b.captchaId);
51
+ }
52
+ function sortAndComputeHashes(received, stored) {
53
+ received.sort(captchaSort);
54
+ stored.sort(captchaSort);
55
+ return stored.map(
56
+ ({ salt, items = [], target = "", captchaId, solved }, index) => {
57
+ const item = util.at(received, index);
58
+ if (captchaId !== item.captchaId) {
59
+ throw new common.ProsopoEnvError("CAPTCHA.ID_MISMATCH");
60
+ }
61
+ return {
62
+ hash: computeCaptchaHash(
63
+ {
64
+ solution: solved ? item.solution : [],
65
+ salt,
66
+ items,
67
+ target
68
+ },
69
+ true,
70
+ true,
71
+ false
72
+ ),
73
+ captchaId
74
+ };
75
+ }
76
+ );
77
+ }
78
+ function compareCaptchaSolutions(received, solutions, totalImages, threshold) {
79
+ received.sort(captchaSort);
80
+ solutions.sort(captchaSort);
81
+ if (received.length !== solutions.length) {
82
+ return false;
83
+ }
84
+ if (received.length && solutions.length && received.length === solutions.length) {
85
+ const captchaIdMismatch = received.some(
86
+ (captcha, index) => solutions[index] && captcha.captchaId !== solutions[index].captchaId
87
+ );
88
+ if (captchaIdMismatch) {
89
+ return false;
90
+ }
91
+ }
92
+ return received.every((captcha, index) => {
93
+ const sortedReceivedSolution = captcha.solution.sort();
94
+ const targetSolution = solutions[index]?.solution.sort();
95
+ if (!targetSolution) {
96
+ return false;
97
+ }
98
+ const incorrectCount = sortedReceivedSolution.filter(
99
+ (solution) => !targetSolution.includes(solution)
100
+ ).length;
101
+ const missingCount = targetSolution.filter(
102
+ (solution) => !sortedReceivedSolution.includes(solution)
103
+ ).length;
104
+ const totalIncorrect = incorrectCount + missingCount;
105
+ const percentageCorrect = 1 - totalIncorrect / totalImages;
106
+ return percentageCorrect >= threshold;
107
+ });
108
+ }
109
+ function computeCaptchaHash(captcha, includeSolution, includeSalt, sortItemHashes) {
110
+ try {
111
+ const itemHashes = captcha.items.map((item, index) => {
112
+ if (item.hash) {
113
+ return item.hash;
114
+ }
115
+ throw new common.ProsopoDatasetError("CAPTCHA.MISSING_ITEM_HASH", {
116
+ context: {
117
+ computeCaptchaHashName: computeCaptchaHash.name,
118
+ index
119
+ }
120
+ });
121
+ });
122
+ return utilCrypto.hexHashArray([
123
+ captcha.target,
124
+ // empty array hashes as empty string, undefined solution results in the array [`NO_SOLUTION`]
125
+ // [undefined] also hashes as empty string, which is why we don't use it
126
+ ...includeSolution ? getSolutionValueToHash(captcha.solution) : [],
127
+ includeSalt ? captcha.salt : "",
128
+ sortItemHashes ? itemHashes.sort() : itemHashes
129
+ ]);
130
+ } catch (err) {
131
+ throw new common.ProsopoDatasetError("DATASET.HASH_ERROR", {
132
+ context: { error: err }
133
+ });
134
+ }
135
+ }
136
+ function getSolutionValueToHash(solution) {
137
+ return solution !== void 0 ? solution.sort() : [NO_SOLUTION_VALUE];
138
+ }
139
+ async function computeItemHash(item) {
140
+ if (item.type === "text") {
141
+ return { ...item, hash: utilCrypto.hexHash(item.data) };
142
+ }
143
+ if (item.type === "image") {
144
+ return { ...item, hash: utilCrypto.hexHash(await util$1.downloadImage(item.data)) };
145
+ }
146
+ throw new common.ProsopoDatasetError("CAPTCHA.INVALID_ITEM_FORMAT");
147
+ }
148
+ function matchItemsToSolutions(solutions, items) {
149
+ if (!items) {
150
+ return [];
151
+ }
152
+ return solutions.map((solution) => {
153
+ if (typeof solution === "string" && util$2.isHex(solution)) {
154
+ if (!items?.some((item) => item.hash === solution)) {
155
+ throw new common.ProsopoDatasetError("CAPTCHA.INVALID_ITEM_HASH");
156
+ }
157
+ return solution;
158
+ }
159
+ if (typeof solution === "number") {
160
+ const item = util.at(items, solution);
161
+ return item.hash;
162
+ }
163
+ throw new common.ProsopoDatasetError("CAPTCHA.INVALID_SOLUTION_TYPE");
164
+ });
165
+ }
166
+ function computeCaptchaSolutionHash(captcha) {
167
+ return utilCrypto.hexHashArray([
168
+ captcha.captchaId,
169
+ captcha.captchaContentId,
170
+ [...captcha.solution].sort(),
171
+ captcha.salt
172
+ ]);
173
+ }
174
+ function computePendingRequestHash(captchaIds, userAccount, salt) {
175
+ return utilCrypto.hexHashArray([...captchaIds.sort(), userAccount, salt]);
176
+ }
177
+ function parseCaptchaAssets(item, assetsResolver) {
178
+ return {
179
+ ...item,
180
+ data: assetsResolver?.resolveAsset(item.data).getURL() || item.data
181
+ };
182
+ }
183
+ exports.NO_SOLUTION_VALUE = NO_SOLUTION_VALUE;
184
+ exports.captchaSort = captchaSort;
185
+ exports.compareCaptchaSolutions = compareCaptchaSolutions;
186
+ exports.computeCaptchaHash = computeCaptchaHash;
187
+ exports.computeCaptchaSolutionHash = computeCaptchaSolutionHash;
188
+ exports.computeItemHash = computeItemHash;
189
+ exports.computePendingRequestHash = computePendingRequestHash;
190
+ exports.getSolutionValueToHash = getSolutionValueToHash;
191
+ exports.matchItemsToSolutions = matchItemsToSolutions;
192
+ exports.parseAndSortCaptchaSolutions = parseAndSortCaptchaSolutions;
193
+ exports.parseCaptchaAssets = parseCaptchaAssets;
194
+ exports.parseCaptchaDataset = parseCaptchaDataset;
195
+ exports.sortAndComputeHashes = sortAndComputeHashes;
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const common = require("@prosopo/common");
4
+ const util = require("@prosopo/util");
5
+ const captcha = require("./captcha.cjs");
6
+ const merkle = require("./merkle.cjs");
7
+ var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
8
+ const logger = common.getLogger("info", typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("captcha/dataset.cjs", document.baseURI).href);
9
+ async function hashDatasetItems(datasetRaw) {
10
+ return datasetRaw.captchas.map(async (captcha$1) => {
11
+ const items = await Promise.all(
12
+ captcha$1.items.map(async (item) => captcha.computeItemHash(item))
13
+ );
14
+ return {
15
+ ...captcha$1,
16
+ items
17
+ };
18
+ });
19
+ }
20
+ async function validateDatasetContent(datasetOriginal) {
21
+ const captchaPromises = await hashDatasetItems(datasetOriginal);
22
+ const captchas = await Promise.all(captchaPromises);
23
+ const dataset = {
24
+ ...datasetOriginal,
25
+ captchas
26
+ };
27
+ const hashes = dataset.captchas.map((captcha2) => {
28
+ const captchaRaw = datasetOriginal.captchas.find(
29
+ (captchaRaw2) => "captchaId" in captchaRaw2 ? captchaRaw2.captchaId === captcha2.captchaId : false
30
+ );
31
+ if (captchaRaw) {
32
+ return captcha2.items.every(
33
+ (item, index) => item.hash === util.at(captchaRaw.items, index).hash
34
+ );
35
+ }
36
+ return false;
37
+ });
38
+ return hashes.every((hash) => hash);
39
+ }
40
+ async function buildDataset(datasetRaw) {
41
+ logger.debug(() => ({ msg: "Adding solution hashes to dataset" }));
42
+ const dataset = await addSolutionHashesToDataset(datasetRaw);
43
+ logger.debug(() => ({ msg: "Building dataset merkle trees" }));
44
+ const contentTree = await buildCaptchaTree(dataset, false, false, true);
45
+ const solutionTree = await buildCaptchaTree(dataset, true, true, false);
46
+ dataset.captchas = dataset.captchas.map(
47
+ (captcha2, index) => ({
48
+ ...captcha2,
49
+ captchaId: util.at(solutionTree.leaves, index).hash,
50
+ captchaContentId: util.at(contentTree.leaves, index).hash,
51
+ datasetId: solutionTree.root?.hash,
52
+ datasetContentId: contentTree.root?.hash
53
+ })
54
+ );
55
+ dataset.solutionTree = solutionTree.layers;
56
+ dataset.contentTree = contentTree.layers;
57
+ dataset.datasetId = solutionTree.root?.hash;
58
+ dataset.datasetContentId = contentTree.root?.hash;
59
+ return dataset;
60
+ }
61
+ async function buildCaptchaTree(dataset, includeSolution, includeSalt, sortItemHashes) {
62
+ try {
63
+ const tree = new merkle.CaptchaMerkleTree();
64
+ const datasetWithItemHashes = { ...dataset };
65
+ const captchaHashes = datasetWithItemHashes.captchas.map(
66
+ (captcha$1) => captcha.computeCaptchaHash(captcha$1, includeSolution, includeSalt, sortItemHashes)
67
+ );
68
+ tree.build(captchaHashes);
69
+ return tree;
70
+ } catch (err) {
71
+ throw new common.ProsopoEnvError("DATASET.HASH_ERROR");
72
+ }
73
+ }
74
+ function addSolutionHashesToDataset(datasetRaw) {
75
+ const captchas = datasetRaw.captchas.map((captcha$1) => {
76
+ return {
77
+ ...captcha$1,
78
+ items: captcha$1.items,
79
+ // some captcha challenges will not have a solution
80
+ ...captcha$1.solution !== void 0 && {
81
+ solution: captcha.matchItemsToSolutions(captcha$1.solution, captcha$1.items)
82
+ }
83
+ };
84
+ });
85
+ return {
86
+ ...datasetRaw,
87
+ captchas
88
+ };
89
+ }
90
+ exports.addSolutionHashesToDataset = addSolutionHashesToDataset;
91
+ exports.buildCaptchaTree = buildCaptchaTree;
92
+ exports.buildDataset = buildDataset;
93
+ exports.hashDatasetItems = hashDatasetItems;
94
+ exports.validateDatasetContent = validateDatasetContent;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const captcha = require("./captcha.cjs");
4
+ const merkle = require("./merkle.cjs");
5
+ const util = require("./util.cjs");
6
+ const dataset = require("./dataset.cjs");
7
+ exports.NO_SOLUTION_VALUE = captcha.NO_SOLUTION_VALUE;
8
+ exports.captchaSort = captcha.captchaSort;
9
+ exports.compareCaptchaSolutions = captcha.compareCaptchaSolutions;
10
+ exports.computeCaptchaHash = captcha.computeCaptchaHash;
11
+ exports.computeCaptchaSolutionHash = captcha.computeCaptchaSolutionHash;
12
+ exports.computeItemHash = captcha.computeItemHash;
13
+ exports.computePendingRequestHash = captcha.computePendingRequestHash;
14
+ exports.getSolutionValueToHash = captcha.getSolutionValueToHash;
15
+ exports.matchItemsToSolutions = captcha.matchItemsToSolutions;
16
+ exports.parseAndSortCaptchaSolutions = captcha.parseAndSortCaptchaSolutions;
17
+ exports.parseCaptchaAssets = captcha.parseCaptchaAssets;
18
+ exports.parseCaptchaDataset = captcha.parseCaptchaDataset;
19
+ exports.sortAndComputeHashes = captcha.sortAndComputeHashes;
20
+ exports.CaptchaMerkleTree = merkle.CaptchaMerkleTree;
21
+ exports.verifyProof = merkle.verifyProof;
22
+ exports.downloadImage = util.downloadImage;
23
+ exports.addSolutionHashesToDataset = dataset.addSolutionHashesToDataset;
24
+ exports.buildCaptchaTree = dataset.buildCaptchaTree;
25
+ exports.buildDataset = dataset.buildDataset;
26
+ exports.hashDatasetItems = dataset.hashDatasetItems;
27
+ exports.validateDatasetContent = dataset.validateDatasetContent;