@prosopo/procaptcha 0.1.18 → 0.2.0

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 (89) hide show
  1. package/dist/api/Extension.d.ts +16 -0
  2. package/dist/api/Extension.d.ts.map +1 -0
  3. package/dist/api/Extension.js +6 -0
  4. package/dist/api/Extension.js.map +1 -0
  5. package/dist/api/ExtensionWeb2.d.ts +13 -0
  6. package/dist/api/ExtensionWeb2.d.ts.map +1 -0
  7. package/dist/api/ExtensionWeb2.js +97 -0
  8. package/dist/api/ExtensionWeb2.js.map +1 -0
  9. package/dist/api/ExtensionWeb3.d.ts +10 -0
  10. package/dist/api/ExtensionWeb3.d.ts.map +1 -0
  11. package/dist/api/ExtensionWeb3.js +29 -0
  12. package/dist/api/ExtensionWeb3.js.map +1 -0
  13. package/dist/api/HttpClientBase.d.ts +9 -0
  14. package/dist/api/HttpClientBase.d.ts.map +1 -0
  15. package/dist/api/HttpClientBase.js +28 -0
  16. package/dist/api/HttpClientBase.js.map +1 -0
  17. package/dist/api/errors.d.ts +16 -0
  18. package/dist/api/errors.d.ts.map +1 -0
  19. package/dist/api/errors.js +39 -0
  20. package/dist/api/errors.js.map +1 -0
  21. package/dist/api/handlers.d.ts +6 -0
  22. package/dist/api/handlers.d.ts.map +1 -0
  23. package/dist/api/handlers.js +9 -0
  24. package/dist/api/handlers.js.map +1 -0
  25. package/dist/api/index.d.ts +4 -0
  26. package/dist/api/index.d.ts.map +1 -0
  27. package/dist/api/index.js +17 -0
  28. package/dist/api/index.js.map +1 -0
  29. package/dist/api/sign.d.ts +5 -0
  30. package/dist/api/sign.d.ts.map +1 -0
  31. package/dist/api/sign.js +25 -0
  32. package/dist/api/sign.js.map +1 -0
  33. package/dist/index.d.ts +5 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +18 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/modules/Manager.d.ts +22 -0
  38. package/dist/modules/Manager.d.ts.map +1 -0
  39. package/dist/modules/Manager.js +421 -0
  40. package/dist/modules/Manager.js.map +1 -0
  41. package/dist/modules/ProsopoCaptchaApi.d.ts +21 -0
  42. package/dist/modules/ProsopoCaptchaApi.d.ts.map +1 -0
  43. package/dist/modules/ProsopoCaptchaApi.js +100 -0
  44. package/dist/modules/ProsopoCaptchaApi.js.map +1 -0
  45. package/dist/modules/canvas.d.ts +13 -0
  46. package/dist/modules/canvas.d.ts.map +1 -0
  47. package/dist/modules/canvas.js +359 -0
  48. package/dist/modules/canvas.js.map +1 -0
  49. package/dist/modules/index.d.ts +3 -0
  50. package/dist/modules/index.d.ts.map +1 -0
  51. package/dist/modules/index.js +16 -0
  52. package/dist/modules/index.js.map +1 -0
  53. package/dist/modules/storage.d.ts +24 -0
  54. package/dist/modules/storage.d.ts.map +1 -0
  55. package/dist/modules/storage.js +46 -0
  56. package/dist/modules/storage.js.map +1 -0
  57. package/dist/types/api.d.ts +35 -0
  58. package/dist/types/api.d.ts.map +1 -0
  59. package/dist/types/api.js +21 -0
  60. package/dist/types/api.js.map +1 -0
  61. package/dist/types/client.d.ts +5 -0
  62. package/dist/types/client.d.ts.map +1 -0
  63. package/dist/types/client.js +2 -0
  64. package/dist/types/client.js.map +1 -0
  65. package/dist/types/contract.d.ts +5 -0
  66. package/dist/types/contract.d.ts.map +1 -0
  67. package/dist/types/contract.js +2 -0
  68. package/dist/types/contract.js.map +1 -0
  69. package/dist/types/index.d.ts +5 -0
  70. package/dist/types/index.d.ts.map +1 -0
  71. package/dist/types/index.js +18 -0
  72. package/dist/types/index.js.map +1 -0
  73. package/dist/types/manager.d.ts +62 -0
  74. package/dist/types/manager.d.ts.map +1 -0
  75. package/dist/types/manager.js +9 -0
  76. package/dist/types/manager.js.map +1 -0
  77. package/dist/types/utils.d.ts +2 -0
  78. package/dist/types/utils.d.ts.map +1 -0
  79. package/dist/types/utils.js +2 -0
  80. package/dist/types/utils.js.map +1 -0
  81. package/dist/utils/index.d.ts +2 -0
  82. package/dist/utils/index.d.ts.map +1 -0
  83. package/dist/utils/index.js +15 -0
  84. package/dist/utils/index.js.map +1 -0
  85. package/dist/utils/utils.d.ts +2 -0
  86. package/dist/utils/utils.d.ts.map +1 -0
  87. package/dist/utils/utils.js +17 -0
  88. package/dist/utils/utils.js.map +1 -0
  89. package/package.json +7 -7
@@ -0,0 +1,421 @@
1
+ import { AccountNotFoundError } from '../api/errors.js';
2
+ import { ApiPromise, Keyring } from '@polkadot/api';
3
+ import { ProviderApi } from '@prosopo/api';
4
+ import { ProsopoCaptchaContract, abiJson, wrapQuery } from '@prosopo/contract';
5
+ import { WsProvider } from '@polkadot/rpc-provider';
6
+ import { at } from '@prosopo/util';
7
+ import { randomAsHex } from '@polkadot/util-crypto';
8
+ import { sleep } from '../utils/utils.js';
9
+ import { stringToU8a } from '@polkadot/util';
10
+ import { trimProviderUrl } from '@prosopo/common';
11
+ import ExtensionWeb2 from '../api/ExtensionWeb2.js';
12
+ import ExtensionWeb3 from '../api/ExtensionWeb3.js';
13
+ import ProsopoCaptchaApi from './ProsopoCaptchaApi.js';
14
+ import storage from './storage.js';
15
+ export const defaultState = () => {
16
+ return {
17
+ // note order matters! see buildUpdateState. These fields are set in order, so disable modal first, then set loading to false, etc.
18
+ showModal: false,
19
+ loading: false,
20
+ challenge: undefined,
21
+ solutions: [],
22
+ index: -1,
23
+ isHuman: false,
24
+ captchaApi: undefined,
25
+ account: undefined,
26
+ // don't handle timeout here, this should be handled by the state management
27
+ };
28
+ };
29
+ const buildUpdateState = (state, onStateUpdate) => {
30
+ const updateCurrentState = (nextState) => {
31
+ // mutate the current state. Note that this is in order of properties in the nextState object.
32
+ // e.g. given {b: 2, c: 3, a: 1}, b will be set, then c, then a. This is because JS stores fields in insertion order by default, unless you override it with a class or such by changing the key enumeration order.
33
+ Object.assign(state, nextState);
34
+ // then call the update function for the frontend to do the same
35
+ onStateUpdate(nextState);
36
+ console.log('Procaptcha state update:', nextState, '\nResult:', state);
37
+ };
38
+ return updateCurrentState;
39
+ };
40
+ export const getNetwork = (config) => {
41
+ const network = config.networks[config.defaultEnvironment];
42
+ if (!network) {
43
+ throw new Error(`No network found for environment ${config.defaultEnvironment}`);
44
+ }
45
+ return network;
46
+ };
47
+ /**
48
+ * 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.
49
+ */
50
+ export function Manager(configOptional, state, onStateUpdate, callbacks) {
51
+ // events are emitted at various points during the captcha process. These each have default behaviours below which can be overridden by the frontend using callbacks.
52
+ const alertError = (error) => {
53
+ console.log(error);
54
+ alert(error.message);
55
+ };
56
+ const events = Object.assign({
57
+ onAccountNotFound: alertError,
58
+ onError: alertError,
59
+ onHuman: (output) => {
60
+ console.log('onHuman event triggered', output);
61
+ },
62
+ onExtensionNotFound: () => {
63
+ alert('No extension found');
64
+ },
65
+ onExpired: () => {
66
+ alert('Challenge has expired, please try again');
67
+ },
68
+ onFailed: () => {
69
+ alert('Captcha challenge failed. Please try again');
70
+ },
71
+ }, callbacks);
72
+ const dispatchErrorEvent = (err) => {
73
+ const error = err instanceof Error ? err : new Error(String(err));
74
+ if (error instanceof AccountNotFoundError) {
75
+ events.onAccountNotFound(error.message);
76
+ }
77
+ else {
78
+ events.onError(error);
79
+ }
80
+ };
81
+ // get the state update mechanism
82
+ const updateState = buildUpdateState(state, onStateUpdate);
83
+ /**
84
+ * Build the config on demand, using the optional config passed in from the outside. State may override various
85
+ * config values depending on the state of the captcha process. E.g. if the process has been started using account
86
+ * "ABC" and then the user changes account to "DEF" via the optional config prop, the account in use will not change.
87
+ * This is because the captcha process has already been started using account "ABC".
88
+ * @returns the config for procaptcha
89
+ */
90
+ const getConfig = () => {
91
+ const config = {
92
+ userAccountAddress: '',
93
+ ...configOptional,
94
+ };
95
+ // overwrite the account in use with the one in state if it exists. Reduces likelihood of bugs where the user
96
+ // changes account in the middle of the captcha process.
97
+ if (state.account) {
98
+ config.userAccountAddress = state.account.account.address;
99
+ }
100
+ return config;
101
+ };
102
+ const fallable = async (fn) => {
103
+ try {
104
+ await fn();
105
+ }
106
+ catch (err) {
107
+ console.error(err);
108
+ // dispatch relevant error event
109
+ dispatchErrorEvent(err);
110
+ // hit an error, disallow user's claim to be human
111
+ updateState({ isHuman: false, showModal: false, loading: false });
112
+ }
113
+ };
114
+ /**
115
+ * Called on start of user verification. This is when the user ticks the box to claim they are human.
116
+ */
117
+ const start = async () => {
118
+ console.log('Starting procaptcha');
119
+ await fallable(async () => {
120
+ if (state.loading) {
121
+ console.log('Procaptcha already loading');
122
+ return;
123
+ }
124
+ if (state.isHuman) {
125
+ console.log('already human');
126
+ return;
127
+ }
128
+ resetState();
129
+ // set the loading flag to true (allow UI to show some sort of loading / pending indicator while we get the captcha process going)
130
+ updateState({ loading: true });
131
+ // snapshot the config into the state
132
+ const config = getConfig();
133
+ updateState({ dappAccount: config.account.address });
134
+ // allow UI to catch up with the loading state
135
+ await sleep(100);
136
+ // check accounts / setup accounts
137
+ const account = await loadAccount();
138
+ // account has been found, check if account is already marked as human
139
+ // first, ask the smart contract
140
+ const contract = await loadContract();
141
+ // We don't need to show CAPTCHA challenges if the user is determined as human by the contract
142
+ let contractIsHuman = false;
143
+ try {
144
+ contractIsHuman = (await contract.query.dappOperatorIsHumanUser(account.account.address, config.solutionThreshold)).value
145
+ .unwrap()
146
+ .unwrap();
147
+ }
148
+ catch (error) {
149
+ console.warn(error);
150
+ }
151
+ if (contractIsHuman) {
152
+ updateState({ isHuman: true, loading: false });
153
+ events.onHuman({
154
+ user: account.account.address,
155
+ dapp: config.account.address,
156
+ });
157
+ return;
158
+ }
159
+ // Check if there is a provider in local storage or get a random one from the contract
160
+ const providerUrlFromStorage = storage.getProviderUrl();
161
+ let providerApi;
162
+ if (providerUrlFromStorage) {
163
+ providerApi = await loadProviderApi(providerUrlFromStorage);
164
+ // if the provider was already in storage, the user may have already solved some captchas but they have not been put on chain yet
165
+ // so contact the provider to check if this is the case
166
+ try {
167
+ const verifyDappUserResponse = await providerApi.verifyDappUser(account.account.address);
168
+ if (verifyDappUserResponse.solutionApproved) {
169
+ updateState({ isHuman: true, loading: false });
170
+ events.onHuman({
171
+ providerUrl: providerUrlFromStorage,
172
+ user: account.account.address,
173
+ dapp: config.account.address,
174
+ commitmentId: verifyDappUserResponse.commitmentId,
175
+ });
176
+ return;
177
+ }
178
+ }
179
+ catch (err) {
180
+ // if the provider is down, we should continue with the process of selecting a random provider
181
+ console.error('Error contacting provider from storage', providerUrlFromStorage);
182
+ // continue as if the provider was not in storage
183
+ }
184
+ }
185
+ const payload = {
186
+ address: account.account.address,
187
+ data: stringToU8a('message'),
188
+ type: 'bytes',
189
+ };
190
+ const signed = await account.extension.signer.signRaw(payload);
191
+ console.log('Signature:', signed);
192
+ // get a random provider
193
+ const getRandomProviderResponse = await wrapQuery(contract.query.getRandomActiveProvider, contract.query)(account.account.address, config.account.address);
194
+ const blockNumber = getRandomProviderResponse.blockNumber;
195
+ console.log('provider', getRandomProviderResponse);
196
+ const providerUrl = trimProviderUrl(getRandomProviderResponse.provider.url.toString());
197
+ // get the provider api inst
198
+ providerApi = await loadProviderApi(providerUrl);
199
+ console.log('providerApi', providerApi);
200
+ // get the captcha challenge and begin the challenge
201
+ const captchaApi = await loadCaptchaApi(contract, getRandomProviderResponse, providerApi);
202
+ console.log('captchaApi', captchaApi);
203
+ const challenge = await captchaApi.getCaptchaChallenge();
204
+ console.log('challenge', challenge);
205
+ if (challenge.captchas.length <= 0) {
206
+ throw new Error('No captchas returned from provider');
207
+ }
208
+ // setup timeout
209
+ const timeMillis = challenge.captchas
210
+ .map((captcha) => captcha.captcha.timeLimitMs || 30 * 1000)
211
+ .reduce((a, b) => a + b);
212
+ const timeout = setTimeout(() => {
213
+ console.log('challenge expired after ' + timeMillis + 'ms');
214
+ events.onExpired();
215
+ // expired, disallow user's claim to be human
216
+ updateState({ isHuman: false, showModal: false, loading: false });
217
+ }, timeMillis);
218
+ // update state with new challenge
219
+ updateState({
220
+ index: 0,
221
+ solutions: challenge.captchas.map(() => []),
222
+ challenge,
223
+ showModal: true,
224
+ timeout,
225
+ blockNumber,
226
+ });
227
+ });
228
+ };
229
+ const submit = async () => {
230
+ await fallable(async () => {
231
+ console.log('submitting solutions');
232
+ // disable the time limit, user has submitted their solution in time
233
+ clearTimeout();
234
+ if (!state.challenge) {
235
+ throw new Error('cannot submit, no challenge found');
236
+ }
237
+ // hide the modal, no further input required from user
238
+ updateState({ showModal: false });
239
+ const challenge = state.challenge;
240
+ const salt = randomAsHex();
241
+ // append solution to each captcha in the challenge
242
+ const captchaSolution = state.challenge.captchas.map((captcha, index) => {
243
+ const solution = at(state.solutions, index);
244
+ return {
245
+ captchaId: captcha.captcha.captchaId,
246
+ captchaContentId: captcha.captcha.captchaContentId,
247
+ salt,
248
+ solution,
249
+ };
250
+ });
251
+ const account = getAccount();
252
+ const blockNumber = getBlockNumber();
253
+ const signer = account.extension.signer;
254
+ const first = at(challenge.captchas, 0);
255
+ if (!first.captcha.datasetId) {
256
+ throw new Error('No datasetId set for challenge');
257
+ }
258
+ const captchaApi = getCaptchaApi();
259
+ // send the commitment to the provider
260
+ const submission = await captchaApi.submitCaptchaSolution(signer, challenge.requestHash, first.captcha.datasetId, captchaSolution, salt);
261
+ // mark as is human if solution has been approved
262
+ const isHuman = submission[0].solutionApproved;
263
+ if (!isHuman) {
264
+ // user failed the captcha for some reason according to the provider
265
+ events.onFailed();
266
+ }
267
+ // update the state with the result of the submission
268
+ updateState({
269
+ submission,
270
+ isHuman,
271
+ loading: false,
272
+ });
273
+ if (state.isHuman) {
274
+ const trimmedUrl = trimProviderUrl(captchaApi.provider.provider.url.toString());
275
+ // cache this provider for future use
276
+ storage.setProviderUrl(trimmedUrl);
277
+ events.onHuman({
278
+ providerUrl: trimmedUrl,
279
+ user: account.account.address,
280
+ dapp: getDappAccount(),
281
+ commitmentId: submission[1],
282
+ blockNumber,
283
+ });
284
+ }
285
+ });
286
+ };
287
+ const cancel = async () => {
288
+ console.log('cancel');
289
+ // disable the time limit
290
+ clearTimeout();
291
+ // abandon the captcha process
292
+ resetState();
293
+ };
294
+ /**
295
+ * (De)Select an image from the solution for the current round. If the hash is already in the solutions list, it will be removed (deselected) and if not it will be added (selected).
296
+ * @param hash the hash of the image
297
+ */
298
+ const select = (hash) => {
299
+ if (!state.challenge) {
300
+ throw new Error('cannot select, no challenge found');
301
+ }
302
+ if (state.index >= state.challenge.captchas.length || state.index < 0) {
303
+ throw new Error('cannot select, round index out of range');
304
+ }
305
+ const index = state.index;
306
+ const solutions = state.solutions;
307
+ const solution = at(solutions, index);
308
+ if (solution.includes(hash)) {
309
+ console.log('deselecting', hash);
310
+ // remove the hash from the solution
311
+ solution.splice(solution.indexOf(hash), 1);
312
+ }
313
+ else {
314
+ console.log('selecting', hash);
315
+ // add the hash to the solution
316
+ solution.push(hash);
317
+ }
318
+ updateState({ solutions });
319
+ };
320
+ /**
321
+ * Proceed to the next round of the challenge.
322
+ */
323
+ const nextRound = () => {
324
+ if (!state.challenge) {
325
+ throw new Error('cannot proceed to next round, no challenge found');
326
+ }
327
+ if (state.index + 1 >= state.challenge.captchas.length) {
328
+ throw new Error('cannot proceed to next round, already at last round');
329
+ }
330
+ console.log('proceeding to next round');
331
+ updateState({ index: state.index + 1 });
332
+ };
333
+ const loadCaptchaApi = async (contract, provider, providerApi) => {
334
+ const config = getConfig();
335
+ // setup the captcha api to carry out a challenge
336
+ const captchaApi = new ProsopoCaptchaApi(getAccount().account.address, contract, provider, providerApi, config.web2, config.account.address);
337
+ updateState({ captchaApi });
338
+ return getCaptchaApi();
339
+ };
340
+ const loadProviderApi = async (providerUrl) => {
341
+ const config = getConfig();
342
+ const network = getNetwork(config);
343
+ return new ProviderApi(network, providerUrl, config.account.address);
344
+ };
345
+ const clearTimeout = () => {
346
+ // clear the timeout
347
+ window.clearTimeout(state.timeout);
348
+ // then clear the timeout from the state
349
+ updateState({ timeout: undefined });
350
+ };
351
+ const resetState = () => {
352
+ // clear timeout just in case a timer is still active (shouldn't be)
353
+ clearTimeout();
354
+ updateState(defaultState());
355
+ };
356
+ const getCaptchaApi = () => {
357
+ if (!state.captchaApi) {
358
+ throw new Error('Captcha api not set');
359
+ }
360
+ return state.captchaApi;
361
+ };
362
+ /**
363
+ * Load the account using address specified in config, or generate new address if not found in local storage for web2 mode.
364
+ */
365
+ const loadAccount = async () => {
366
+ const config = getConfig();
367
+ // check if account has been provided in config (doesn't matter in web2 mode)
368
+ if (!config.web2 && !config.userAccountAddress) {
369
+ throw new Error('Account address has not been set for web3 mode');
370
+ }
371
+ // check if account exists in extension
372
+ const ext = config.web2 ? new ExtensionWeb2() : new ExtensionWeb3();
373
+ const account = await ext.getAccount(config);
374
+ // Store the account in local storage
375
+ storage.setAccount(account.account.address);
376
+ console.log('Using account:', account);
377
+ updateState({ account });
378
+ return getAccount();
379
+ };
380
+ const getAccount = () => {
381
+ if (!state.account) {
382
+ throw new Error('Account not loaded');
383
+ }
384
+ const account = state.account;
385
+ return account;
386
+ };
387
+ const getDappAccount = () => {
388
+ if (!state.dappAccount) {
389
+ throw new Error('Dapp account not loaded');
390
+ }
391
+ const dappAccount = state.dappAccount;
392
+ return dappAccount;
393
+ };
394
+ const getBlockNumber = () => {
395
+ if (!state.blockNumber) {
396
+ throw new Error('Account not loaded');
397
+ }
398
+ const blockNumber = state.blockNumber;
399
+ return blockNumber;
400
+ };
401
+ /**
402
+ * Load the contract instance using addresses from config.
403
+ */
404
+ const loadContract = async () => {
405
+ const config = getConfig();
406
+ const network = getNetwork(config);
407
+ const api = await ApiPromise.create({ provider: new WsProvider(network.endpoint) });
408
+ // TODO create a shared keyring that's stored somewhere
409
+ const type = 'sr25519';
410
+ const keyring = new Keyring({ type, ss58Format: api.registry.chainSS58 });
411
+ return new ProsopoCaptchaContract(api, abiJson, network.contract.address, keyring.addFromAddress(getAccount().account.address), 'prosopo', 0);
412
+ };
413
+ return {
414
+ start,
415
+ cancel,
416
+ submit,
417
+ select,
418
+ nextRound,
419
+ };
420
+ }
421
+ //# sourceMappingURL=Manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Manager.js","sourceRoot":"","sources":["../../src/modules/Manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { CaptchaSolution } from '@prosopo/types';
2
+ import { GetCaptchaResponse } from '../types/api.js';
3
+ import { ProsopoCaptchaContract } from '@prosopo/contract';
4
+ import { ProviderApi } from '@prosopo/api';
5
+ import { RandomProvider } from '@prosopo/types';
6
+ import { Signer } from '@polkadot/api/types';
7
+ import { TCaptchaSubmitResult } from '../types/client.js';
8
+ export declare class ProsopoCaptchaApi {
9
+ userAccount: string;
10
+ contract: ProsopoCaptchaContract;
11
+ provider: RandomProvider;
12
+ providerApi: ProviderApi;
13
+ dappAccount: string;
14
+ private web2;
15
+ constructor(userAccount: string, contract: ProsopoCaptchaContract, provider: RandomProvider, providerApi: ProviderApi, web2: boolean, dappAccount: string);
16
+ getCaptchaChallenge(): Promise<GetCaptchaResponse>;
17
+ verifyCaptchaChallengeContent(provider: RandomProvider, captchaChallenge: GetCaptchaResponse): void;
18
+ submitCaptchaSolution(signer: Signer, requestHash: string, datasetId: string, solutions: CaptchaSolution[], salt: string): Promise<TCaptchaSubmitResult>;
19
+ }
20
+ export default ProsopoCaptchaApi;
21
+ //# sourceMappingURL=ProsopoCaptchaApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProsopoCaptchaApi.d.ts","sourceRoot":"","sources":["../../src/modules/ProsopoCaptchaApi.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,eAAe,EAAoB,MAAM,gBAAgB,CAAA;AAClE,OAAO,EAA2B,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAG7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAE1D,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAIzD,qBAAa,iBAAiB;IAC1B,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,sBAAsB,CAAA;IAChC,QAAQ,EAAE,cAAc,CAAA;IACxB,WAAW,EAAE,WAAW,CAAA;IACxB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,CAAC,IAAI,CAAS;gBAGjB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,sBAAsB,EAChC,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,OAAO,EACb,WAAW,EAAE,MAAM;IAUV,mBAAmB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAWxD,6BAA6B,CAAC,QAAQ,EAAE,cAAc,EAAE,gBAAgB,EAAE,kBAAkB,GAAG,IAAI;IAyB7F,qBAAqB,CAC9B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,eAAe,EAAE,EAC5B,IAAI,EAAE,MAAM,GACb,OAAO,CAAC,oBAAoB,CAAC;CA2CnC;AA4BD,eAAe,iBAAiB,CAAA"}
@@ -0,0 +1,100 @@
1
+ import { CaptchaMerkleTree, computeCaptchaHash, computeCaptchaSolutionHash, computeItemHash, verifyProof, } from '@prosopo/datasets';
2
+ import { ProsopoApiError } from '../api/handlers.js';
3
+ import { ProsopoEnvError } from '@prosopo/common';
4
+ import { at } from '@prosopo/util';
5
+ import { stringToHex } from '@polkadot/util';
6
+ export class ProsopoCaptchaApi {
7
+ constructor(userAccount, contract, provider, providerApi, web2, dappAccount) {
8
+ this.userAccount = userAccount;
9
+ this.contract = contract;
10
+ this.provider = provider;
11
+ this.providerApi = providerApi;
12
+ this.web2 = web2;
13
+ this.dappAccount = dappAccount;
14
+ }
15
+ async getCaptchaChallenge() {
16
+ try {
17
+ const captchaChallenge = await this.providerApi.getCaptchaChallenge(this.userAccount, this.provider);
18
+ this.verifyCaptchaChallengeContent(this.provider, captchaChallenge);
19
+ return captchaChallenge;
20
+ }
21
+ catch (e) {
22
+ // TODO fix/improve error handling
23
+ throw new ProsopoEnvError(e);
24
+ }
25
+ }
26
+ verifyCaptchaChallengeContent(provider, captchaChallenge) {
27
+ // TODO make sure root is equal to root on the provider
28
+ const first = at(captchaChallenge.captchas, 0);
29
+ const proofLength = first.proof.length;
30
+ console.log(provider.provider);
31
+ const last = at(first.proof, proofLength - 1);
32
+ if (provider.provider.datasetIdContent.toString() !== at(last, 0)) {
33
+ throw new ProsopoEnvError('CAPTCHA.INVALID_DATASET_CONTENT_ID');
34
+ }
35
+ for (const captchaWithProof of captchaChallenge.captchas) {
36
+ //TODO calculate the captchaId from the captcha content
37
+ if (!verifyCaptchaData(captchaWithProof)) {
38
+ throw new ProsopoEnvError('CAPTCHA.INVALID_CAPTCHA_CHALLENGE');
39
+ }
40
+ if (!verifyProof(captchaWithProof.captcha.captchaContentId, captchaWithProof.proof)) {
41
+ throw new ProsopoEnvError('CAPTCHA.INVALID_CAPTCHA_CHALLENGE');
42
+ }
43
+ }
44
+ console.log('CAPTCHA.CHALLENGE_VERIFIED');
45
+ return;
46
+ }
47
+ async submitCaptchaSolution(signer, requestHash, datasetId, solutions, salt) {
48
+ const tree = new CaptchaMerkleTree();
49
+ const captchasHashed = solutions.map((captcha) => computeCaptchaSolutionHash(captcha));
50
+ tree.build(captchasHashed);
51
+ const commitmentId = tree.root.hash;
52
+ console.log('solveCaptchaChallenge commitmentId', commitmentId);
53
+ const tx = undefined;
54
+ let signature = undefined;
55
+ if (this.web2) {
56
+ if (!signer || !signer.signRaw) {
57
+ throw new Error('Signer is not defined, cannot sign message to prove account ownership');
58
+ }
59
+ // sign the request hash to prove account ownership
60
+ const signed = await signer.signRaw({
61
+ address: this.userAccount,
62
+ data: stringToHex(requestHash),
63
+ type: 'bytes',
64
+ });
65
+ signature = signed.signature;
66
+ }
67
+ let result;
68
+ try {
69
+ result = await this.providerApi.submitCaptchaSolution(solutions, requestHash, this.contract.pair.address, salt, signature);
70
+ }
71
+ catch (err) {
72
+ // TODO fix/improve error handling
73
+ throw new ProsopoApiError(err);
74
+ }
75
+ return [result, commitmentId, tx];
76
+ }
77
+ }
78
+ /**
79
+ * Verify the captcha data by hashing the images and checking the hashes correspond to the hashes passed in the captcha
80
+ * Verify the captcha content id is present in the first layer of the proof
81
+ * @param {CaptchaWithProof} captchaWithProof
82
+ * @returns {boolean}
83
+ */
84
+ async function verifyCaptchaData(captchaWithProof) {
85
+ const captcha = captchaWithProof.captcha;
86
+ const proof = captchaWithProof.proof;
87
+ // Check that all the item hashes are equal to the provided item hashes in the captcha
88
+ if (!(await Promise.all(captcha.items.map(async (item) => (await computeItemHash(item)).hash === item.hash))).every((hash) => hash === true)) {
89
+ return false;
90
+ }
91
+ // Check that the computed captcha content id is equal to the provided captcha content id
92
+ const captchaHash = computeCaptchaHash(captcha, false, false, false);
93
+ if (captchaHash !== captcha.captchaContentId) {
94
+ return false;
95
+ }
96
+ // Check that the captcha content id is present in the first layer of the proof
97
+ return at(proof, 0).indexOf(captchaHash) !== -1;
98
+ }
99
+ export default ProsopoCaptchaApi;
100
+ //# sourceMappingURL=ProsopoCaptchaApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProsopoCaptchaApi.js","sourceRoot":"","sources":["../../src/modules/ProsopoCaptchaApi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ type Area = {
2
+ width: number;
3
+ height: number;
4
+ };
5
+ export declare function picassoCanvas(roundNumber: number, seed: number, params: {
6
+ area: Area;
7
+ offsetParameter: number;
8
+ multiplier: number;
9
+ fontSizeFactor: number;
10
+ maxShadowBlur: number;
11
+ }): string;
12
+ export {};
13
+ //# sourceMappingURL=canvas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas.d.ts","sourceRoot":"","sources":["../../src/modules/canvas.ts"],"names":[],"mappings":"AAyNA,KAAK,IAAI,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE7C,wBAAgB,aAAa,CACzB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE;IACJ,IAAI,EAAE,IAAI,CAAA;IACV,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;CACxB,UAgNJ"}