@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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @prosopo/datasets
2
2
 
3
+ ## 3.0.43
4
+ ### Patch Changes
5
+
6
+ - 8ce9205: Change engine requirements
7
+ - b6e98b2: Run npm audit
8
+ - Updated dependencies [15ae7cf]
9
+ - Updated dependencies [bb5f41c]
10
+ - Updated dependencies [55a64c6]
11
+ - Updated dependencies [8ce9205]
12
+ - Updated dependencies [df79c03]
13
+ - Updated dependencies [8f22479]
14
+ - Updated dependencies [b6e98b2]
15
+ - Updated dependencies [55a64c6]
16
+ - @prosopo/types@3.6.0
17
+ - @prosopo/types-database@4.0.0
18
+ - @prosopo/util@3.2.0
19
+ - @prosopo/util-crypto@13.5.24
20
+ - @prosopo/common@3.1.22
21
+ - @prosopo/config@3.1.22
22
+
3
23
  ## 3.0.42
4
24
  ### Patch Changes
5
25
 
@@ -1,176 +1,195 @@
1
1
  import { isHex } from "@polkadot/util";
2
2
  import { ProsopoDatasetError, ProsopoEnvError } from "@prosopo/common";
3
- import { CaptchaSolutionArraySchema, DatasetWithNumericSolutionSchema, } from "@prosopo/types";
3
+ import { DatasetWithNumericSolutionSchema, CaptchaSolutionArraySchema } from "@prosopo/types";
4
4
  import { at } from "@prosopo/util";
5
- import { hexHash, hexHashArray } from "@prosopo/util-crypto";
5
+ import { hexHashArray, hexHash } from "@prosopo/util-crypto";
6
6
  import { downloadImage } from "./util.js";
7
- export const NO_SOLUTION_VALUE = "NO_SOLUTION";
8
- export function parseCaptchaDataset(datasetJSON) {
9
- try {
10
- const result = DatasetWithNumericSolutionSchema.parse(datasetJSON);
11
- const result2 = {
12
- format: result.format,
13
- captchas: result.captchas.map((captcha) => {
14
- return {
15
- ...captcha,
16
- solution: captcha.solution
17
- ? matchItemsToSolutions(captcha.solution, captcha.items)
18
- : [],
19
- unlabelled: captcha.unlabelled
20
- ? matchItemsToSolutions(captcha.unlabelled, captcha.items)
21
- : [],
22
- };
23
- }),
24
- };
25
- if (result.datasetId !== undefined)
26
- result2.datasetId = result.datasetId;
27
- if (result.contentTree !== undefined)
28
- result2.contentTree = result.contentTree;
29
- if (result.datasetContentId !== undefined)
30
- result2.datasetContentId = result.datasetContentId;
31
- if (result.solutionTree !== undefined)
32
- result2.solutionTree = result.solutionTree;
33
- return result2;
34
- }
35
- catch (err) {
36
- throw new ProsopoDatasetError("DATASET.DATASET_PARSE_ERROR", {
37
- context: { error: err },
38
- });
39
- }
40
- }
41
- export function parseAndSortCaptchaSolutions(captchaJSON) {
42
- try {
43
- return CaptchaSolutionArraySchema.parse(captchaJSON).map((captcha) => ({
44
- ...captcha,
45
- solution: captcha.solution.sort(),
46
- }));
47
- }
48
- catch (err) {
49
- throw new ProsopoDatasetError("DATASET.SOLUTION_PARSE_ERROR", {
50
- context: { error: err },
51
- });
52
- }
53
- }
54
- export function captchaSort(a, b) {
55
- return a.captchaId.localeCompare(b.captchaId);
56
- }
57
- export function sortAndComputeHashes(received, stored) {
58
- received.sort(captchaSort);
59
- stored.sort(captchaSort);
60
- return stored.map(({ salt, items = [], target = "", captchaId, solved }, index) => {
61
- const item = at(received, index);
62
- if (captchaId !== item.captchaId) {
63
- throw new ProsopoEnvError("CAPTCHA.ID_MISMATCH");
64
- }
7
+ const NO_SOLUTION_VALUE = "NO_SOLUTION";
8
+ function parseCaptchaDataset(datasetJSON) {
9
+ try {
10
+ const result = DatasetWithNumericSolutionSchema.parse(datasetJSON);
11
+ const result2 = {
12
+ format: result.format,
13
+ captchas: result.captchas.map((captcha) => {
65
14
  return {
66
- hash: computeCaptchaHash({
67
- solution: solved ? item.solution : [],
68
- salt,
69
- items,
70
- target,
71
- }, true, true, false),
72
- captchaId,
15
+ ...captcha,
16
+ solution: captcha.solution ? matchItemsToSolutions(captcha.solution, captcha.items) : [],
17
+ unlabelled: captcha.unlabelled ? matchItemsToSolutions(captcha.unlabelled, captcha.items) : []
73
18
  };
19
+ })
20
+ };
21
+ if (result.datasetId !== void 0) result2.datasetId = result.datasetId;
22
+ if (result.contentTree !== void 0)
23
+ result2.contentTree = result.contentTree;
24
+ if (result.datasetContentId !== void 0)
25
+ result2.datasetContentId = result.datasetContentId;
26
+ if (result.solutionTree !== void 0)
27
+ result2.solutionTree = result.solutionTree;
28
+ return result2;
29
+ } catch (err) {
30
+ throw new ProsopoDatasetError("DATASET.DATASET_PARSE_ERROR", {
31
+ context: { error: err }
74
32
  });
33
+ }
75
34
  }
76
- export function compareCaptchaSolutions(received, solutions, totalImages, threshold) {
77
- received.sort(captchaSort);
78
- solutions.sort(captchaSort);
79
- if (received.length !== solutions.length) {
80
- return false;
81
- }
82
- if (received.length &&
83
- solutions.length &&
84
- received.length === solutions.length) {
85
- const captchaIdMismatch = received.some((captcha, index) => solutions[index] && captcha.captchaId !== solutions[index].captchaId);
86
- if (captchaIdMismatch) {
87
- return false;
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((solution) => !targetSolution.includes(solution)).length;
97
- const missingCount = targetSolution.filter((solution) => !sortedReceivedSolution.includes(solution)).length;
98
- const totalIncorrect = incorrectCount + missingCount;
99
- const percentageCorrect = 1 - totalIncorrect / totalImages;
100
- return percentageCorrect >= threshold;
35
+ function parseAndSortCaptchaSolutions(captchaJSON) {
36
+ try {
37
+ return CaptchaSolutionArraySchema.parse(captchaJSON).map((captcha) => ({
38
+ ...captcha,
39
+ solution: captcha.solution.sort()
40
+ }));
41
+ } catch (err) {
42
+ throw new ProsopoDatasetError("DATASET.SOLUTION_PARSE_ERROR", {
43
+ context: { error: err }
101
44
  });
45
+ }
102
46
  }
103
- export function computeCaptchaHash(captcha, includeSolution, includeSalt, sortItemHashes) {
104
- try {
105
- const itemHashes = captcha.items.map((item, index) => {
106
- if (item.hash) {
107
- return item.hash;
108
- }
109
- throw new ProsopoDatasetError("CAPTCHA.MISSING_ITEM_HASH", {
110
- context: {
111
- computeCaptchaHashName: computeCaptchaHash.name,
112
- index,
113
- },
114
- });
115
- });
116
- return hexHashArray([
117
- captcha.target,
118
- ...(includeSolution ? getSolutionValueToHash(captcha.solution) : []),
119
- includeSalt ? captcha.salt : "",
120
- sortItemHashes ? itemHashes.sort() : itemHashes,
121
- ]);
122
- }
123
- catch (err) {
124
- throw new ProsopoDatasetError("DATASET.HASH_ERROR", {
125
- context: { error: err },
126
- });
127
- }
47
+ function captchaSort(a, b) {
48
+ return a.captchaId.localeCompare(b.captchaId);
128
49
  }
129
- export function getSolutionValueToHash(solution) {
130
- return solution !== undefined ? solution.sort() : [NO_SOLUTION_VALUE];
50
+ function sortAndComputeHashes(received, stored) {
51
+ received.sort(captchaSort);
52
+ stored.sort(captchaSort);
53
+ return stored.map(
54
+ ({ salt, items = [], target = "", captchaId, solved }, index) => {
55
+ const item = at(received, index);
56
+ if (captchaId !== item.captchaId) {
57
+ throw new ProsopoEnvError("CAPTCHA.ID_MISMATCH");
58
+ }
59
+ return {
60
+ hash: computeCaptchaHash(
61
+ {
62
+ solution: solved ? item.solution : [],
63
+ salt,
64
+ items,
65
+ target
66
+ },
67
+ true,
68
+ true,
69
+ false
70
+ ),
71
+ captchaId
72
+ };
73
+ }
74
+ );
131
75
  }
132
- export async function computeItemHash(item) {
133
- if (item.type === "text") {
134
- return { ...item, hash: hexHash(item.data) };
76
+ function compareCaptchaSolutions(received, solutions, totalImages, threshold) {
77
+ received.sort(captchaSort);
78
+ solutions.sort(captchaSort);
79
+ if (received.length !== solutions.length) {
80
+ return false;
81
+ }
82
+ if (received.length && solutions.length && received.length === solutions.length) {
83
+ const captchaIdMismatch = received.some(
84
+ (captcha, index) => solutions[index] && captcha.captchaId !== solutions[index].captchaId
85
+ );
86
+ if (captchaIdMismatch) {
87
+ return false;
135
88
  }
136
- if (item.type === "image") {
137
- return { ...item, hash: hexHash(await downloadImage(item.data)) };
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;
138
95
  }
139
- throw new ProsopoDatasetError("CAPTCHA.INVALID_ITEM_FORMAT");
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
+ });
140
106
  }
141
- export function matchItemsToSolutions(solutions, items) {
142
- if (!items) {
143
- return [];
144
- }
145
- return solutions.map((solution) => {
146
- if (typeof solution === "string" && isHex(solution)) {
147
- if (!items?.some((item) => item.hash === solution)) {
148
- throw new ProsopoDatasetError("CAPTCHA.INVALID_ITEM_HASH");
149
- }
150
- return solution;
107
+ function computeCaptchaHash(captcha, includeSolution, includeSalt, sortItemHashes) {
108
+ try {
109
+ const itemHashes = captcha.items.map((item, index) => {
110
+ if (item.hash) {
111
+ return item.hash;
112
+ }
113
+ throw new ProsopoDatasetError("CAPTCHA.MISSING_ITEM_HASH", {
114
+ context: {
115
+ computeCaptchaHashName: computeCaptchaHash.name,
116
+ index
151
117
  }
152
- if (typeof solution === "number") {
153
- const item = at(items, solution);
154
- return item.hash;
155
- }
156
- throw new ProsopoDatasetError("CAPTCHA.INVALID_SOLUTION_TYPE");
118
+ });
157
119
  });
158
- }
159
- export function computeCaptchaSolutionHash(captcha) {
160
120
  return hexHashArray([
161
- captcha.captchaId,
162
- captcha.captchaContentId,
163
- [...captcha.solution].sort(),
164
- captcha.salt,
121
+ captcha.target,
122
+ // empty array hashes as empty string, undefined solution results in the array [`NO_SOLUTION`]
123
+ // [undefined] also hashes as empty string, which is why we don't use it
124
+ ...includeSolution ? getSolutionValueToHash(captcha.solution) : [],
125
+ includeSalt ? captcha.salt : "",
126
+ sortItemHashes ? itemHashes.sort() : itemHashes
165
127
  ]);
128
+ } catch (err) {
129
+ throw new ProsopoDatasetError("DATASET.HASH_ERROR", {
130
+ context: { error: err }
131
+ });
132
+ }
166
133
  }
167
- export function computePendingRequestHash(captchaIds, userAccount, salt) {
168
- return hexHashArray([...captchaIds.sort(), userAccount, salt]);
134
+ function getSolutionValueToHash(solution) {
135
+ return solution !== void 0 ? solution.sort() : [NO_SOLUTION_VALUE];
169
136
  }
170
- export function parseCaptchaAssets(item, assetsResolver) {
171
- return {
172
- ...item,
173
- data: assetsResolver?.resolveAsset(item.data).getURL() || item.data,
174
- };
137
+ async function computeItemHash(item) {
138
+ if (item.type === "text") {
139
+ return { ...item, hash: hexHash(item.data) };
140
+ }
141
+ if (item.type === "image") {
142
+ return { ...item, hash: hexHash(await downloadImage(item.data)) };
143
+ }
144
+ throw new ProsopoDatasetError("CAPTCHA.INVALID_ITEM_FORMAT");
145
+ }
146
+ function matchItemsToSolutions(solutions, items) {
147
+ if (!items) {
148
+ return [];
149
+ }
150
+ return solutions.map((solution) => {
151
+ if (typeof solution === "string" && isHex(solution)) {
152
+ if (!items?.some((item) => item.hash === solution)) {
153
+ throw new ProsopoDatasetError("CAPTCHA.INVALID_ITEM_HASH");
154
+ }
155
+ return solution;
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
+ });
163
+ }
164
+ function computeCaptchaSolutionHash(captcha) {
165
+ return hexHashArray([
166
+ captcha.captchaId,
167
+ captcha.captchaContentId,
168
+ [...captcha.solution].sort(),
169
+ captcha.salt
170
+ ]);
171
+ }
172
+ function computePendingRequestHash(captchaIds, userAccount, salt) {
173
+ return hexHashArray([...captchaIds.sort(), userAccount, salt]);
174
+ }
175
+ function parseCaptchaAssets(item, assetsResolver) {
176
+ return {
177
+ ...item,
178
+ data: assetsResolver?.resolveAsset(item.data).getURL() || item.data
179
+ };
175
180
  }
176
- //# sourceMappingURL=captcha.js.map
181
+ export {
182
+ NO_SOLUTION_VALUE,
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
+ };
@@ -1,79 +1,93 @@
1
- import { ProsopoEnvError, getLogger } from "@prosopo/common";
1
+ import { getLogger, ProsopoEnvError } from "@prosopo/common";
2
2
  import { at } from "@prosopo/util";
3
- import { computeCaptchaHash, computeItemHash, matchItemsToSolutions, } from "./captcha.js";
3
+ import { computeItemHash, computeCaptchaHash, matchItemsToSolutions } from "./captcha.js";
4
4
  import { CaptchaMerkleTree } from "./merkle.js";
5
5
  const logger = getLogger("info", import.meta.url);
6
- export async function hashDatasetItems(datasetRaw) {
7
- return datasetRaw.captchas.map(async (captcha) => {
8
- const items = await Promise.all(captcha.items.map(async (item) => computeItemHash(item)));
9
- return {
10
- ...captcha,
11
- items,
12
- };
13
- });
14
- }
15
- export async function validateDatasetContent(datasetOriginal) {
16
- const captchaPromises = await hashDatasetItems(datasetOriginal);
17
- const captchas = await Promise.all(captchaPromises);
18
- const dataset = {
19
- ...datasetOriginal,
20
- captchas,
6
+ async function hashDatasetItems(datasetRaw) {
7
+ return datasetRaw.captchas.map(async (captcha) => {
8
+ const items = await Promise.all(
9
+ captcha.items.map(async (item) => computeItemHash(item))
10
+ );
11
+ return {
12
+ ...captcha,
13
+ items
21
14
  };
22
- const hashes = dataset.captchas.map((captcha) => {
23
- const captchaRaw = datasetOriginal.captchas.find((captchaRaw) => "captchaId" in captchaRaw
24
- ? captchaRaw.captchaId === captcha.captchaId
25
- : false);
26
- if (captchaRaw) {
27
- return captcha.items.every((item, index) => item.hash === at(captchaRaw.items, index).hash);
28
- }
29
- return false;
30
- });
31
- return hashes.every((hash) => hash);
32
- }
33
- export async function buildDataset(datasetRaw) {
34
- logger.debug(() => ({ msg: "Adding solution hashes to dataset" }));
35
- const dataset = await addSolutionHashesToDataset(datasetRaw);
36
- logger.debug(() => ({ msg: "Building dataset merkle trees" }));
37
- const contentTree = await buildCaptchaTree(dataset, false, false, true);
38
- const solutionTree = await buildCaptchaTree(dataset, true, true, false);
39
- dataset.captchas = dataset.captchas.map((captcha, index) => ({
40
- ...captcha,
41
- captchaId: at(solutionTree.leaves, index).hash,
42
- captchaContentId: at(contentTree.leaves, index).hash,
43
- datasetId: solutionTree.root?.hash,
44
- datasetContentId: contentTree.root?.hash,
45
- }));
46
- dataset.solutionTree = solutionTree.layers;
47
- dataset.contentTree = contentTree.layers;
48
- dataset.datasetId = solutionTree.root?.hash;
49
- dataset.datasetContentId = contentTree.root?.hash;
50
- return dataset;
15
+ });
51
16
  }
52
- export async function buildCaptchaTree(dataset, includeSolution, includeSalt, sortItemHashes) {
53
- try {
54
- const tree = new CaptchaMerkleTree();
55
- const datasetWithItemHashes = { ...dataset };
56
- const captchaHashes = datasetWithItemHashes.captchas.map((captcha) => computeCaptchaHash(captcha, includeSolution, includeSalt, sortItemHashes));
57
- tree.build(captchaHashes);
58
- return tree;
59
- }
60
- catch (err) {
61
- throw new ProsopoEnvError("DATASET.HASH_ERROR");
17
+ async function validateDatasetContent(datasetOriginal) {
18
+ const captchaPromises = await hashDatasetItems(datasetOriginal);
19
+ const captchas = await Promise.all(captchaPromises);
20
+ const dataset = {
21
+ ...datasetOriginal,
22
+ captchas
23
+ };
24
+ const hashes = dataset.captchas.map((captcha) => {
25
+ const captchaRaw = datasetOriginal.captchas.find(
26
+ (captchaRaw2) => "captchaId" in captchaRaw2 ? captchaRaw2.captchaId === captcha.captchaId : false
27
+ );
28
+ if (captchaRaw) {
29
+ return captcha.items.every(
30
+ (item, index) => item.hash === at(captchaRaw.items, index).hash
31
+ );
62
32
  }
33
+ return false;
34
+ });
35
+ return hashes.every((hash) => hash);
36
+ }
37
+ async function buildDataset(datasetRaw) {
38
+ logger.debug(() => ({ msg: "Adding solution hashes to dataset" }));
39
+ const dataset = await addSolutionHashesToDataset(datasetRaw);
40
+ logger.debug(() => ({ msg: "Building dataset merkle trees" }));
41
+ const contentTree = await buildCaptchaTree(dataset, false, false, true);
42
+ const solutionTree = await buildCaptchaTree(dataset, true, true, false);
43
+ dataset.captchas = dataset.captchas.map(
44
+ (captcha, index) => ({
45
+ ...captcha,
46
+ captchaId: at(solutionTree.leaves, index).hash,
47
+ captchaContentId: at(contentTree.leaves, index).hash,
48
+ datasetId: solutionTree.root?.hash,
49
+ datasetContentId: contentTree.root?.hash
50
+ })
51
+ );
52
+ dataset.solutionTree = solutionTree.layers;
53
+ dataset.contentTree = contentTree.layers;
54
+ dataset.datasetId = solutionTree.root?.hash;
55
+ dataset.datasetContentId = contentTree.root?.hash;
56
+ return dataset;
57
+ }
58
+ async function buildCaptchaTree(dataset, includeSolution, includeSalt, sortItemHashes) {
59
+ try {
60
+ const tree = new CaptchaMerkleTree();
61
+ const datasetWithItemHashes = { ...dataset };
62
+ const captchaHashes = datasetWithItemHashes.captchas.map(
63
+ (captcha) => computeCaptchaHash(captcha, includeSolution, includeSalt, sortItemHashes)
64
+ );
65
+ tree.build(captchaHashes);
66
+ return tree;
67
+ } catch (err) {
68
+ throw new ProsopoEnvError("DATASET.HASH_ERROR");
69
+ }
63
70
  }
64
- export function addSolutionHashesToDataset(datasetRaw) {
65
- const captchas = datasetRaw.captchas.map((captcha) => {
66
- return {
67
- ...captcha,
68
- items: captcha.items,
69
- ...(captcha.solution !== undefined && {
70
- solution: matchItemsToSolutions(captcha.solution, captcha.items),
71
- }),
72
- };
73
- });
71
+ function addSolutionHashesToDataset(datasetRaw) {
72
+ const captchas = datasetRaw.captchas.map((captcha) => {
74
73
  return {
75
- ...datasetRaw,
76
- captchas,
74
+ ...captcha,
75
+ items: captcha.items,
76
+ // some captcha challenges will not have a solution
77
+ ...captcha.solution !== void 0 && {
78
+ solution: matchItemsToSolutions(captcha.solution, captcha.items)
79
+ }
77
80
  };
81
+ });
82
+ return {
83
+ ...datasetRaw,
84
+ captchas
85
+ };
78
86
  }
79
- //# sourceMappingURL=dataset.js.map
87
+ export {
88
+ addSolutionHashesToDataset,
89
+ buildCaptchaTree,
90
+ buildDataset,
91
+ hashDatasetItems,
92
+ validateDatasetContent
93
+ };
@@ -1,5 +1,27 @@
1
- export * from "./captcha.js";
2
- export * from "./merkle.js";
3
- export * from "./util.js";
4
- export * from "./dataset.js";
5
- //# sourceMappingURL=index.js.map
1
+ import { NO_SOLUTION_VALUE, captchaSort, compareCaptchaSolutions, computeCaptchaHash, computeCaptchaSolutionHash, computeItemHash, computePendingRequestHash, getSolutionValueToHash, matchItemsToSolutions, parseAndSortCaptchaSolutions, parseCaptchaAssets, parseCaptchaDataset, sortAndComputeHashes } from "./captcha.js";
2
+ import { CaptchaMerkleTree, verifyProof } from "./merkle.js";
3
+ import { downloadImage } from "./util.js";
4
+ import { addSolutionHashesToDataset, buildCaptchaTree, buildDataset, hashDatasetItems, validateDatasetContent } from "./dataset.js";
5
+ export {
6
+ CaptchaMerkleTree,
7
+ NO_SOLUTION_VALUE,
8
+ addSolutionHashesToDataset,
9
+ buildCaptchaTree,
10
+ buildDataset,
11
+ captchaSort,
12
+ compareCaptchaSolutions,
13
+ computeCaptchaHash,
14
+ computeCaptchaSolutionHash,
15
+ computeItemHash,
16
+ computePendingRequestHash,
17
+ downloadImage,
18
+ getSolutionValueToHash,
19
+ hashDatasetItems,
20
+ matchItemsToSolutions,
21
+ parseAndSortCaptchaSolutions,
22
+ parseCaptchaAssets,
23
+ parseCaptchaDataset,
24
+ sortAndComputeHashes,
25
+ validateDatasetContent,
26
+ verifyProof
27
+ };