@prosopo/procaptcha 0.2.13 → 0.2.15

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/dist/api/Extension.d.ts +0 -10
  2. package/dist/api/Extension.d.ts.map +1 -1
  3. package/dist/api/Extension.js +0 -3
  4. package/dist/api/Extension.js.map +1 -1
  5. package/dist/api/ExtensionWeb2.d.ts +0 -3
  6. package/dist/api/ExtensionWeb2.d.ts.map +1 -1
  7. package/dist/api/ExtensionWeb2.js +9 -17
  8. package/dist/api/ExtensionWeb2.js.map +1 -1
  9. package/dist/api/ExtensionWeb3.d.ts +0 -3
  10. package/dist/api/ExtensionWeb3.d.ts.map +1 -1
  11. package/dist/api/ExtensionWeb3.js +0 -5
  12. package/dist/api/ExtensionWeb3.js.map +1 -1
  13. package/dist/api/errors.js +0 -13
  14. package/dist/api/errors.js.map +1 -1
  15. package/dist/api/handlers.js +0 -15
  16. package/dist/api/handlers.js.map +1 -1
  17. package/dist/api/index.js +0 -13
  18. package/dist/api/index.js.map +1 -1
  19. package/dist/api/sign.js +2 -15
  20. package/dist/api/sign.js.map +1 -1
  21. package/dist/cjs/api/ExtensionWeb2.cjs +17 -16
  22. package/dist/cjs/modules/Manager.cjs +217 -212
  23. package/dist/cjs/modules/ProsopoCaptchaApi.cjs +10 -12
  24. package/dist/index.js +0 -13
  25. package/dist/index.js.map +1 -1
  26. package/dist/modules/Manager.d.ts +0 -3
  27. package/dist/modules/Manager.d.ts.map +1 -1
  28. package/dist/modules/Manager.js +195 -287
  29. package/dist/modules/Manager.js.map +1 -1
  30. package/dist/modules/ProsopoCaptchaApi.d.ts +1 -1
  31. package/dist/modules/ProsopoCaptchaApi.d.ts.map +1 -1
  32. package/dist/modules/ProsopoCaptchaApi.js +1 -28
  33. package/dist/modules/ProsopoCaptchaApi.js.map +1 -1
  34. package/dist/modules/canvas.js +0 -14
  35. package/dist/modules/canvas.js.map +1 -1
  36. package/dist/modules/index.js +0 -13
  37. package/dist/modules/index.js.map +1 -1
  38. package/dist/modules/storage.d.ts +0 -12
  39. package/dist/modules/storage.d.ts.map +1 -1
  40. package/dist/modules/storage.js +0 -25
  41. package/dist/modules/storage.js.map +1 -1
  42. package/dist/tests/mocks/browser.js +0 -13
  43. package/dist/tests/mocks/browser.js.map +1 -1
  44. package/dist/types/api.js +0 -19
  45. package/dist/types/api.js.map +1 -1
  46. package/dist/types/index.js +0 -13
  47. package/dist/types/index.js.map +1 -1
  48. package/dist/types/manager.d.ts +0 -24
  49. package/dist/types/manager.d.ts.map +1 -1
  50. package/dist/utils/index.js +0 -13
  51. package/dist/utils/index.js.map +1 -1
  52. package/dist/utils/utils.js +0 -13
  53. package/dist/utils/utils.js.map +1 -1
  54. package/package.json +10 -8
  55. package/dist/cjs/contracts/captcha/dist/build-extrinsic/captcha.cjs +0 -339
  56. package/dist/cjs/contracts/captcha/dist/contract-info/captcha.cjs +0 -6
  57. package/dist/cjs/contracts/captcha/dist/contracts/captcha.cjs +0 -79
  58. package/dist/cjs/contracts/captcha/dist/data/captcha.json.cjs +0 -3374
  59. package/dist/cjs/contracts/captcha/dist/event-data/captcha.json.cjs +0 -3
  60. package/dist/cjs/contracts/captcha/dist/events/captcha.cjs +0 -23
  61. package/dist/cjs/contracts/captcha/dist/index.cjs +0 -44
  62. package/dist/cjs/contracts/captcha/dist/mixed-methods/captcha.cjs +0 -470
  63. package/dist/cjs/contracts/captcha/dist/query/captcha.cjs +0 -468
  64. package/dist/cjs/contracts/captcha/dist/shared/utils.cjs +0 -31
  65. package/dist/cjs/contracts/captcha/dist/tx-sign-and-send/captcha.cjs +0 -426
  66. package/dist/cjs/contracts/captcha/dist/types-arguments/captcha.cjs +0 -62
  67. package/dist/cjs/packages/datasets/dist/captcha/captcha.cjs +0 -143
  68. package/dist/cjs/packages/datasets/dist/captcha/dataset.cjs +0 -87
  69. package/dist/cjs/packages/datasets/dist/captcha/index.cjs +0 -27
  70. package/dist/cjs/packages/datasets/dist/captcha/merkle.cjs +0 -106
  71. package/dist/cjs/packages/datasets/dist/captcha/util.cjs +0 -16
  72. package/dist/cjs/packages/datasets/dist/index.cjs +0 -2
@@ -1,34 +1,43 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const errors = require("../api/errors.cjs");
4
- const api = require("@polkadot/api");
4
+ const Api = require("@polkadot/api/promise/Api");
5
5
  const types = require("@prosopo/types");
6
- const rxjs = require("rxjs");
6
+ const api = require("@prosopo/api");
7
+ const keyring = require("@polkadot/keyring");
7
8
  const contract = require("@prosopo/contract");
8
9
  const common = require("@prosopo/common");
9
- const api$1 = require("@prosopo/api");
10
- require("../contracts/captcha/dist/index.cjs");
10
+ const ws = require("@polkadot/rpc-provider/ws");
11
+ const contractInfo = require("@prosopo/captcha-contract/contract-info");
11
12
  const util = require("@prosopo/util");
12
- const utilCrypto = require("@polkadot/util-crypto");
13
- const operators = require("rxjs/operators");
13
+ const random = require("@polkadot/util-crypto/random");
14
+ const utils = require("../utils/utils.cjs");
15
+ const string = require("@polkadot/util/string");
14
16
  const ExtensionWeb2 = require("../api/ExtensionWeb2.cjs");
15
17
  const ExtensionWeb3 = require("../api/ExtensionWeb3.cjs");
16
18
  const ProsopoCaptchaApi = require("./ProsopoCaptchaApi.cjs");
17
19
  const storage = require("./storage.cjs");
18
- const captcha = require("../contracts/captcha/dist/contract-info/captcha.cjs");
19
- const defaultState = () => ({
20
- showModal: false,
21
- loading: false,
22
- index: 0,
23
- challenge: void 0,
24
- solutions: void 0,
25
- isHuman: false,
26
- captchaApi: void 0,
27
- account: void 0
28
- });
29
- const buildUpdateState = (state, onStateUpdate) => (nextState) => {
30
- Object.assign(state, nextState);
31
- onStateUpdate(nextState);
20
+ const defaultState = () => {
21
+ return {
22
+ // note order matters! see buildUpdateState. These fields are set in order, so disable modal first, then set loading to false, etc.
23
+ showModal: false,
24
+ loading: false,
25
+ index: 0,
26
+ challenge: void 0,
27
+ solutions: void 0,
28
+ isHuman: false,
29
+ captchaApi: void 0,
30
+ account: void 0
31
+ // don't handle timeout here, this should be handled by the state management
32
+ };
33
+ };
34
+ const buildUpdateState = (state, onStateUpdate) => {
35
+ const updateCurrentState = (nextState) => {
36
+ Object.assign(state, nextState);
37
+ onStateUpdate(nextState);
38
+ console.log("Procaptcha state update:", nextState, "\nResult:", state);
39
+ };
40
+ return updateCurrentState;
32
41
  };
33
42
  const getNetwork = (config) => {
34
43
  const network = config.networks[config.defaultNetwork];
@@ -39,7 +48,7 @@ const getNetwork = (config) => {
39
48
  };
40
49
  function Manager(configOptional, state, onStateUpdate, callbacks) {
41
50
  const alertError = (error) => {
42
- console.error(error);
51
+ console.log(error);
43
52
  alert(error.message);
44
53
  };
45
54
  const events = Object.assign(
@@ -47,7 +56,7 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
47
56
  onAccountNotFound: alertError,
48
57
  onError: alertError,
49
58
  onHuman: (output) => {
50
- console.info("onHuman event triggered", output);
59
+ console.log("onHuman event triggered", output);
51
60
  },
52
61
  onExtensionNotFound: () => {
53
62
  alert("No extension found");
@@ -62,10 +71,10 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
62
71
  alert("Uncompleted challenge has expired, please try again");
63
72
  },
64
73
  onOpen: () => {
65
- console.info("onOpen event triggered");
74
+ console.log("onOpen event triggered");
66
75
  },
67
76
  onClose: () => {
68
- console.info("onClose event triggered");
77
+ console.log("onClose event triggered");
69
78
  }
70
79
  },
71
80
  callbacks
@@ -79,10 +88,16 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
79
88
  }
80
89
  };
81
90
  const updateState = buildUpdateState(state, onStateUpdate);
82
- const getConfig = () => types.ProcaptchaConfigSchema.parse({
83
- ...configOptional,
84
- userAccountAddress: state.account ? state.account.account.address : configOptional.userAccountAddress || ""
85
- });
91
+ const getConfig = () => {
92
+ const config = {
93
+ userAccountAddress: "",
94
+ ...configOptional
95
+ };
96
+ if (state.account) {
97
+ config.userAccountAddress = state.account.account.address;
98
+ }
99
+ return types.ProcaptchaConfigSchema.parse(config);
100
+ };
86
101
  const fallable = async (fn) => {
87
102
  try {
88
103
  await fn();
@@ -93,59 +108,135 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
93
108
  }
94
109
  };
95
110
  const start = async () => {
111
+ console.log("Starting procaptcha");
96
112
  events.onOpen();
97
113
  await fallable(async () => {
98
- if (state.loading || state.isHuman)
114
+ if (state.loading) {
115
+ console.log("Procaptcha already loading");
116
+ return;
117
+ }
118
+ if (state.isHuman) {
119
+ console.log("already human");
99
120
  return;
121
+ }
100
122
  resetState();
101
- updateState({ dappAccount: getConfig().account.address, loading: true });
123
+ updateState({ loading: true });
124
+ const config = getConfig();
125
+ updateState({ dappAccount: config.account.address });
126
+ await utils.sleep(100);
102
127
  const account = await loadAccount();
103
- const contract2 = await loadContract();
104
- if (await checkHumanInContract(contract2, account)) {
105
- handleHumanInContract(account);
128
+ const contract$1 = await loadContract();
129
+ let contractIsHuman = false;
130
+ try {
131
+ contractIsHuman = (await contract$1.query.dappOperatorIsHumanUser(account.account.address, config.solutionThreshold)).value.unwrap().unwrap();
132
+ } catch (error) {
133
+ console.warn(error);
134
+ }
135
+ if (contractIsHuman) {
136
+ updateState({ isHuman: true, loading: false });
137
+ events.onHuman({
138
+ user: account.account.address,
139
+ dapp: getDappAccount()
140
+ });
141
+ setValidChallengeTimeout();
106
142
  return;
107
143
  }
108
144
  const providerUrlFromStorage = storage.getProviderUrl();
145
+ let providerApi;
109
146
  if (providerUrlFromStorage) {
147
+ providerApi = await loadProviderApi(providerUrlFromStorage);
110
148
  try {
111
- const verifyDappUserResponse = await getVerifyDappUserFunction(providerUrlFromStorage, account);
149
+ const verifyDappUserResponse = await providerApi.verifyDappUser(
150
+ account.account.address,
151
+ void 0,
152
+ configOptional.challengeValidLength
153
+ );
112
154
  if (verifyDappUserResponse.solutionApproved) {
113
- handleHumanInCachedProvider(providerUrlFromStorage, account, verifyDappUserResponse);
155
+ updateState({ isHuman: true, loading: false });
156
+ events.onHuman({
157
+ providerUrl: providerUrlFromStorage,
158
+ user: account.account.address,
159
+ dapp: getDappAccount(),
160
+ commitmentId: verifyDappUserResponse.commitmentId
161
+ });
162
+ setValidChallengeTimeout();
114
163
  return;
115
164
  }
116
165
  } catch (err) {
117
166
  console.error("Error contacting provider from storage", providerUrlFromStorage);
118
167
  }
119
168
  }
120
- const randomProviderResponse = await getRandomProviderResponse(contract2, account);
121
- const challenge = await getChallenge(randomProviderResponse, contract2);
169
+ const payload = {
170
+ address: account.account.address,
171
+ data: string.stringToU8a("message"),
172
+ type: "bytes"
173
+ };
174
+ const signed = await account.extension.signer.signRaw(payload);
175
+ console.log("Signature:", signed);
176
+ const getRandomProviderResponse = await contract.wrapQuery(
177
+ contract$1.query.getRandomActiveProvider,
178
+ contract$1.query
179
+ )(account.account.address, getDappAccount());
180
+ const blockNumber = parseInt(getRandomProviderResponse.blockNumber.toString());
181
+ console.log("provider", getRandomProviderResponse);
182
+ const providerUrl = common.trimProviderUrl(getRandomProviderResponse.provider.url.toString());
183
+ providerApi = await loadProviderApi(providerUrl);
184
+ console.log("providerApi", providerApi);
185
+ const captchaApi = await loadCaptchaApi(contract$1, getRandomProviderResponse, providerApi);
186
+ console.log("captchaApi", captchaApi);
187
+ const challenge = await captchaApi.getCaptchaChallenge();
188
+ console.log("challenge", challenge);
122
189
  if (challenge.captchas.length <= 0) {
123
190
  throw new Error("No captchas returned from provider");
124
191
  }
192
+ const timeMillis = challenge.captchas.map((captcha) => captcha.captcha.timeLimitMs || 30 * 1e3).reduce((a, b) => a + b);
193
+ const timeout = setTimeout(() => {
194
+ console.log("challenge expired after " + timeMillis + "ms");
195
+ events.onChallengeExpired();
196
+ updateState({ isHuman: false, showModal: false, loading: false });
197
+ }, timeMillis);
125
198
  updateState({
126
- challenge,
127
199
  index: 0,
128
200
  solutions: challenge.captchas.map(() => []),
201
+ challenge,
129
202
  showModal: true,
130
- timeout: setTimeToComplete(challenge),
131
- blockNumber: getBlockNumberFromProvider(randomProviderResponse)
203
+ timeout,
204
+ blockNumber
132
205
  });
133
206
  });
134
207
  };
135
208
  const submit = async () => {
136
209
  await fallable(async () => {
210
+ console.log("submitting solutions");
137
211
  clearTimeout();
138
- updateState({ showModal: false });
139
212
  if (!state.challenge) {
140
213
  throw new Error("cannot submit, no challenge found");
141
214
  }
142
- const datasetId = getDatasetId();
143
- const salt = utilCrypto.randomAsHex();
144
- const submission = await getCaptchaApi().submitCaptchaSolution(
145
- getAccount().extension.signer,
146
- state.challenge.requestHash,
147
- datasetId,
148
- getSolutionsFromState(salt),
215
+ updateState({ showModal: false });
216
+ const challenge = state.challenge;
217
+ const salt = random.randomAsHex();
218
+ const captchaSolution = state.challenge.captchas.map((captcha, index) => {
219
+ const solution = util.at(state.solutions, index);
220
+ return {
221
+ captchaId: captcha.captcha.captchaId,
222
+ captchaContentId: captcha.captcha.captchaContentId,
223
+ salt,
224
+ solution
225
+ };
226
+ });
227
+ const account = getAccount();
228
+ const blockNumber = getBlockNumber();
229
+ const signer = account.extension.signer;
230
+ const first = util.at(challenge.captchas, 0);
231
+ if (!first.captcha.datasetId) {
232
+ throw new Error("No datasetId set for challenge");
233
+ }
234
+ const captchaApi = getCaptchaApi();
235
+ const submission = await captchaApi.submitCaptchaSolution(
236
+ signer,
237
+ challenge.requestHash,
238
+ first.captcha.datasetId,
239
+ captchaSolution,
149
240
  salt
150
241
  );
151
242
  const isHuman = submission[0].solutionApproved;
@@ -157,20 +248,26 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
157
248
  isHuman,
158
249
  loading: false
159
250
  });
160
- if (isHuman) {
161
- const trimmedUrl = common.trimProviderUrl(getCaptchaApi().provider.provider.url.toString());
251
+ if (state.isHuman) {
252
+ const trimmedUrl = common.trimProviderUrl(captchaApi.provider.provider.url.toString());
162
253
  storage.setProviderUrl(trimmedUrl);
163
254
  events.onHuman({
164
255
  providerUrl: trimmedUrl,
165
- user: getAccount().account.address,
256
+ user: account.account.address,
166
257
  dapp: getDappAccount(),
167
258
  commitmentId: submission[1],
168
- blockNumber: getBlockNumberFromState()
259
+ blockNumber
169
260
  });
170
261
  setValidChallengeTimeout();
171
262
  }
172
263
  });
173
264
  };
265
+ const cancel = async () => {
266
+ console.log("cancel");
267
+ clearTimeout();
268
+ resetState();
269
+ events.onClose();
270
+ };
174
271
  const select = (hash) => {
175
272
  if (!state.challenge) {
176
273
  throw new Error("cannot select, no challenge found");
@@ -178,9 +275,17 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
178
275
  if (state.index >= state.challenge.captchas.length || state.index < 0) {
179
276
  throw new Error("cannot select, round index out of range");
180
277
  }
181
- const solution = util.at(state.solutions, state.index);
182
- handleIsSelected(solution, hash);
183
- updateState({ solutions: state.solutions });
278
+ const index = state.index;
279
+ const solutions = state.solutions;
280
+ const solution = util.at(solutions, index);
281
+ if (solution.includes(hash)) {
282
+ console.log("deselecting", hash);
283
+ solution.splice(solution.indexOf(hash), 1);
284
+ } else {
285
+ console.log("selecting", hash);
286
+ solution.push(hash);
287
+ }
288
+ updateState({ solutions });
184
289
  };
185
290
  const nextRound = () => {
186
291
  if (!state.challenge) {
@@ -189,161 +294,44 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
189
294
  if (state.index + 1 >= state.challenge.captchas.length) {
190
295
  throw new Error("cannot proceed to next round, already at last round");
191
296
  }
297
+ console.log("proceeding to next round");
192
298
  updateState({ index: state.index + 1 });
193
299
  };
194
300
  const loadCaptchaApi = async (contract2, provider, providerApi) => {
195
- updateState({
196
- captchaApi: new ProsopoCaptchaApi.ProsopoCaptchaApi(
197
- getAccount().account.address,
198
- contract2,
199
- provider,
200
- providerApi,
201
- getConfig().web2,
202
- getDappAccount()
203
- )
204
- });
205
- return getCaptchaApi();
206
- };
207
- const createBlockObservable = () => new rxjs.Observable(
208
- (subscriber) => () => api.ApiPromise.create({ provider: new api.WsProvider(getNetwork(getConfig()).endpoint) }).then((api2) => {
209
- api2.rpc.chain.subscribeNewHeads((header) => {
210
- subscriber.next(header);
211
- });
212
- }).catch((error) => {
213
- subscriber.error(error);
214
- })
215
- );
216
- const loadAccount = async () => {
217
301
  const config = getConfig();
218
- if (!config.web2 && !config.userAccountAddress) {
219
- throw new Error("Account address has not been set for web3 mode");
220
- }
221
- const ext = config.web2 ? new ExtensionWeb2() : new ExtensionWeb3();
222
- const account = await ext.getAccount(config);
223
- storage.setAccount(account.account.address);
224
- updateState({ account });
225
- return getAccount();
302
+ const captchaApi = new ProsopoCaptchaApi.ProsopoCaptchaApi(
303
+ getAccount().account.address,
304
+ contract2,
305
+ provider,
306
+ providerApi,
307
+ config.web2,
308
+ getDappAccount()
309
+ );
310
+ updateState({ captchaApi });
311
+ return getCaptchaApi();
226
312
  };
227
313
  const loadProviderApi = async (providerUrl) => {
228
314
  const config = getConfig();
315
+ const network = getNetwork(config);
229
316
  if (!config.account.address) {
230
317
  throw new common.ProsopoEnvError("GENERAL.SITE_KEY_MISSING");
231
318
  }
232
- return new api$1.ProviderApi(getNetwork(config), providerUrl, config.account.address);
233
- };
234
- const loadContract = async () => {
235
- const network = getNetwork(getConfig());
236
- const api$12 = await api.ApiPromise.create({ provider: new api.WsProvider(network.endpoint) });
237
- const type = "sr25519";
238
- return new contract.ProsopoCaptchaContract(
239
- api$12,
240
- JSON.parse(captcha.ContractAbi),
241
- network.contract.address,
242
- "prosopo",
243
- 0,
244
- new api.Keyring({ type, ss58Format: api$12.registry.chainSS58 }).addFromAddress(getAccount().account.address)
245
- );
246
- };
247
- function handleIsSelected(solution, hash) {
248
- if (solution.includes(hash)) {
249
- solution.splice(solution.indexOf(hash), 1);
250
- } else {
251
- solution.push(hash);
252
- }
253
- }
254
- function getSolutionsFromState(salt) {
255
- if (!state.challenge) {
256
- throw new Error("cannot get solutions, no challenge found");
257
- }
258
- return state.challenge.captchas.map((captcha2, index) => ({
259
- captchaId: captcha2.captcha.captchaId,
260
- captchaContentId: captcha2.captcha.captchaContentId,
261
- salt,
262
- solution: util.at(state.solutions, index)
263
- }));
264
- }
265
- function handleHumanInCachedProvider(providerUrlFromStorage, account, verifyDappUserResponse) {
266
- updateState({ isHuman: true, loading: false });
267
- events.onHuman({
268
- providerUrl: providerUrlFromStorage,
269
- user: account.account.address,
270
- dapp: getDappAccount(),
271
- commitmentId: verifyDappUserResponse.commitmentId
272
- });
273
- setValidChallengeTimeout();
274
- }
275
- function getVerifyDappUserFunction(providerUrlFromStorage, account) {
276
- return loadProviderApi(providerUrlFromStorage).then(
277
- (providerApi) => providerApi.verifyDappUser(account.account.address)
278
- );
279
- }
280
- function handleHumanInContract(account) {
281
- updateState({ isHuman: true, loading: false });
282
- events.onHuman({
283
- user: account.account.address,
284
- dapp: getDappAccount()
285
- });
286
- setValidChallengeTimeout();
287
- }
288
- async function checkHumanInContract(contract2, account) {
289
- try {
290
- return await contract2.query.dappOperatorIsHumanUser(account.account.address, getConfig().solutionThreshold).then((res) => res.value.unwrap().unwrap());
291
- } catch (err) {
292
- console.error(err);
293
- return false;
294
- }
295
- }
296
- function getChallenge(getRandomProviderResponse2, contract2) {
297
- return loadProviderApi(common.trimProviderUrl(getRandomProviderResponse2.provider.url.toString())).then((api2) => loadCaptchaApi(contract2, getRandomProviderResponse2, api2)).then((captchaApi) => captchaApi.getCaptchaChallenge());
298
- }
299
- function getRandomProviderResponse(contract$1, account) {
300
- return rxjs.lastValueFrom(
301
- rxjs.from(
302
- contract.wrapQuery(contract$1.query.getRandomActiveProvider, contract$1.query)(
303
- account.account.address,
304
- getDappAccount()
305
- )
306
- ).pipe(
307
- operators.retry({
308
- count: 3,
309
- delay: (error, retryCount) => {
310
- console.error(`Attempt ${retryCount} failed. Retrying on next block. Error: ${error}`);
311
- return createBlockObservable().pipe(operators.take(1));
312
- },
313
- resetOnSuccess: true
314
- })
315
- )
316
- );
317
- }
318
- function setTimeToComplete(challenge) {
319
- return setTimeout(
320
- () => {
321
- events.onChallengeExpired();
322
- updateState({ isHuman: false, showModal: false, loading: false });
323
- },
324
- challenge.captchas.map((captcha2) => captcha2.captcha.timeLimitMs || 30 * 1e3).reduce((a, b) => a + b)
325
- );
326
- }
327
- const setValidChallengeTimeout = () => {
328
- updateState({
329
- successfullChallengeTimeout: setTimeout(
330
- () => {
331
- updateState({ isHuman: false });
332
- events.onExpired();
333
- },
334
- configOptional.challengeValidLength || 120 * 1e3
335
- )
336
- });
337
- };
338
- const cancel = async () => {
339
- clearTimeout();
340
- resetState();
341
- events.onClose();
319
+ return new api.ProviderApi(network, providerUrl, config.account.address);
342
320
  };
343
321
  const clearTimeout = () => {
344
322
  window.clearTimeout(state.timeout);
345
323
  updateState({ timeout: void 0 });
346
324
  };
325
+ const setValidChallengeTimeout = () => {
326
+ console.log("setting valid challenge timeout");
327
+ const timeMillis = configOptional.challengeValidLength || 120 * 1e3;
328
+ const successfullChallengeTimeout = setTimeout(() => {
329
+ console.log("valid challenge expired after " + timeMillis + "ms");
330
+ updateState({ isHuman: false });
331
+ events.onExpired();
332
+ }, timeMillis);
333
+ updateState({ successfullChallengeTimeout });
334
+ };
347
335
  const resetState = () => {
348
336
  clearTimeout();
349
337
  updateState(defaultState());
@@ -354,37 +342,54 @@ function Manager(configOptional, state, onStateUpdate, callbacks) {
354
342
  }
355
343
  return state.captchaApi;
356
344
  };
345
+ const loadAccount = async () => {
346
+ const config = getConfig();
347
+ if (!config.web2 && !config.userAccountAddress) {
348
+ throw new Error("Account address has not been set for web3 mode");
349
+ }
350
+ const ext = config.web2 ? new ExtensionWeb2() : new ExtensionWeb3();
351
+ const account = await ext.getAccount(config);
352
+ storage.setAccount(account.account.address);
353
+ console.log("Using account:", account);
354
+ updateState({ account });
355
+ return getAccount();
356
+ };
357
357
  const getAccount = () => {
358
358
  if (!state.account) {
359
359
  throw new Error("Account not loaded");
360
360
  }
361
- return state.account;
361
+ const account = state.account;
362
+ return account;
362
363
  };
363
364
  const getDappAccount = () => {
364
365
  if (!state.dappAccount) {
365
366
  throw new common.ProsopoEnvError("GENERAL.SITE_KEY_MISSING");
366
367
  }
367
- return state.dappAccount;
368
+ const dappAccount = state.dappAccount;
369
+ return dappAccount;
368
370
  };
369
- const getBlockNumberFromState = () => {
371
+ const getBlockNumber = () => {
370
372
  if (!state.blockNumber) {
371
373
  throw new Error("Account not loaded");
372
374
  }
373
- return state.blockNumber;
375
+ const blockNumber = state.blockNumber;
376
+ return blockNumber;
377
+ };
378
+ const loadContract = async () => {
379
+ const config = getConfig();
380
+ const network = getNetwork(config);
381
+ const api2 = await Api.ApiPromise.create({ provider: new ws.WsProvider(network.endpoint), initWasm: false });
382
+ const type = "sr25519";
383
+ const keyring$1 = new keyring.Keyring({ type, ss58Format: api2.registry.chainSS58 });
384
+ return new contract.ProsopoCaptchaContract(
385
+ api2,
386
+ JSON.parse(contractInfo.ContractAbi),
387
+ network.contract.address,
388
+ "prosopo",
389
+ 0,
390
+ keyring$1.addFromAddress(getAccount().account.address)
391
+ );
374
392
  };
375
- function getBlockNumberFromProvider(getRandomProviderResponse2) {
376
- return parseInt(getRandomProviderResponse2.blockNumber.toString());
377
- }
378
- function getDatasetId() {
379
- if (!state.challenge) {
380
- throw new Error("cannot get datasetId, no challenge found");
381
- }
382
- const datasetId = util.at(state.challenge.captchas, 0).captcha.datasetId;
383
- if (!datasetId) {
384
- throw new Error("No datasetId set for challenge");
385
- }
386
- return datasetId;
387
- }
388
393
  return {
389
394
  start,
390
395
  cancel,
@@ -1,12 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
- require("../packages/datasets/dist/index.cjs");
3
+ const datasets = require("@prosopo/datasets");
4
4
  const handlers = require("../api/handlers.cjs");
5
5
  const common = require("@prosopo/common");
6
6
  const util = require("@prosopo/util");
7
- const util$1 = require("@polkadot/util");
8
- const merkle = require("../packages/datasets/dist/captcha/merkle.cjs");
9
- const captcha = require("../packages/datasets/dist/captcha/captcha.cjs");
7
+ const string = require("@polkadot/util/string");
10
8
  class ProsopoCaptchaApi {
11
9
  constructor(userAccount, contract, provider, providerApi, web2, dappAccount) {
12
10
  this.userAccount = userAccount;
@@ -37,7 +35,7 @@ class ProsopoCaptchaApi {
37
35
  if (!verifyCaptchaData(captchaWithProof)) {
38
36
  throw new common.ProsopoEnvError("CAPTCHA.INVALID_CAPTCHA_CHALLENGE");
39
37
  }
40
- if (!merkle.verifyProof(captchaWithProof.captcha.captchaContentId, captchaWithProof.proof)) {
38
+ if (!datasets.verifyProof(captchaWithProof.captcha.captchaContentId, captchaWithProof.proof)) {
41
39
  throw new common.ProsopoEnvError("CAPTCHA.INVALID_CAPTCHA_CHALLENGE");
42
40
  }
43
41
  }
@@ -45,8 +43,8 @@ class ProsopoCaptchaApi {
45
43
  return;
46
44
  }
47
45
  async submitCaptchaSolution(signer, requestHash, datasetId, solutions, salt) {
48
- const tree = new merkle.CaptchaMerkleTree();
49
- const captchasHashed = solutions.map((captcha$1) => captcha.computeCaptchaSolutionHash(captcha$1));
46
+ const tree = new datasets.CaptchaMerkleTree();
47
+ const captchasHashed = solutions.map((captcha) => datasets.computeCaptchaSolutionHash(captcha));
50
48
  tree.build(captchasHashed);
51
49
  const commitmentId = tree.root.hash;
52
50
  console.log("solveCaptchaChallenge commitmentId", commitmentId);
@@ -58,7 +56,7 @@ class ProsopoCaptchaApi {
58
56
  }
59
57
  const signed = await signer.signRaw({
60
58
  address: this.userAccount,
61
- data: util$1.stringToHex(requestHash),
59
+ data: string.stringToHex(requestHash),
62
60
  type: "bytes"
63
61
  });
64
62
  signature = signed.signature;
@@ -79,15 +77,15 @@ class ProsopoCaptchaApi {
79
77
  }
80
78
  }
81
79
  async function verifyCaptchaData(captchaWithProof) {
82
- const captcha$1 = captchaWithProof.captcha;
80
+ const captcha = captchaWithProof.captcha;
83
81
  const proof = captchaWithProof.proof;
84
- if (!(await Promise.all(captcha$1.items.map(async (item) => (await captcha.computeItemHash(item)).hash === item.hash))).every(
82
+ if (!(await Promise.all(captcha.items.map(async (item) => (await datasets.computeItemHash(item)).hash === item.hash))).every(
85
83
  (hash) => hash === true
86
84
  )) {
87
85
  return false;
88
86
  }
89
- const captchaHash = captcha.computeCaptchaHash(captcha$1, false, false, false);
90
- if (captchaHash !== captcha$1.captchaContentId) {
87
+ const captchaHash = datasets.computeCaptchaHash(captcha, false, false, false);
88
+ if (captchaHash !== captcha.captchaContentId) {
91
89
  return false;
92
90
  }
93
91
  return util.at(proof, 0).indexOf(captchaHash) !== -1;
package/dist/index.js CHANGED
@@ -1,16 +1,3 @@
1
- // Copyright 2021-2023 Prosopo (UK) Ltd.
2
- //
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
1
  export * from './api/index.js';
15
2
  export * from './modules/index.js';
16
3
  export * from './types/index.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wCAAwC;AACxC,EAAE;AACF,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,iDAAiD;AACjD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AACjC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA"}
@@ -10,9 +10,6 @@ export declare const getNetwork: (config: ProcaptchaClientConfigOutput) => {
10
10
  pairType: "sr25519" | "ed25519" | "ecdsa" | "ethereum";
11
11
  ss58Format: number;
12
12
  };
13
- /**
14
- * The state operator. This is used to mutate the state of Procaptcha during the captcha process. State updates are published via the onStateUpdate callback. This should be used by frontends, e.g. react, to maintain the state of Procaptcha across renders.
15
- */
16
13
  export declare function Manager(configOptional: ProcaptchaConfigOptional, state: ProcaptchaState, onStateUpdate: ProcaptchaStateUpdateFn, callbacks: ProcaptchaCallbacks): {
17
14
  start: () => Promise<void>;
18
15
  cancel: () => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"Manager.d.ts","sourceRoot":"","sources":["../../src/modules/Manager.ts"],"names":[],"mappings":"AAaA,OAAO,EAEH,mBAAmB,EACnB,wBAAwB,EAExB,eAAe,EACf,uBAAuB,EAC1B,MAAM,qBAAqB,CAAA;AAG5B,OAAO,EAAmB,4BAA4B,EAA0B,MAAM,gBAAgB,CAAA;AAetG,eAAO,MAAM,YAAY,QAAO,QAAQ,eAAe,CASrD,CAAA;AAQF,eAAO,MAAM,UAAU,WAAY,4BAA4B;;;;;;;;CAM9D,CAAA;AAED;;GAEG;AACH,wBAAgB,OAAO,CACnB,cAAc,EAAE,wBAAwB,EACxC,KAAK,EAAE,eAAe,EACtB,aAAa,EAAE,uBAAuB,EACtC,SAAS,EAAE,mBAAmB;;;;mBAqLR,MAAM;;EA4V/B"}
1
+ {"version":3,"file":"Manager.d.ts","sourceRoot":"","sources":["../../src/modules/Manager.ts"],"names":[],"mappings":"AAaA,OAAO,EAEH,mBAAmB,EACnB,wBAAwB,EAExB,eAAe,EACf,uBAAuB,EAC1B,MAAM,qBAAqB,CAAA;AAG5B,OAAO,EAGH,4BAA4B,EAE/B,MAAM,gBAAgB,CAAA;AAmBvB,eAAO,MAAM,YAAY,QAAO,QAAQ,eAAe,CAatD,CAAA;AAgBD,eAAO,MAAM,UAAU,WAAY,4BAA4B;;;;;;;;CAM9D,CAAA;AAKD,wBAAgB,OAAO,CACnB,cAAc,EAAE,wBAAwB,EACxC,KAAK,EAAE,eAAe,EACtB,aAAa,EAAE,uBAAuB,EACtC,SAAS,EAAE,mBAAmB;;;;mBAuTR,MAAM;;EA+K/B"}