@prosopo/provider 1.0.2 → 2.0.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 (190) hide show
  1. package/README.md +0 -258
  2. package/dist/api/admin.d.ts +2 -2
  3. package/dist/api/admin.d.ts.map +1 -1
  4. package/dist/api/admin.js +5 -64
  5. package/dist/api/admin.js.map +1 -1
  6. package/dist/api/authMiddleware.d.ts +4 -4
  7. package/dist/api/authMiddleware.d.ts.map +1 -1
  8. package/dist/api/authMiddleware.js +15 -29
  9. package/dist/api/authMiddleware.js.map +1 -1
  10. package/dist/api/captcha.d.ts +2 -2
  11. package/dist/api/captcha.d.ts.map +1 -1
  12. package/dist/api/captcha.js +64 -55
  13. package/dist/api/captcha.js.map +1 -1
  14. package/dist/api/captchaScheduler.d.ts +2 -2
  15. package/dist/api/captchaScheduler.d.ts.map +1 -1
  16. package/dist/api/captchaScheduler.js +11 -10
  17. package/dist/api/captchaScheduler.js.map +1 -1
  18. package/dist/api/errorHandler.d.ts +3 -3
  19. package/dist/api/errorHandler.d.ts.map +1 -1
  20. package/dist/api/errorHandler.js +7 -3
  21. package/dist/api/errorHandler.js.map +1 -1
  22. package/dist/api/verify.d.ts +2 -2
  23. package/dist/api/verify.d.ts.map +1 -1
  24. package/dist/api/verify.js +37 -29
  25. package/dist/api/verify.js.map +1 -1
  26. package/dist/cjs/api/admin.cjs +2 -89
  27. package/dist/cjs/api/authMiddleware.cjs +1 -15
  28. package/dist/cjs/api/captcha.cjs +89 -52
  29. package/dist/cjs/api/captchaScheduler.cjs +4 -7
  30. package/dist/cjs/api/errorHandler.cjs +3 -1
  31. package/dist/cjs/api/verify.cjs +54 -28
  32. package/dist/cjs/index.cjs +0 -3
  33. package/dist/cjs/tasks/dataset/datasetTasks.cjs +68 -0
  34. package/dist/cjs/tasks/dataset/datasetTasksUtils.cjs +34 -0
  35. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +277 -0
  36. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasksUtils.cjs +25 -0
  37. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +107 -0
  38. package/dist/cjs/tasks/powCaptcha/powTasksUtils.cjs +55 -0
  39. package/dist/cjs/tasks/tasks.cjs +21 -524
  40. package/dist/cjs/util.cjs +32 -19
  41. package/dist/index.d.ts +7 -8
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +7 -8
  44. package/dist/index.js.map +1 -1
  45. package/dist/tasks/dataset/datasetTasks.d.ts +15 -0
  46. package/dist/tasks/dataset/datasetTasks.d.ts.map +1 -0
  47. package/dist/tasks/dataset/datasetTasks.js +40 -0
  48. package/dist/tasks/dataset/datasetTasks.js.map +1 -0
  49. package/dist/tasks/dataset/datasetTasksUtils.d.ts +3 -0
  50. package/dist/tasks/dataset/datasetTasksUtils.d.ts.map +1 -0
  51. package/dist/tasks/dataset/datasetTasksUtils.js +34 -0
  52. package/dist/tasks/dataset/datasetTasksUtils.js.map +1 -0
  53. package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts +28 -0
  54. package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts.map +1 -0
  55. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +212 -0
  56. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js.map +1 -0
  57. package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.d.ts +7 -0
  58. package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.d.ts.map +1 -0
  59. package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.js +18 -0
  60. package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.js.map +1 -0
  61. package/dist/tasks/index.d.ts +1 -1
  62. package/dist/tasks/index.d.ts.map +1 -1
  63. package/dist/tasks/index.js +1 -1
  64. package/dist/tasks/index.js.map +1 -1
  65. package/dist/tasks/powCaptcha/powTasks.d.ts +13 -0
  66. package/dist/tasks/powCaptcha/powTasks.d.ts.map +1 -0
  67. package/dist/tasks/powCaptcha/powTasks.js +66 -0
  68. package/dist/tasks/powCaptcha/powTasks.js.map +1 -0
  69. package/dist/tasks/powCaptcha/powTasksUtils.d.ts +5 -0
  70. package/dist/tasks/powCaptcha/powTasksUtils.d.ts.map +1 -0
  71. package/dist/tasks/powCaptcha/powTasksUtils.js +49 -0
  72. package/dist/tasks/powCaptcha/powTasksUtils.js.map +1 -0
  73. package/dist/tasks/tasks.d.ts +12 -43
  74. package/dist/tasks/tasks.d.ts.map +1 -1
  75. package/dist/tasks/tasks.js +13 -431
  76. package/dist/tasks/tasks.js.map +1 -1
  77. package/dist/tests/index.d.ts +2 -0
  78. package/dist/tests/index.d.ts.map +1 -0
  79. package/dist/tests/index.js +2 -0
  80. package/dist/tests/index.js.map +1 -0
  81. package/dist/tests/integration/imgCaptcha.test.d.ts +2 -0
  82. package/dist/tests/integration/imgCaptcha.test.d.ts.map +1 -0
  83. package/dist/tests/integration/imgCaptcha.test.js +111 -0
  84. package/dist/tests/integration/imgCaptcha.test.js.map +1 -0
  85. package/dist/tests/integration/mocks/solvedTestCaptchas.d.ts +32 -0
  86. package/dist/tests/integration/mocks/solvedTestCaptchas.d.ts.map +1 -0
  87. package/dist/tests/integration/mocks/solvedTestCaptchas.js +1042 -0
  88. package/dist/tests/integration/mocks/solvedTestCaptchas.js.map +1 -0
  89. package/dist/tests/integration/powCaptcha.test.d.ts +2 -0
  90. package/dist/tests/integration/powCaptcha.test.d.ts.map +1 -0
  91. package/dist/tests/integration/powCaptcha.test.js +171 -0
  92. package/dist/tests/integration/powCaptcha.test.js.map +1 -0
  93. package/dist/tests/unit/api/authMiddleware.test.d.ts +2 -0
  94. package/dist/tests/unit/api/authMiddleware.test.d.ts.map +1 -0
  95. package/dist/tests/unit/api/authMiddleware.test.js +87 -0
  96. package/dist/tests/unit/api/authMiddleware.test.js.map +1 -0
  97. package/dist/tests/unit/api/captchaScheduler.test.d.ts +2 -0
  98. package/dist/tests/unit/api/captchaScheduler.test.d.ts.map +1 -0
  99. package/dist/tests/unit/api/captchaScheduler.test.js +47 -0
  100. package/dist/tests/unit/api/captchaScheduler.test.js.map +1 -0
  101. package/dist/tests/unit/api/errorHandler.test.d.ts +2 -0
  102. package/dist/tests/unit/api/errorHandler.test.d.ts.map +1 -0
  103. package/dist/tests/unit/api/errorHandler.test.js +65 -0
  104. package/dist/tests/unit/api/errorHandler.test.js.map +1 -0
  105. package/dist/tests/unit/tasks/dataset/datasetTasks.test.d.ts +2 -0
  106. package/dist/tests/unit/tasks/dataset/datasetTasks.test.d.ts.map +1 -0
  107. package/dist/tests/unit/tasks/dataset/datasetTasks.test.js +88 -0
  108. package/dist/tests/unit/tasks/dataset/datasetTasks.test.js.map +1 -0
  109. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.test.d.ts +2 -0
  110. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.test.d.ts.map +1 -0
  111. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.test.js +75 -0
  112. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.test.js.map +1 -0
  113. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.test.d.ts +2 -0
  114. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.test.d.ts.map +1 -0
  115. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.test.js +260 -0
  116. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.test.js.map +1 -0
  117. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.test.d.ts +2 -0
  118. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.test.d.ts.map +1 -0
  119. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.test.js +46 -0
  120. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.test.js.map +1 -0
  121. package/dist/tests/unit/tasks/powCaptcha/powTasks.test.d.ts +2 -0
  122. package/dist/tests/unit/tasks/powCaptcha/powTasks.test.d.ts.map +1 -0
  123. package/dist/tests/unit/tasks/powCaptcha/powTasks.test.js +133 -0
  124. package/dist/tests/unit/tasks/powCaptcha/powTasks.test.js.map +1 -0
  125. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.test.d.ts +2 -0
  126. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.test.d.ts.map +1 -0
  127. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.test.js +94 -0
  128. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.test.js.map +1 -0
  129. package/dist/util.d.ts +2 -2
  130. package/dist/util.d.ts.map +1 -1
  131. package/dist/util.js +10 -8
  132. package/dist/util.js.map +1 -1
  133. package/package.json +74 -86
  134. package/vite.cjs.config.ts +3 -3
  135. package/vite.test.config.ts +12 -12
  136. package/dist/batch/commitments.d.ts +0 -24
  137. package/dist/batch/commitments.d.ts.map +0 -1
  138. package/dist/batch/commitments.js +0 -130
  139. package/dist/batch/commitments.js.map +0 -1
  140. package/dist/batch/index.d.ts +0 -2
  141. package/dist/batch/index.d.ts.map +0 -1
  142. package/dist/batch/index.js +0 -2
  143. package/dist/batch/index.js.map +0 -1
  144. package/dist/cjs/batch/commitments.cjs +0 -158
  145. package/dist/cjs/batch/index.cjs +0 -4
  146. package/dist/scheduler.d.ts +0 -4
  147. package/dist/scheduler.d.ts.map +0 -1
  148. package/dist/scheduler.js +0 -21
  149. package/dist/scheduler.js.map +0 -1
  150. package/dist/tests/accounts.d.ts +0 -12
  151. package/dist/tests/accounts.d.ts.map +0 -1
  152. package/dist/tests/accounts.js +0 -35
  153. package/dist/tests/accounts.js.map +0 -1
  154. package/dist/tests/contract/helpers.test.d.ts +0 -6
  155. package/dist/tests/contract/helpers.test.d.ts.map +0 -1
  156. package/dist/tests/contract/helpers.test.js +0 -54
  157. package/dist/tests/contract/helpers.test.js.map +0 -1
  158. package/dist/tests/dataUtils/DatabaseAccounts.d.ts +0 -35
  159. package/dist/tests/dataUtils/DatabaseAccounts.d.ts.map +0 -1
  160. package/dist/tests/dataUtils/DatabaseAccounts.js +0 -84
  161. package/dist/tests/dataUtils/DatabaseAccounts.js.map +0 -1
  162. package/dist/tests/dataUtils/DatabasePopulator.d.ts +0 -73
  163. package/dist/tests/dataUtils/DatabasePopulator.d.ts.map +0 -1
  164. package/dist/tests/dataUtils/DatabasePopulator.js +0 -326
  165. package/dist/tests/dataUtils/DatabasePopulator.js.map +0 -1
  166. package/dist/tests/dataUtils/dapp-example-contract/dapp.json +0 -648
  167. package/dist/tests/dataUtils/dapp-example-contract/loadFiles.d.ts +0 -4
  168. package/dist/tests/dataUtils/dapp-example-contract/loadFiles.d.ts.map +0 -1
  169. package/dist/tests/dataUtils/dapp-example-contract/loadFiles.js +0 -27
  170. package/dist/tests/dataUtils/dapp-example-contract/loadFiles.js.map +0 -1
  171. package/dist/tests/dataUtils/funds.d.ts +0 -9
  172. package/dist/tests/dataUtils/funds.d.ts.map +0 -1
  173. package/dist/tests/dataUtils/funds.js +0 -105
  174. package/dist/tests/dataUtils/funds.js.map +0 -1
  175. package/dist/tests/dataUtils/populateDatabase.d.ts +0 -16
  176. package/dist/tests/dataUtils/populateDatabase.d.ts.map +0 -1
  177. package/dist/tests/dataUtils/populateDatabase.js +0 -72
  178. package/dist/tests/dataUtils/populateDatabase.js.map +0 -1
  179. package/dist/tests/getUser.d.ts +0 -4
  180. package/dist/tests/getUser.d.ts.map +0 -1
  181. package/dist/tests/getUser.js +0 -18
  182. package/dist/tests/getUser.js.map +0 -1
  183. package/dist/tests/tasks/tasks.test.d.ts +0 -6
  184. package/dist/tests/tasks/tasks.test.d.ts.map +0 -1
  185. package/dist/tests/tasks/tasks.test.js +0 -636
  186. package/dist/tests/tasks/tasks.test.js.map +0 -1
  187. package/dist/tests/util.test.d.ts +0 -2
  188. package/dist/tests/util.test.d.ts.map +0 -1
  189. package/dist/tests/util.test.js +0 -23
  190. package/dist/tests/util.test.js.map +0 -1
@@ -1,537 +1,34 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const types = require("@prosopo/types");
4
- const datasets = require("@prosopo/datasets");
5
- const typesReturns = require("@prosopo/captcha-contract/types-returns");
6
3
  const common = require("@prosopo/common");
7
- const contract = require("@prosopo/contract");
8
- const util$2 = require("@prosopo/util");
9
- const hex = require("@polkadot/util/hex");
10
- const random = require("@polkadot/util-crypto/random");
11
- const database = require("@prosopo/database");
12
- const sha256 = require("@noble/hashes/sha256");
13
- const util = require("../util.cjs");
14
- const signature = require("@polkadot/util-crypto/signature");
15
- const string = require("@polkadot/util/string");
16
- const util$1 = require("@polkadot/util");
17
- const POW_SEPARATOR = "___";
4
+ const datasetTasks = require("./dataset/datasetTasks.cjs");
5
+ const imgCaptchaTasks = require("./imgCaptcha/imgCaptchaTasks.cjs");
6
+ const powTasks = require("./powCaptcha/powTasks.cjs");
18
7
  class Tasks {
19
8
  constructor(env) {
20
- if (!env.contractInterface) {
21
- throw new common.ProsopoEnvError("CONTRACT.CONTRACT_UNDEFINED", {
22
- context: { failedFuncName: this.constructor.name, contractAddress: env.contractAddress }
23
- });
24
- }
25
9
  this.config = env.config;
26
- this.contract = env.contractInterface;
27
- this.db = env.db;
10
+ this.db = env.getDb();
28
11
  this.captchaConfig = env.config.captchas;
29
- this.captchaSolutionConfig = env.config.captchaSolutions;
30
12
  this.logger = common.getLogger(env.config.logLevel, "Tasks");
31
- }
32
- async providerSetDatasetFromFile(file) {
33
- const datasetRaw = datasets.parseCaptchaDataset(file);
34
- this.logger.debug("Parsed raw data set");
35
- return await this.providerSetDataset(datasetRaw);
36
- }
37
- async providerSetDataset(datasetRaw) {
38
- if (datasetRaw.captchas.length < this.config.captchas.solved.count + this.config.captchas.unsolved.count) {
39
- throw new common.ProsopoEnvError("DATASET.CAPTCHAS_COUNT_LESS_THAN_CONFIGURED", {
40
- context: { failedFuncName: this.providerSetDataset.name }
41
- });
42
- }
43
- const solutions = datasetRaw.captchas.map((captcha) => captcha.solution ? 1 : 0).reduce((partialSum, b) => partialSum + b, 0);
44
- if (solutions < this.config.captchas.solved.count) {
45
- throw new common.ProsopoEnvError("DATASET.SOLUTIONS_COUNT_LESS_THAN_CONFIGURED", {
46
- context: { failedFuncName: this.providerSetDataset.name }
47
- });
48
- }
49
- if (solutions < this.config.captchas.unsolved.count) {
50
- throw new common.ProsopoEnvError("DATASET.SOLUTIONS_COUNT_LESS_THAN_CONFIGURED", {
51
- context: { failedFuncName: this.providerSetDataset.name }
52
- });
53
- }
54
- const dataset = await datasets.buildDataset(datasetRaw);
55
- if (!dataset.datasetId || !dataset.datasetContentId) {
56
- throw new common.ProsopoEnvError("DATASET.DATASET_ID_UNDEFINED", {
57
- context: { failedFuncName: this.providerSetDataset.name }
58
- });
59
- }
60
- await this.db?.storeDataset(dataset);
61
- await contract.wrapQuery(this.contract.query.providerSetDataset, this.contract.query)(
62
- dataset.datasetId,
63
- dataset.datasetContentId
64
- );
65
- const txResult = await this.contract.methods.providerSetDataset(dataset.datasetId, dataset.datasetContentId, {
66
- value: 0
67
- });
68
- return txResult.result;
69
- }
70
- // Other tasks
71
- /**
72
- * @description Get random captchas that are solved or not solved, along with the merkle proof for each
73
- * @param {string} datasetId the id of the data set
74
- * @param {boolean} solved `true` when captcha is solved
75
- * @param {number} size the number of records to be returned
76
- */
77
- async getCaptchaWithProof(datasetId, solved, size) {
78
- const captchaDocs = await this.db.getRandomCaptcha(solved, datasetId, size);
79
- if (captchaDocs) {
80
- const captchas = [];
81
- for (const captcha of captchaDocs) {
82
- const datasetDetails = await this.db.getDatasetDetails(datasetId);
83
- const tree = new datasets.CaptchaMerkleTree();
84
- if (datasetDetails.contentTree) {
85
- tree.layers = datasetDetails.contentTree;
86
- const proof = tree.proof(captcha.captchaContentId);
87
- delete captcha.solution;
88
- captcha.items = util.shuffleArray(captcha.items);
89
- captchas.push({ captcha, proof });
90
- }
91
- }
92
- return captchas;
93
- }
94
- throw new common.ProsopoEnvError("DATABASE.CAPTCHA_GET_FAILED", {
95
- context: { failedFuncName: this.getCaptchaWithProof.name, datasetId, solved, size }
96
- });
97
- }
98
- /**
99
- * @description Generates a PoW Captcha for a given user and dapp
100
- *
101
- * @param {string} userAccount - user that is solving the captcha
102
- * @param {string} dappAccount - dapp that is requesting the captcha
103
- */
104
- async getPowCaptchaChallenge(userAccount, dappAccount, origin) {
105
- const difficulty = 4;
106
- const latestHeader = await this.contract.api.rpc.chain.getHeader();
107
- const latestBlockNumber = latestHeader.number.toNumber();
108
- const challenge = `${latestBlockNumber}___${userAccount}___${dappAccount}`;
109
- const signature2 = util$1.u8aToHex(this.contract.pair.sign(string.stringToHex(challenge)));
110
- return { challenge, difficulty, signature: signature2 };
111
- }
112
- /**
113
- * @description Verifies a PoW Captcha for a given user and dapp
114
- *
115
- * @param {string} blockNumber - the block at which the Provider was selected
116
- * @param {string} challenge - the starting string for the PoW challenge
117
- * @param {string} difficulty - how many leading zeroes the solution must have
118
- * @param {string} signature - proof that the Provider provided the challenge
119
- * @param {string} nonce - the string that the user has found that satisfies the PoW challenge
120
- * @param {number} timeout - the time in milliseconds since the Provider was selected to provide the PoW captcha
121
- */
122
- async verifyPowCaptchaSolution(blockNumber, challenge, difficulty, signature$1, nonce, timeout) {
123
- const recent = contract.verifyRecency(this.contract.api, blockNumber, timeout);
124
- if (!recent) {
125
- throw new common.ProsopoContractError("CONTRACT.INVALID_BLOCKHASH", {
126
- context: {
127
- ERROR: `Block in which the Provider was selected must be within the last ${timeout / 1e3} seconds`,
128
- failedFuncName: this.verifyPowCaptchaSolution.name,
129
- blockNumber
130
- }
131
- });
132
- }
133
- const signatureVerification = signature.signatureVerify(string.stringToHex(challenge), signature$1, this.contract.pair.address);
134
- if (!signatureVerification.isValid) {
135
- throw new common.ProsopoContractError("GENERAL.INVALID_SIGNATURE", {
136
- context: {
137
- ERROR: "Provider signature is invalid for this message",
138
- failedFuncName: this.verifyPowCaptchaSolution.name,
139
- signature: signature$1
140
- }
141
- });
142
- }
143
- const solutionValid = Array.from(sha256.sha256(new TextEncoder().encode(nonce + challenge))).map((byte) => byte.toString(16).padStart(2, "0")).join("").startsWith("0".repeat(difficulty));
144
- if (!solutionValid) {
145
- throw new common.ProsopoContractError("API.CAPTCHA_FAILED", {
146
- context: {
147
- ERROR: "Captcha solution is invalid",
148
- failedFuncName: this.verifyPowCaptchaSolution.name,
149
- nonce,
150
- challenge,
151
- difficulty
152
- }
153
- });
154
- }
155
- await this.db.storePowCaptchaRecord(challenge, false);
156
- return true;
157
- }
158
- async serverVerifyPowCaptchaSolution(dappAccount, challenge, timeout) {
159
- const challengeRecord = await this.db.getPowCaptchaRecordByChallenge(challenge);
160
- if (!challengeRecord) {
161
- throw new common.ProsopoEnvError("DATABASE.CAPTCHA_GET_FAILED", {
162
- context: { failedFuncName: this.serverVerifyPowCaptchaSolution.name, challenge }
163
- });
164
- }
165
- if (challengeRecord.checked) {
166
- return false;
167
- }
168
- const [blocknumber, userAccount, challengeDappAccount] = challengeRecord.challenge.split(POW_SEPARATOR);
169
- if (dappAccount !== challengeDappAccount) {
170
- throw new common.ProsopoEnvError("CAPTCHA.DAPP_USER_SOLUTION_NOT_FOUND", {
171
- context: {
172
- failedFuncName: this.serverVerifyPowCaptchaSolution.name,
173
- dappAccount,
174
- challengeDappAccount
175
- }
176
- });
177
- }
178
- if (!blocknumber) {
179
- throw new common.ProsopoContractError("CONTRACT.INVALID_BLOCKHASH", {
180
- context: {
181
- ERROR: "Block number not provided",
182
- failedFuncName: this.verifyPowCaptchaSolution.name,
183
- blocknumber
184
- }
185
- });
186
- }
187
- const recent = contract.verifyRecency(this.contract.api, parseInt(blocknumber), timeout);
188
- if (!recent) {
189
- throw new common.ProsopoContractError("CONTRACT.INVALID_BLOCKHASH", {
190
- context: {
191
- ERROR: `Block in which the Provider was selected must be within the last ${timeout / 1e3} seconds`,
192
- failedFuncName: this.verifyPowCaptchaSolution.name,
193
- blocknumber
194
- }
195
- });
196
- }
197
- await this.db.updatePowCaptchaRecord(challengeRecord.challenge, true);
198
- return true;
199
- }
200
- /**
201
- * Validate and store the text captcha solution(s) from the Dapp User in a web2 environment
202
- * @param {string} userAccount
203
- * @param {string} dappAccount
204
- * @param {string} requestHash
205
- * @param {JSON} captchas
206
- * @param {string} signature
207
- * @return {Promise<DappUserSolutionResult>} result containing the contract event
208
- */
209
- async dappUserSolution(userAccount, dappAccount, requestHash, captchas, signature$1) {
210
- if (!await this.dappIsActive(dappAccount)) {
211
- throw new common.ProsopoEnvError("CONTRACT.DAPP_NOT_ACTIVE", {
212
- context: { failedFuncName: this.getPaymentInfo.name, dappAccount }
213
- });
214
- }
215
- const verification = signature.signatureVerify(string.stringToHex(requestHash), signature$1, userAccount);
216
- if (!verification.isValid) {
217
- throw new common.ProsopoEnvError("GENERAL.INVALID_SIGNATURE", {
218
- context: { failedFuncName: this.dappUserSolution.name, userAccount }
219
- });
220
- }
221
- let response = {
222
- captchas: [],
223
- verified: false
224
- };
225
- const { storedCaptchas, receivedCaptchas, captchaIds } = await this.validateReceivedCaptchasAgainstStoredCaptchas(captchas);
226
- const { tree, commitmentId } = await this.buildTreeAndGetCommitmentId(receivedCaptchas);
227
- const provider = (await this.contract.methods.getProvider(this.contract.pair.address, {})).value.unwrap().unwrap();
228
- const pendingRecord = await this.db.getDappUserPending(requestHash);
229
- const pendingRequest = await this.validateDappUserSolutionRequestIsPending(
230
- requestHash,
231
- pendingRecord,
232
- userAccount,
233
- captchaIds
234
- );
235
- const userSignature = hex.hexToU8a(signature$1);
236
- const blockNumber = await contract.getCurrentBlockNumber(this.contract.api);
237
- if (pendingRequest) {
238
- await this.db.updateDappUserPendingStatus(requestHash);
239
- const commit = {
240
- id: commitmentId,
241
- userAccount,
242
- dappContract: dappAccount,
243
- providerAccount: this.contract.pair.address,
244
- datasetId: provider.datasetId.toString(),
245
- status: typesReturns.CaptchaStatus.pending,
246
- userSignature: Array.from(userSignature),
247
- requestedAt: pendingRecord.requestedAtBlock,
248
- // TODO is this correct or should it be block number?
249
- completedAt: blockNumber,
250
- processed: false,
251
- batched: false,
252
- stored: false
253
- };
254
- await this.db.storeDappUserSolution(receivedCaptchas, commit);
255
- if (datasets.compareCaptchaSolutions(receivedCaptchas, storedCaptchas)) {
256
- response = {
257
- captchas: captchaIds.map((id) => ({
258
- captchaId: id,
259
- proof: tree.proof(id)
260
- })),
261
- verified: true
262
- };
263
- await this.db.approveDappUserCommitment(commitmentId);
264
- } else {
265
- response = {
266
- captchas: captchaIds.map((id) => ({
267
- captchaId: id,
268
- proof: [[]]
269
- })),
270
- verified: false
271
- };
272
- }
273
- }
274
- return response;
275
- }
276
- /**
277
- * Validate that the dapp is active in the contract
278
- */
279
- async dappIsActive(dappAccount) {
280
- const dapp = await contract.wrapQuery(this.contract.query.getDapp, this.contract.query)(dappAccount);
281
- return dapp.status.toString() === "Active";
282
- }
283
- /**
284
- * Gets provider status in contract
285
- */
286
- async providerStatus() {
287
- try {
288
- const provider = await contract.wrapQuery(
289
- this.contract.query.getProvider,
290
- this.contract.query
291
- )(this.contract.pair.address);
292
- return { status: provider.status ? "Registered" : "Unregistered" };
293
- } catch (e) {
294
- return { status: "Unregistered" };
295
- }
296
- }
297
- /**
298
- * Validate length of received captchas array matches length of captchas found in database
299
- * Validate that the datasetId is the same for all captchas and is equal to the datasetId on the stored captchas
300
- */
301
- async validateReceivedCaptchasAgainstStoredCaptchas(captchas) {
302
- const receivedCaptchas = datasets.parseAndSortCaptchaSolutions(captchas);
303
- const captchaIds = receivedCaptchas.map((captcha) => captcha.captchaId);
304
- const storedCaptchas = await this.db.getCaptchaById(captchaIds);
305
- if (!storedCaptchas || receivedCaptchas.length !== storedCaptchas.length) {
306
- throw new common.ProsopoEnvError("CAPTCHA.INVALID_CAPTCHA_ID", {
307
- context: {
308
- failedFuncName: this.validateReceivedCaptchasAgainstStoredCaptchas.name,
309
- captchas
310
- }
311
- });
312
- }
313
- if (!storedCaptchas.every((captcha) => captcha.datasetId === util$2.at(storedCaptchas, 0).datasetId)) {
314
- throw new common.ProsopoEnvError("CAPTCHA.DIFFERENT_DATASET_IDS", {
315
- context: {
316
- failedFuncName: this.validateReceivedCaptchasAgainstStoredCaptchas.name,
317
- captchas
318
- }
319
- });
320
- }
321
- return { storedCaptchas, receivedCaptchas, captchaIds };
322
- }
323
- /**
324
- * Build merkle tree and get commitment from contract, returning the tree, commitment, and commitmentId
325
- * @param {CaptchaSolution[]} captchaSolutions
326
- * @returns {Promise<{ tree: CaptchaMerkleTree, commitment: CaptchaSolutionCommitment, commitmentId: string }>}
327
- */
328
- async buildTreeAndGetCommitmentId(captchaSolutions) {
329
- const tree = new datasets.CaptchaMerkleTree();
330
- const solutionsHashed = captchaSolutions.map((captcha) => datasets.computeCaptchaSolutionHash(captcha));
331
- tree.build(solutionsHashed);
332
- const commitmentId = tree.root?.hash;
333
- if (!commitmentId) {
334
- throw new common.ProsopoEnvError("CONTRACT.CAPTCHA_SOLUTION_COMMITMENT_DOES_NOT_EXIST", {
335
- context: {
336
- failedFuncName: this.buildTreeAndGetCommitmentId.name,
337
- commitmentId
338
- }
339
- });
340
- }
341
- return { tree, commitmentId };
342
- }
343
- /**
344
- * Validate that a Dapp User is responding to their own pending captcha request
345
- * @param {string} requestHash
346
- * @param {PendingCaptchaRequest} pendingRecord
347
- * @param {string} userAccount
348
- * @param {string[]} captchaIds
349
- */
350
- async validateDappUserSolutionRequestIsPending(requestHash, pendingRecord, userAccount, captchaIds) {
351
- const currentTime = Date.now();
352
- if (pendingRecord.deadlineTimestamp < currentTime) {
353
- this.logger.info("Deadline for responding to captcha has expired");
354
- return false;
355
- }
356
- if (pendingRecord) {
357
- const pendingHashComputed = datasets.computePendingRequestHash(captchaIds, userAccount, pendingRecord.salt);
358
- return requestHash === pendingHashComputed;
359
- }
360
- return false;
361
- }
362
- /**
363
- * Get two random captchas from specified dataset, create the response and store a hash of it, marked as pending
364
- * @param {string} datasetId
365
- * @param {string} userAccount
366
- */
367
- async getRandomCaptchasAndRequestHash(datasetId, userAccount) {
368
- const dataset = await this.db.getDatasetDetails(datasetId);
369
- if (!dataset) {
370
- throw new common.ProsopoEnvError("DATABASE.DATASET_GET_FAILED");
371
- }
372
- const unsolvedCount = Math.abs(Math.trunc(this.captchaConfig.unsolved.count));
373
- const solvedCount = Math.abs(Math.trunc(this.captchaConfig.solved.count));
374
- if (!solvedCount) {
375
- throw new common.ProsopoEnvError("CONFIG.INVALID_CAPTCHA_NUMBER");
376
- }
377
- const solved = await this.getCaptchaWithProof(datasetId, true, solvedCount);
378
- let unsolved = [];
379
- if (unsolvedCount) {
380
- unsolved = await this.getCaptchaWithProof(datasetId, false, unsolvedCount);
381
- }
382
- const captchas = util.shuffleArray([...solved, ...unsolved]);
383
- const salt = random.randomAsHex();
384
- const requestHash = datasets.computePendingRequestHash(
385
- captchas.map((c) => c.captcha.captchaId),
386
- userAccount,
387
- salt
388
- );
389
- const currentTime = Date.now();
390
- const timeLimit = captchas.map((captcha) => captcha.captcha.timeLimitMs || types.DEFAULT_IMAGE_CAPTCHA_TIMEOUT).reduce((a, b) => a + b, 0);
391
- const deadlineTs = timeLimit + currentTime;
392
- const currentBlockNumber = await contract.getCurrentBlockNumber(this.contract.api);
393
- await this.db.storeDappUserPending(userAccount, requestHash, salt, deadlineTs, currentBlockNumber);
394
- return { captchas, requestHash };
395
- }
396
- /**
397
- * Block by block search for blockNo
398
- */
399
- async isRecentBlock(contract2, header, blockNo, depth = this.captchaSolutionConfig.captchaBlockRecency) {
400
- if (depth == 0) {
401
- return false;
402
- }
403
- const headerBlockNo = header.number.toPrimitive();
404
- if (headerBlockNo === blockNo) {
405
- return true;
406
- }
407
- const parent = await contract2.api.rpc.chain.getBlock(header.parentHash);
408
- return this.isRecentBlock(contract2, parent.block.header, blockNo, depth - 1);
409
- }
410
- /**
411
- * Validate that provided `datasetId` was a result of calling `get_random_provider` method
412
- * @param {string} userAccount - Same user that called `get_random_provider`
413
- * @param {string} dappContractAccount - account of dapp that is requesting captcha
414
- * @param {string} datasetId - `captcha_dataset_id` from the result of `get_random_provider`
415
- * @param {string} blockNumber - Block on which `get_random_provider` was called
416
- */
417
- async validateProviderWasRandomlyChosen(userAccount, dappContractAccount, datasetId, blockNumber) {
418
- const contract2 = await this.contract.contract;
419
- if (!contract2) {
420
- throw new common.ProsopoEnvError("CONTRACT.CONTRACT_UNDEFINED", {
421
- context: { failedFuncName: this.validateProviderWasRandomlyChosen.name }
422
- });
423
- }
424
- const header = await contract2.api.rpc.chain.getHeader();
425
- const isBlockNoValid = await this.isRecentBlock(contract2, header, blockNumber);
426
- if (!isBlockNoValid) {
427
- throw new common.ProsopoEnvError("CAPTCHA.INVALID_BLOCK_NO", {
428
- context: {
429
- failedFuncName: this.validateProviderWasRandomlyChosen.name,
430
- userAccount,
431
- dappContractAccount,
432
- datasetId,
433
- header,
434
- blockNumber
435
- }
436
- });
437
- }
438
- const block = await contract2.api.rpc.chain.getBlockHash(blockNumber);
439
- const randomProviderAndBlockNo = await this.contract.queryAtBlock(
440
- block,
441
- "getRandomActiveProvider",
442
- [userAccount, dappContractAccount]
13
+ if (!env.pair) {
14
+ throw new common.ProsopoEnvError("DEVELOPER.MISSING_PROVIDER_PAIR", {
15
+ context: { failedFuncName: "Tasks.constructor" }
16
+ });
17
+ }
18
+ this.pair = env.pair;
19
+ this.powCaptchaManager = new powTasks.PowCaptchaManager(this.pair, this.db);
20
+ this.datasetManager = new datasetTasks.DatasetManager(
21
+ this.config,
22
+ this.logger,
23
+ this.captchaConfig,
24
+ this.db
443
25
  );
444
- if (datasetId.toString().localeCompare(randomProviderAndBlockNo.provider.datasetId.toString())) {
445
- throw new common.ProsopoEnvError("DATASET.INVALID_DATASET_ID", {
446
- context: {
447
- failedFuncName: this.validateProviderWasRandomlyChosen.name,
448
- randomProviderAndBlockNo
449
- }
450
- });
451
- }
452
- }
453
- /**
454
- * Get payment info for a transaction
455
- * @param {string} userAccount
456
- * @param {string} blockHash
457
- * @param {string} txHash
458
- * @returns {Promise<RuntimeDispatchInfo|null>}
459
- */
460
- async getPaymentInfo(userAccount, blockHash, txHash) {
461
- const signedBlock = await this.contract.api.rpc.chain.getBlock(blockHash);
462
- if (!signedBlock) {
463
- return null;
464
- }
465
- const extrinsic = signedBlock.block.extrinsics.find((extrinsic2) => extrinsic2.hash.toString() === txHash);
466
- if (!extrinsic || extrinsic.signer.toString() !== userAccount) {
467
- return null;
468
- }
469
- const paymentInfo = await this.contract.api.rpc.payment.queryInfo(
470
- extrinsic.toHex(),
471
- blockHash
26
+ this.imgCaptchaManager = new imgCaptchaTasks.ImgCaptchaManager(
27
+ this.db,
28
+ this.pair,
29
+ this.logger,
30
+ this.captchaConfig
472
31
  );
473
- if (!paymentInfo) {
474
- return null;
475
- }
476
- return paymentInfo;
477
- }
478
- /*
479
- * Get dapp user solution from database
480
- */
481
- async getDappUserCommitmentById(commitmentId) {
482
- const dappUserSolution = await this.db.getDappUserCommitmentById(commitmentId);
483
- if (!dappUserSolution) {
484
- throw new common.ProsopoEnvError("CAPTCHA.DAPP_USER_SOLUTION_NOT_FOUND", {
485
- context: {
486
- failedFuncName: this.getDappUserCommitmentById.name,
487
- commitmentId
488
- }
489
- });
490
- }
491
- return dappUserSolution;
492
- }
493
- /* Check if dapp user has verified solution in cache */
494
- async getDappUserCommitmentByAccount(userAccount) {
495
- const dappUserSolutions = await this.db.getDappUserCommitmentByAccount(userAccount);
496
- if (dappUserSolutions.length > 0) {
497
- for (const dappUserSolution of dappUserSolutions) {
498
- if (dappUserSolution.status === typesReturns.CaptchaStatus.approved) {
499
- return dappUserSolution;
500
- }
501
- }
502
- }
503
- return void 0;
504
- }
505
- /* Returns public details of provider */
506
- async getProviderDetails() {
507
- const provider = await contract.wrapQuery(
508
- this.contract.query.getProvider,
509
- this.contract.query
510
- )(this.contract.pair.address);
511
- const dbConnectionOk = await this.getCaptchaWithProof(provider.datasetId, true, 1).then(() => true).catch(() => false);
512
- return { provider, dbConnectionOk };
513
- }
514
- /** Get the dataset from the database */
515
- async getProviderDataset(datasetId) {
516
- return await this.db.getDataset(datasetId);
517
- }
518
- async saveCaptchaEvent(events, accountId) {
519
- if (!this.config.devOnlyWatchEvents || !this.config.mongoEventsUri) {
520
- this.logger.info("Dev watch events not set to true, not saving events");
521
- return;
522
- }
523
- await database.saveCaptchaEvent(events, accountId, this.config.mongoEventsUri);
524
- }
525
- async storeCommitmentsExternal() {
526
- if (!this.config.mongoCaptchaUri) {
527
- this.logger.info("Mongo env not set");
528
- return;
529
- }
530
- const commitments = await this.db.getUnstoredDappUserCommitments();
531
- this.logger.info(`Storing ${commitments.length} commitments externally`);
532
- await database.saveCaptchas(commitments, this.config.mongoCaptchaUri);
533
- const commitIds = commitments.map((commitment) => commitment.id);
534
- await this.db.markDappUserCommitmentsStored(commitIds);
535
32
  }
536
33
  }
537
34
  exports.Tasks = Tasks;
package/dist/cjs/util.cjs CHANGED
@@ -1,16 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const common = require("@prosopo/common");
4
- const types = require("@prosopo/types");
5
- const util = require("@prosopo/util");
6
3
  const address = require("@polkadot/util-crypto/address");
7
4
  const hex = require("@polkadot/util/hex");
8
5
  const is = require("@polkadot/util/is");
6
+ const common = require("@prosopo/common");
7
+ const types = require("@prosopo/types");
8
+ const util = require("@prosopo/util");
9
9
  function encodeStringAddress(address$1) {
10
10
  try {
11
- return address.encodeAddress(is.isHex(address$1) ? hex.hexToU8a(address$1) : address.decodeAddress(address$1));
11
+ return address.encodeAddress(
12
+ is.isHex(address$1) ? hex.hexToU8a(address$1) : address.decodeAddress(address$1)
13
+ );
12
14
  } catch (err) {
13
- throw new common.ProsopoContractError("CONTRACT.INVALID_ADDRESS", { context: { address: address$1 } });
15
+ throw new common.ProsopoContractError("CONTRACT.INVALID_ADDRESS", {
16
+ context: { address: address$1 }
17
+ });
14
18
  }
15
19
  }
16
20
  function shuffleArray(array) {
@@ -24,26 +28,35 @@ function shuffleArray(array) {
24
28
  }
25
29
  async function promiseQueue(array) {
26
30
  const ret = [];
27
- await [...array, () => Promise.resolve(void 0)].reduce((promise, curr, i) => {
28
- return promise.then((res) => {
29
- if (res) {
30
- ret.push({ data: res });
31
- }
32
- return curr();
33
- }).catch((err) => {
34
- ret.push({ data: err });
35
- return curr();
36
- });
37
- }, Promise.resolve(void 0));
31
+ await [...array, () => Promise.resolve(void 0)].reduce(
32
+ (promise, curr, i) => {
33
+ return promise.then((res) => {
34
+ if (res) {
35
+ ret.push({ data: res });
36
+ }
37
+ return curr();
38
+ }).catch((err) => {
39
+ ret.push({ data: err });
40
+ return curr();
41
+ });
42
+ },
43
+ Promise.resolve(void 0)
44
+ );
38
45
  return ret;
39
46
  }
40
47
  function parseBlockNumber(blockNumberString) {
41
- return parseInt(blockNumberString.replace(/,/g, ""));
48
+ return Number.parseInt(blockNumberString.replace(/,/g, ""));
42
49
  }
43
50
  async function checkIfTaskIsRunning(taskName, db) {
44
- const runningTask = await db.getLastScheduledTaskStatus(taskName, types.ScheduledTaskStatus.Running);
51
+ const runningTask = await db.getLastScheduledTaskStatus(
52
+ taskName,
53
+ types.ScheduledTaskStatus.Running
54
+ );
45
55
  if (runningTask) {
46
- const completedTask = await db.getScheduledTaskStatus(runningTask.taskId, types.ScheduledTaskStatus.Completed);
56
+ const completedTask = await db.getScheduledTaskStatus(
57
+ runningTask.taskId,
58
+ types.ScheduledTaskStatus.Completed
59
+ );
47
60
  return !completedTask;
48
61
  }
49
62
  return false;
package/dist/index.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- export * from './tasks/index.js';
2
- export * from './util.js';
3
- export * from './batch/index.js';
4
- export * from './api/captcha.js';
5
- export * from './api/verify.js';
6
- export * from './api/admin.js';
7
- export * from './api/errorHandler.js';
8
- export * from './api/captchaScheduler.js';
1
+ export * from "./tasks/index.js";
2
+ export * from "./util.js";
3
+ export * from "./api/captcha.js";
4
+ export * from "./api/verify.js";
5
+ export * from "./api/admin.js";
6
+ export * from "./api/errorHandler.js";
7
+ export * from "./api/captchaScheduler.js";
9
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,kBAAkB,CAAA;AAChC,cAAc,WAAW,CAAA;AACzB,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC"}
package/dist/index.js CHANGED
@@ -1,9 +1,8 @@
1
- export * from './tasks/index.js';
2
- export * from './util.js';
3
- export * from './batch/index.js';
4
- export * from './api/captcha.js';
5
- export * from './api/verify.js';
6
- export * from './api/admin.js';
7
- export * from './api/errorHandler.js';
8
- export * from './api/captchaScheduler.js';
1
+ export * from "./tasks/index.js";
2
+ export * from "./util.js";
3
+ export * from "./api/captcha.js";
4
+ export * from "./api/verify.js";
5
+ export * from "./api/admin.js";
6
+ export * from "./api/errorHandler.js";
7
+ export * from "./api/captchaScheduler.js";
9
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,kBAAkB,CAAA;AAChC,cAAc,WAAW,CAAA;AACzB,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,uBAAuB,CAAA;AACrC,cAAc,2BAA2B,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,cAAc,2BAA2B,CAAC"}