@prosopo/procaptcha 0.2.29 → 0.2.32

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.
@@ -6,13 +6,11 @@ require("./types/index.cjs");
6
6
  require("./utils/index.cjs");
7
7
  const Manager = require("./modules/Manager.cjs");
8
8
  const ProsopoCaptchaApi = require("./modules/ProsopoCaptchaApi.cjs");
9
- const collector = require("./modules/collector.cjs");
10
9
  const manager = require("./types/manager.cjs");
11
10
  const utils = require("./utils/utils.cjs");
12
11
  exports.Manager = Manager.Manager;
13
12
  exports.defaultState = Manager.defaultState;
14
13
  exports.getNetwork = Manager.getNetwork;
15
14
  exports.ProsopoCaptchaApi = ProsopoCaptchaApi.ProsopoCaptchaApi;
16
- exports.startCollector = collector.startCollector;
17
15
  exports.ProcapchaEventNames = manager.ProcapchaEventNames;
18
16
  exports.sleep = utils.sleep;
@@ -5,10 +5,10 @@ const Api = require("@polkadot/api/promise/Api");
5
5
  const types = require("@prosopo/types");
6
6
  const api = require("@prosopo/api");
7
7
  const keyring = require("@polkadot/keyring");
8
- const common = require("@prosopo/common");
9
8
  const contract = require("@prosopo/contract");
9
+ const common = require("@prosopo/common");
10
10
  const ws = require("@polkadot/rpc-provider/ws");
11
- const contractInfo = require("@prosopo/captcha-contract/contract-info");
11
+ const captcha = require("../contracts/captcha/dist/contract-info/captcha.cjs");
12
12
  const util = require("@prosopo/util");
13
13
  const random = require("@polkadot/util-crypto/random");
14
14
  const utils = require("../utils/utils.cjs");
@@ -42,9 +42,7 @@ const buildUpdateState = (state, onStateUpdate) => {
42
42
  const getNetwork = (config) => {
43
43
  const network = config.networks[config.defaultNetwork];
44
44
  if (!network) {
45
- throw new common.ProsopoEnvError("DEVELOPER.NETWORK_NOT_FOUND", {
46
- context: { error: `No network found for environment ${config.defaultEnvironment}` }
47
- });
45
+ throw new Error(`No network found for environment ${config.defaultEnvironment}`);
48
46
  }
49
47
  return network;
50
48
  };
@@ -59,14 +57,12 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
59
57
  onError: alertError,
60
58
  onHuman: (output) => {
61
59
  console.log("onHuman event triggered", output);
62
- updateState({ sendData: !state.sendData });
63
60
  },
64
61
  onExtensionNotFound: () => {
65
62
  alert("No extension found");
66
63
  },
67
64
  onFailed: () => {
68
65
  alert("Captcha challenge failed. Please try again");
69
- updateState({ sendData: !state.sendData });
70
66
  },
71
67
  onExpired: () => {
72
68
  alert("Completed challenge has expired, please try again");
@@ -76,7 +72,6 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
76
72
  },
77
73
  onOpen: () => {
78
74
  console.log("onOpen event triggered");
79
- updateState({ sendData: !state.sendData });
80
75
  },
81
76
  onClose: () => {
82
77
  console.log("onClose event triggered");
@@ -151,12 +146,7 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
151
146
  if (providerUrlFromStorage) {
152
147
  providerApi = await loadProviderApi(providerUrlFromStorage);
153
148
  try {
154
- const verifyDappUserResponse = await providerApi.verifyDappUser(
155
- getDappAccount(),
156
- account.account.address,
157
- void 0,
158
- configOptional.challengeValidLength
159
- );
149
+ const verifyDappUserResponse = await providerApi.verifyDappUser(account.account.address);
160
150
  if (verifyDappUserResponse.solutionApproved) {
161
151
  updateState({ isHuman: true, loading: false });
162
152
  events.onHuman({
@@ -193,9 +183,9 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
193
183
  const challenge = await captchaApi.getCaptchaChallenge();
194
184
  console.log("challenge", challenge);
195
185
  if (challenge.captchas.length <= 0) {
196
- throw new common.ProsopoApiError("DEVELOPER.PROVIDER_NO_CAPTCHA");
186
+ throw new Error("No captchas returned from provider");
197
187
  }
198
- const timeMillis = challenge.captchas.map((captcha) => captcha.captcha.timeLimitMs || 30 * 1e3).reduce((a, b) => a + b);
188
+ const timeMillis = challenge.captchas.map((captcha2) => captcha2.captcha.timeLimitMs || 30 * 1e3).reduce((a, b) => a + b);
199
189
  const timeout = setTimeout(() => {
200
190
  console.log("challenge expired after " + timeMillis + "ms");
201
191
  events.onChallengeExpired();
@@ -216,18 +206,16 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
216
206
  console.log("submitting solutions");
217
207
  clearTimeout();
218
208
  if (!state.challenge) {
219
- throw new common.ProsopoError("CAPTCHA.NO_CAPTCHA", {
220
- context: { error: "Cannot submit, no Captcha found in state" }
221
- });
209
+ throw new Error("cannot submit, no challenge found");
222
210
  }
223
211
  updateState({ showModal: false });
224
212
  const challenge = state.challenge;
225
213
  const salt = random.randomAsHex();
226
- const captchaSolution = state.challenge.captchas.map((captcha, index) => {
214
+ const captchaSolution = state.challenge.captchas.map((captcha2, index) => {
227
215
  const solution = util.at(state.solutions, index);
228
216
  return {
229
- captchaId: captcha.captcha.captchaId,
230
- captchaContentId: captcha.captcha.captchaContentId,
217
+ captchaId: captcha2.captcha.captchaId,
218
+ captchaContentId: captcha2.captcha.captchaContentId,
231
219
  salt,
232
220
  solution
233
221
  };
@@ -237,9 +225,7 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
237
225
  const signer = account.extension.signer;
238
226
  const first = util.at(challenge.captchas, 0);
239
227
  if (!first.captcha.datasetId) {
240
- throw new common.ProsopoDatasetError("CAPTCHA.INVALID_CAPTCHA_ID", {
241
- context: { error: "No datasetId set for challenge" }
242
- });
228
+ throw new Error("No datasetId set for challenge");
243
229
  }
244
230
  const captchaApi = getCaptchaApi();
245
231
  const submission = await captchaApi.submitCaptchaSolution(
@@ -280,14 +266,10 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
280
266
  };
281
267
  const select = (hash) => {
282
268
  if (!state.challenge) {
283
- throw new common.ProsopoError("CAPTCHA.NO_CAPTCHA", {
284
- context: { error: "Cannot select, no Captcha found in state" }
285
- });
269
+ throw new Error("cannot select, no challenge found");
286
270
  }
287
271
  if (state.index >= state.challenge.captchas.length || state.index < 0) {
288
- throw new common.ProsopoError("CAPTCHA.NO_CAPTCHA", {
289
- context: { error: "Cannot select, index is out of range for this Captcha" }
290
- });
272
+ throw new Error("cannot select, round index out of range");
291
273
  }
292
274
  const index = state.index;
293
275
  const solutions = state.solutions;
@@ -303,14 +285,10 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
303
285
  };
304
286
  const nextRound = () => {
305
287
  if (!state.challenge) {
306
- throw new common.ProsopoError("CAPTCHA.NO_CAPTCHA", {
307
- context: { error: "Cannot select, no Captcha found in state" }
308
- });
288
+ throw new Error("cannot proceed to next round, no challenge found");
309
289
  }
310
290
  if (state.index + 1 >= state.challenge.captchas.length) {
311
- throw new common.ProsopoError("CAPTCHA.NO_CAPTCHA", {
312
- context: { error: "Cannot select, index is out of range for this Captcha" }
313
- });
291
+ throw new Error("cannot proceed to next round, already at last round");
314
292
  }
315
293
  console.log("proceeding to next round");
316
294
  updateState({ index: state.index + 1 });
@@ -356,16 +334,14 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
356
334
  };
357
335
  const getCaptchaApi = () => {
358
336
  if (!state.captchaApi) {
359
- throw new common.ProsopoApiError("API.UNKNOWN", { context: { error: "Captcha api not set", state } });
337
+ throw new Error("Captcha api not set");
360
338
  }
361
339
  return state.captchaApi;
362
340
  };
363
341
  const loadAccount = async () => {
364
342
  const config = getConfig();
365
343
  if (!config.web2 && !config.userAccountAddress) {
366
- throw new common.ProsopoEnvError("GENERAL.ACCOUNT_NOT_FOUND", {
367
- context: { error: "Account address has not been set for web3 mode" }
368
- });
344
+ throw new Error("Account address has not been set for web3 mode");
369
345
  }
370
346
  const ext = config.web2 ? new ExtensionWeb2() : new ExtensionWeb3();
371
347
  const account = await ext.getAccount(config);
@@ -376,7 +352,7 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
376
352
  };
377
353
  const getAccount = () => {
378
354
  if (!state.account) {
379
- throw new common.ProsopoEnvError("GENERAL.ACCOUNT_NOT_FOUND", { context: { error: "Account not loaded" } });
355
+ throw new Error("Account not loaded");
380
356
  }
381
357
  const account = state.account;
382
358
  return account;
@@ -390,7 +366,7 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
390
366
  };
391
367
  const getBlockNumber = () => {
392
368
  if (!state.blockNumber) {
393
- throw new common.ProsopoContractError("CAPTCHA.INVALID_BLOCK_NO", { context: { error: "Block number not found" } });
369
+ throw new Error("Account not loaded");
394
370
  }
395
371
  const blockNumber = state.blockNumber;
396
372
  return blockNumber;
@@ -403,29 +379,19 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
403
379
  const keyring$1 = new keyring.Keyring({ type, ss58Format: api2.registry.chainSS58 });
404
380
  return new contract.ProsopoCaptchaContract(
405
381
  api2,
406
- JSON.parse(contractInfo.ContractAbi),
382
+ JSON.parse(captcha.ContractAbi),
407
383
  network.contract.address,
408
384
  "prosopo",
409
385
  0,
410
386
  keyring$1.addFromAddress(getAccount().account.address)
411
387
  );
412
388
  };
413
- const exportData = async (events2) => {
414
- var _a;
415
- const providerUrl = storage.getProviderUrl() || ((_a = state.captchaApi) == null ? void 0 : _a.provider.provider.url.toString());
416
- if (!providerUrl) {
417
- return;
418
- }
419
- const providerApi = await loadProviderApi(providerUrl);
420
- await providerApi.submitUserEvents(events2, getAccount().account.address);
421
- };
422
389
  return {
423
390
  start,
424
391
  cancel,
425
392
  submit,
426
393
  select,
427
- nextRound,
428
- exportData
394
+ nextRound
429
395
  };
430
396
  }
431
397
  exports.Manager = Manager;
@@ -1,9 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
- const datasets = require("@prosopo/datasets");
3
+ require("../packages/datasets/dist/index.cjs");
4
+ const handlers = require("../api/handlers.cjs");
4
5
  const common = require("@prosopo/common");
5
6
  const util = require("@prosopo/util");
6
7
  const string = require("@polkadot/util/string");
8
+ const merkle = require("../packages/datasets/dist/captcha/merkle.cjs");
9
+ const captcha = require("../packages/datasets/dist/captcha/captcha.cjs");
7
10
  class ProsopoCaptchaApi {
8
11
  constructor(userAccount, contract, provider, providerApi, web2, dappAccount) {
9
12
  this.userAccount = userAccount;
@@ -18,8 +21,8 @@ class ProsopoCaptchaApi {
18
21
  const captchaChallenge = await this.providerApi.getCaptchaChallenge(this.userAccount, this.provider);
19
22
  this.verifyCaptchaChallengeContent(this.provider, captchaChallenge);
20
23
  return captchaChallenge;
21
- } catch (error) {
22
- throw new common.ProsopoEnvError("CAPTCHA.INVALID_CAPTCHA_CHALLENGE", { context: { error } });
24
+ } catch (e) {
25
+ throw new common.ProsopoEnvError(e);
23
26
  }
24
27
  }
25
28
  verifyCaptchaChallengeContent(provider, captchaChallenge) {
@@ -34,7 +37,7 @@ class ProsopoCaptchaApi {
34
37
  if (!verifyCaptchaData(captchaWithProof)) {
35
38
  throw new common.ProsopoEnvError("CAPTCHA.INVALID_CAPTCHA_CHALLENGE");
36
39
  }
37
- if (!datasets.verifyProof(captchaWithProof.captcha.captchaContentId, captchaWithProof.proof)) {
40
+ if (!merkle.verifyProof(captchaWithProof.captcha.captchaContentId, captchaWithProof.proof)) {
38
41
  throw new common.ProsopoEnvError("CAPTCHA.INVALID_CAPTCHA_CHALLENGE");
39
42
  }
40
43
  }
@@ -42,8 +45,8 @@ class ProsopoCaptchaApi {
42
45
  return;
43
46
  }
44
47
  async submitCaptchaSolution(signer, requestHash, datasetId, solutions, salt) {
45
- const tree = new datasets.CaptchaMerkleTree();
46
- const captchasHashed = solutions.map((captcha) => datasets.computeCaptchaSolutionHash(captcha));
48
+ const tree = new merkle.CaptchaMerkleTree();
49
+ const captchasHashed = solutions.map((captcha$1) => captcha.computeCaptchaSolutionHash(captcha$1));
47
50
  tree.build(captchasHashed);
48
51
  const commitmentId = tree.root.hash;
49
52
  console.log("solveCaptchaChallenge commitmentId", commitmentId);
@@ -51,9 +54,7 @@ class ProsopoCaptchaApi {
51
54
  let signature = void 0;
52
55
  if (this.web2) {
53
56
  if (!signer || !signer.signRaw) {
54
- throw new common.ProsopoEnvError("GENERAL.CANT_FIND_KEYRINGPAIR", {
55
- context: { error: "Signer is not defined, cannot sign message to prove account ownership" }
56
- });
57
+ throw new Error("Signer is not defined, cannot sign message to prove account ownership");
57
58
  }
58
59
  const signed = await signer.signRaw({
59
60
  address: this.userAccount,
@@ -71,22 +72,22 @@ class ProsopoCaptchaApi {
71
72
  salt,
72
73
  signature
73
74
  );
74
- } catch (error) {
75
- throw new common.ProsopoDatasetError("CAPTCHA.INVALID_CAPTCHA_CHALLENGE", { context: { error } });
75
+ } catch (err) {
76
+ throw new handlers.ProsopoApiError(err);
76
77
  }
77
78
  return [result, commitmentId, tx];
78
79
  }
79
80
  }
80
81
  async function verifyCaptchaData(captchaWithProof) {
81
- const captcha = captchaWithProof.captcha;
82
+ const captcha$1 = captchaWithProof.captcha;
82
83
  const proof = captchaWithProof.proof;
83
- if (!(await Promise.all(captcha.items.map(async (item) => (await datasets.computeItemHash(item)).hash === item.hash))).every(
84
+ if (!(await Promise.all(captcha$1.items.map(async (item) => (await captcha.computeItemHash(item)).hash === item.hash))).every(
84
85
  (hash) => hash === true
85
86
  )) {
86
87
  return false;
87
88
  }
88
- const captchaHash = datasets.computeCaptchaHash(captcha, false, false, false);
89
- if (captchaHash !== captcha.captchaContentId) {
89
+ const captchaHash = captcha.computeCaptchaHash(captcha$1, false, false, false);
90
+ if (captchaHash !== captcha$1.captchaContentId) {
90
91
  return false;
91
92
  }
92
93
  return util.at(proof, 0).indexOf(captchaHash) !== -1;
@@ -366,8 +366,9 @@ function picassoCanvas(roundNumber, seed, params) {
366
366
  }
367
367
  }
368
368
  return x64hash128(canvasElt.toDataURL(), seed);
369
- } catch (error) {
370
- throw new common.ProsopoError("WIDGET.CANVAS", { context: { error } });
369
+ } catch (e) {
370
+ console.log(e);
371
+ throw new common.ProsopoEnvError(e);
371
372
  }
372
373
  }
373
374
  exports.picassoCanvas = picassoCanvas;
@@ -2,9 +2,7 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const Manager = require("./Manager.cjs");
4
4
  const ProsopoCaptchaApi = require("./ProsopoCaptchaApi.cjs");
5
- const collector = require("./collector.cjs");
6
5
  exports.Manager = Manager.Manager;
7
6
  exports.defaultState = Manager.defaultState;
8
7
  exports.getNetwork = Manager.getNetwork;
9
8
  exports.ProsopoCaptchaApi = ProsopoCaptchaApi.ProsopoCaptchaApi;
10
- exports.startCollector = collector.startCollector;
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const types = require("@prosopo/types");
4
+ const common = require("@prosopo/common");
5
+ const util = require("@prosopo/util");
6
+ const util$1 = require("./util.cjs");
7
+ const NO_SOLUTION_VALUE = "NO_SOLUTION";
8
+ function parseCaptchaDataset(datasetJSON) {
9
+ try {
10
+ const result = types.DatasetWithNumericSolutionSchema.parse(datasetJSON);
11
+ const result2 = {
12
+ format: result.format,
13
+ captchas: result.captchas.map((captcha) => {
14
+ return {
15
+ ...captcha,
16
+ solution: captcha.solution ? matchItemsToSolutions(captcha.solution, captcha.items) : [],
17
+ unlabelled: captcha.unlabelled ? matchItemsToSolutions(captcha.unlabelled, captcha.items) : []
18
+ };
19
+ })
20
+ };
21
+ if (result.datasetId !== void 0)
22
+ result2.datasetId = result.datasetId;
23
+ if (result.contentTree !== void 0)
24
+ result2.contentTree = result.contentTree;
25
+ if (result.datasetContentId !== void 0)
26
+ result2.datasetContentId = result.datasetContentId;
27
+ if (result.solutionTree !== void 0)
28
+ result2.solutionTree = result.solutionTree;
29
+ return result2;
30
+ } catch (err) {
31
+ throw new common.ProsopoEnvError(err);
32
+ }
33
+ }
34
+ function parseAndSortCaptchaSolutions(captchaJSON) {
35
+ try {
36
+ return types.CaptchaSolutionArraySchema.parse(captchaJSON).map((captcha) => ({
37
+ ...captcha,
38
+ solution: captcha.solution.sort()
39
+ }));
40
+ } catch (err) {
41
+ throw new common.ProsopoEnvError(err);
42
+ }
43
+ }
44
+ function captchaSort(a, b) {
45
+ return a.captchaId.localeCompare(b.captchaId);
46
+ }
47
+ function sortAndComputeHashes(received, stored) {
48
+ received.sort(captchaSort);
49
+ stored.sort(captchaSort);
50
+ return stored.map(({ salt, items = [], target = "", captchaId, solved }, index) => {
51
+ const item = util.at(received, index);
52
+ if (captchaId != item.captchaId) {
53
+ throw new common.ProsopoEnvError("CAPTCHA.ID_MISMATCH");
54
+ }
55
+ return {
56
+ hash: computeCaptchaHash({
57
+ solution: solved ? item.solution : [],
58
+ salt,
59
+ items,
60
+ target
61
+ }, true, true, false),
62
+ captchaId
63
+ };
64
+ });
65
+ }
66
+ function compareCaptchaSolutions(received, stored) {
67
+ if (received.length && stored.length && received.length === stored.length) {
68
+ const hashes = sortAndComputeHashes(received, stored);
69
+ return hashes.every(({ hash, captchaId }) => hash === captchaId);
70
+ }
71
+ return false;
72
+ }
73
+ function computeCaptchaHash(captcha, includeSolution = false, includeSalt = false, sortItemHashes) {
74
+ try {
75
+ const itemHashes = captcha.items.map((item, index) => {
76
+ if (item.hash) {
77
+ return item.hash;
78
+ } else {
79
+ throw new common.ProsopoEnvError("CAPTCHA.MISSING_ITEM_HASH", computeCaptchaHash.name, void 0, index);
80
+ }
81
+ });
82
+ return common.hexHashArray([
83
+ captcha.target,
84
+ // empty array hashes as empty string, undefined solution results in the array [`NO_SOLUTION`]
85
+ // [undefined] also hashes as empty string, which is why we don't use it
86
+ ...includeSolution ? getSolutionValueToHash(captcha.solution) : [],
87
+ includeSalt ? captcha.salt : "",
88
+ sortItemHashes ? itemHashes.sort() : itemHashes
89
+ ]);
90
+ } catch (err) {
91
+ throw new common.ProsopoEnvError(err);
92
+ }
93
+ }
94
+ function getSolutionValueToHash(solution) {
95
+ return solution !== void 0 ? solution.sort() : [NO_SOLUTION_VALUE];
96
+ }
97
+ async function computeItemHash(item) {
98
+ if (item.type === "text") {
99
+ return { ...item, hash: common.hexHash(item.data) };
100
+ } else if (item.type === "image") {
101
+ return { ...item, hash: common.hexHash(await util$1.downloadImage(item.data)) };
102
+ } else {
103
+ throw new common.ProsopoEnvError("CAPTCHA.INVALID_ITEM_FORMAT");
104
+ }
105
+ }
106
+ function matchItemsToSolutions(solutions, items) {
107
+ if (!items) {
108
+ return [];
109
+ }
110
+ return solutions.map((solution) => {
111
+ if (typeof solution === "string") {
112
+ if (!(items == null ? void 0 : items.some((item2) => item2.hash === solution))) {
113
+ throw new common.ProsopoEnvError("CAPTCHA.INVALID_ITEM_HASH");
114
+ }
115
+ return solution;
116
+ }
117
+ const item = util.at(items, solution);
118
+ const hash = item.hash;
119
+ return hash;
120
+ });
121
+ }
122
+ function computeCaptchaSolutionHash(captcha) {
123
+ return common.hexHashArray([captcha.captchaId, captcha.captchaContentId, [...captcha.solution].sort(), captcha.salt]);
124
+ }
125
+ function computePendingRequestHash(captchaIds, userAccount, salt) {
126
+ return common.hexHashArray([...captchaIds.sort(), userAccount, salt]);
127
+ }
128
+ function parseCaptchaAssets(item, assetsResolver) {
129
+ return { ...item, path: (assetsResolver == null ? void 0 : assetsResolver.resolveAsset(item.data).getURL()) || item.data };
130
+ }
131
+ exports.NO_SOLUTION_VALUE = NO_SOLUTION_VALUE;
132
+ exports.captchaSort = captchaSort;
133
+ exports.compareCaptchaSolutions = compareCaptchaSolutions;
134
+ exports.computeCaptchaHash = computeCaptchaHash;
135
+ exports.computeCaptchaSolutionHash = computeCaptchaSolutionHash;
136
+ exports.computeItemHash = computeItemHash;
137
+ exports.computePendingRequestHash = computePendingRequestHash;
138
+ exports.getSolutionValueToHash = getSolutionValueToHash;
139
+ exports.matchItemsToSolutions = matchItemsToSolutions;
140
+ exports.parseAndSortCaptchaSolutions = parseAndSortCaptchaSolutions;
141
+ exports.parseCaptchaAssets = parseCaptchaAssets;
142
+ exports.parseCaptchaDataset = parseCaptchaDataset;
143
+ exports.sortAndComputeHashes = sortAndComputeHashes;
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const merkle = require("./merkle.cjs");
4
+ const common = require("@prosopo/common");
5
+ const util = require("@prosopo/util");
6
+ const captcha = require("./captcha.cjs");
7
+ const logger = common.getLogger(`Info`, `dataset.ts`);
8
+ async function hashDatasetItems(datasetRaw) {
9
+ return datasetRaw.captchas.map(async (captcha$1) => {
10
+ const items = await Promise.all(captcha$1.items.map(async (item) => captcha.computeItemHash(item)));
11
+ return {
12
+ ...captcha$1,
13
+ items
14
+ };
15
+ });
16
+ }
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((captcha2) => {
25
+ const captchaRaw = datasetOriginal.captchas.find((captchaRaw2) => "captchaId" in captchaRaw2 ? captchaRaw2.captchaId === captcha2.captchaId : false);
26
+ if (captchaRaw) {
27
+ return captcha2.items.every((item, index) => item.hash === util.at(captchaRaw.items, index).hash);
28
+ } else {
29
+ return false;
30
+ }
31
+ });
32
+ return hashes.every((hash) => hash);
33
+ }
34
+ async function buildDataset(datasetRaw) {
35
+ var _a, _b;
36
+ logger.info(`Adding solution hashes to dataset`);
37
+ const dataset = await addSolutionHashesToDataset(datasetRaw);
38
+ logger.info(`Building dataset merkle trees`);
39
+ const contentTree = await buildCaptchaTree(dataset, false, false, true);
40
+ const solutionTree = await buildCaptchaTree(dataset, true, true, false);
41
+ dataset.captchas = dataset.captchas.map((captcha2, index) => {
42
+ var _a2, _b2;
43
+ return {
44
+ ...captcha2,
45
+ captchaId: util.at(solutionTree.leaves, index).hash,
46
+ captchaContentId: util.at(contentTree.leaves, index).hash,
47
+ datasetId: (_a2 = solutionTree.root) == null ? void 0 : _a2.hash,
48
+ datasetContentId: (_b2 = contentTree.root) == null ? void 0 : _b2.hash
49
+ };
50
+ });
51
+ dataset.solutionTree = solutionTree.layers;
52
+ dataset.contentTree = contentTree.layers;
53
+ dataset.datasetId = (_a = solutionTree.root) == null ? void 0 : _a.hash;
54
+ dataset.datasetContentId = (_b = contentTree.root) == null ? void 0 : _b.hash;
55
+ return dataset;
56
+ }
57
+ async function buildCaptchaTree(dataset, includeSolution, includeSalt, sortItemHashes) {
58
+ try {
59
+ const tree = new merkle.CaptchaMerkleTree();
60
+ const datasetWithItemHashes = { ...dataset };
61
+ const captchaHashes = datasetWithItemHashes.captchas.map((captcha$1) => captcha.computeCaptchaHash(captcha$1, includeSolution, includeSalt, sortItemHashes));
62
+ tree.build(captchaHashes);
63
+ return tree;
64
+ } catch (err) {
65
+ throw new common.ProsopoEnvError("DATASET.HASH_ERROR");
66
+ }
67
+ }
68
+ async function addSolutionHashesToDataset(datasetRaw) {
69
+ const captchaPromises = datasetRaw.captchas.map(async (captcha$1) => {
70
+ return {
71
+ ...captcha$1,
72
+ items: captcha$1.items,
73
+ // some captcha challenges will not have a solution
74
+ ...captcha$1.solution !== void 0 && { solution: captcha.matchItemsToSolutions(captcha$1.solution, captcha$1.items) }
75
+ };
76
+ });
77
+ const captchas = await Promise.all(captchaPromises);
78
+ return {
79
+ ...datasetRaw,
80
+ captchas
81
+ };
82
+ }
83
+ exports.addSolutionHashesToDataset = addSolutionHashesToDataset;
84
+ exports.buildCaptchaTree = buildCaptchaTree;
85
+ exports.buildDataset = buildDataset;
86
+ exports.hashDatasetItems = hashDatasetItems;
87
+ 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;