@prosopo/provider 2.0.1 → 2.0.3

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 (124) hide show
  1. package/dist/api/captcha.d.ts.map +1 -1
  2. package/dist/api/captcha.js +15 -9
  3. package/dist/api/captcha.js.map +1 -1
  4. package/dist/api/captchaScheduler.d.ts +1 -1
  5. package/dist/api/captchaScheduler.d.ts.map +1 -1
  6. package/dist/api/captchaScheduler.js +10 -4
  7. package/dist/api/captchaScheduler.js.map +1 -1
  8. package/dist/api/verify.d.ts.map +1 -1
  9. package/dist/api/verify.js +22 -9
  10. package/dist/api/verify.js.map +1 -1
  11. package/dist/cjs/api/captcha.cjs +51 -39
  12. package/dist/cjs/api/captchaScheduler.cjs +17 -4
  13. package/dist/cjs/api/verify.cjs +22 -10
  14. package/dist/cjs/index.cjs +0 -2
  15. package/dist/cjs/tasks/dataset/datasetTasks.cjs +68 -11
  16. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +35 -34
  17. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +53 -28
  18. package/dist/cjs/tasks/powCaptcha/powTasksUtils.cjs +0 -29
  19. package/dist/cjs/util.cjs +1 -24
  20. package/dist/tasks/dataset/datasetTasks.d.ts +2 -2
  21. package/dist/tasks/dataset/datasetTasks.d.ts.map +1 -1
  22. package/dist/tasks/dataset/datasetTasks.js +39 -8
  23. package/dist/tasks/dataset/datasetTasks.js.map +1 -1
  24. package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts +6 -6
  25. package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts.map +1 -1
  26. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +22 -27
  27. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js.map +1 -1
  28. package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.d.ts.map +1 -1
  29. package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.js.map +1 -1
  30. package/dist/tasks/powCaptcha/powTasks.d.ts +2 -2
  31. package/dist/tasks/powCaptcha/powTasks.d.ts.map +1 -1
  32. package/dist/tasks/powCaptcha/powTasks.js +40 -23
  33. package/dist/tasks/powCaptcha/powTasks.js.map +1 -1
  34. package/dist/tasks/powCaptcha/powTasksUtils.d.ts +0 -2
  35. package/dist/tasks/powCaptcha/powTasksUtils.d.ts.map +1 -1
  36. package/dist/tasks/powCaptcha/powTasksUtils.js +0 -27
  37. package/dist/tasks/powCaptcha/powTasksUtils.js.map +1 -1
  38. package/dist/tests/integration/imgCaptcha.integration.test.d.ts +2 -0
  39. package/dist/tests/integration/imgCaptcha.integration.test.d.ts.map +1 -0
  40. package/dist/tests/integration/{imgCaptcha.test.js → imgCaptcha.integration.test.js} +9 -5
  41. package/dist/tests/integration/imgCaptcha.integration.test.js.map +1 -0
  42. package/dist/tests/integration/mocks/solvedTestCaptchas.d.ts +5 -1
  43. package/dist/tests/integration/mocks/solvedTestCaptchas.d.ts.map +1 -1
  44. package/dist/tests/integration/mocks/solvedTestCaptchas.js +4 -0
  45. package/dist/tests/integration/mocks/solvedTestCaptchas.js.map +1 -1
  46. package/dist/tests/integration/powCaptcha.integration.test.d.ts +2 -0
  47. package/dist/tests/integration/powCaptcha.integration.test.d.ts.map +1 -0
  48. package/dist/tests/integration/{powCaptcha.test.js → powCaptcha.integration.test.js} +12 -10
  49. package/dist/tests/integration/powCaptcha.integration.test.js.map +1 -0
  50. package/dist/tests/unit/api/authMiddleware.unit.test.d.ts +2 -0
  51. package/dist/tests/unit/api/authMiddleware.unit.test.d.ts.map +1 -0
  52. package/dist/tests/unit/api/{authMiddleware.test.js → authMiddleware.unit.test.js} +1 -1
  53. package/dist/tests/unit/api/authMiddleware.unit.test.js.map +1 -0
  54. package/dist/tests/unit/api/captchaScheduler.unit.test.d.ts +2 -0
  55. package/dist/tests/unit/api/captchaScheduler.unit.test.d.ts.map +1 -0
  56. package/dist/tests/unit/api/{captchaScheduler.test.js → captchaScheduler.unit.test.js} +20 -6
  57. package/dist/tests/unit/api/captchaScheduler.unit.test.js.map +1 -0
  58. package/dist/tests/unit/api/errorHandler.unit.test.d.ts +2 -0
  59. package/dist/tests/unit/api/errorHandler.unit.test.d.ts.map +1 -0
  60. package/dist/tests/unit/api/{errorHandler.test.js → errorHandler.unit.test.js} +1 -1
  61. package/dist/tests/unit/api/errorHandler.unit.test.js.map +1 -0
  62. package/dist/tests/unit/tasks/dataset/datasetTasks.unit.test.d.ts +2 -0
  63. package/dist/tests/unit/tasks/dataset/datasetTasks.unit.test.d.ts.map +1 -0
  64. package/dist/tests/unit/tasks/dataset/datasetTasks.unit.test.js +188 -0
  65. package/dist/tests/unit/tasks/dataset/datasetTasks.unit.test.js.map +1 -0
  66. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.d.ts +2 -0
  67. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.d.ts.map +1 -0
  68. package/dist/tests/unit/tasks/dataset/{datasetTasksUtils.test.js → datasetTasksUtils.unit.test.js} +1 -1
  69. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.js.map +1 -0
  70. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.d.ts +2 -0
  71. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.d.ts.map +1 -0
  72. package/dist/tests/unit/tasks/imgCaptcha/{imgCaptchaTasks.test.js → imgCaptchaTasks.unit.test.js} +27 -25
  73. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.js.map +1 -0
  74. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.d.ts +2 -0
  75. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.d.ts.map +1 -0
  76. package/dist/tests/unit/tasks/imgCaptcha/{imgCaptchaTasksUtils.test.js → imgCaptchaTasksUtils.unit.test.js} +1 -1
  77. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js.map +1 -0
  78. package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.d.ts +2 -0
  79. package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.d.ts.map +1 -0
  80. package/dist/tests/unit/tasks/powCaptcha/{powTasks.test.js → powTasks.unit.test.js} +104 -33
  81. package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js.map +1 -0
  82. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.d.ts +2 -0
  83. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.d.ts.map +1 -0
  84. package/dist/tests/unit/tasks/powCaptcha/{powTasksUtils.test.js → powTasksUtils.unit.test.js} +6 -35
  85. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.js.map +1 -0
  86. package/dist/util.d.ts +0 -7
  87. package/dist/util.d.ts.map +1 -1
  88. package/dist/util.js +1 -21
  89. package/dist/util.js.map +1 -1
  90. package/package.json +72 -73
  91. package/dist/tests/integration/imgCaptcha.test.d.ts +0 -2
  92. package/dist/tests/integration/imgCaptcha.test.d.ts.map +0 -1
  93. package/dist/tests/integration/imgCaptcha.test.js.map +0 -1
  94. package/dist/tests/integration/powCaptcha.test.d.ts +0 -2
  95. package/dist/tests/integration/powCaptcha.test.d.ts.map +0 -1
  96. package/dist/tests/integration/powCaptcha.test.js.map +0 -1
  97. package/dist/tests/unit/api/authMiddleware.test.d.ts +0 -2
  98. package/dist/tests/unit/api/authMiddleware.test.d.ts.map +0 -1
  99. package/dist/tests/unit/api/authMiddleware.test.js.map +0 -1
  100. package/dist/tests/unit/api/captchaScheduler.test.d.ts +0 -2
  101. package/dist/tests/unit/api/captchaScheduler.test.d.ts.map +0 -1
  102. package/dist/tests/unit/api/captchaScheduler.test.js.map +0 -1
  103. package/dist/tests/unit/api/errorHandler.test.d.ts +0 -2
  104. package/dist/tests/unit/api/errorHandler.test.d.ts.map +0 -1
  105. package/dist/tests/unit/api/errorHandler.test.js.map +0 -1
  106. package/dist/tests/unit/tasks/dataset/datasetTasks.test.d.ts +0 -2
  107. package/dist/tests/unit/tasks/dataset/datasetTasks.test.d.ts.map +0 -1
  108. package/dist/tests/unit/tasks/dataset/datasetTasks.test.js +0 -88
  109. package/dist/tests/unit/tasks/dataset/datasetTasks.test.js.map +0 -1
  110. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.test.d.ts +0 -2
  111. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.test.d.ts.map +0 -1
  112. package/dist/tests/unit/tasks/dataset/datasetTasksUtils.test.js.map +0 -1
  113. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.test.d.ts +0 -2
  114. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.test.d.ts.map +0 -1
  115. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.test.js.map +0 -1
  116. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.test.d.ts +0 -2
  117. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.test.d.ts.map +0 -1
  118. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.test.js.map +0 -1
  119. package/dist/tests/unit/tasks/powCaptcha/powTasks.test.d.ts +0 -2
  120. package/dist/tests/unit/tasks/powCaptcha/powTasks.test.d.ts.map +0 -1
  121. package/dist/tests/unit/tasks/powCaptcha/powTasks.test.js.map +0 -1
  122. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.test.d.ts +0 -2
  123. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.test.d.ts.map +0 -1
  124. package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.test.js.map +0 -1
@@ -29,7 +29,7 @@ class ImgCaptchaManager {
29
29
  }
30
30
  return captchaDocs;
31
31
  }
32
- async getRandomCaptchasAndRequestHash(datasetId, userAccount) {
32
+ async getRandomCaptchasAndRequestHash(datasetId, userAccount, ipAddress) {
33
33
  const dataset = await this.db.getDatasetDetails(datasetId);
34
34
  if (!dataset) {
35
35
  throw new common.ProsopoEnvError("DATABASE.DATASET_GET_FAILED", {
@@ -66,8 +66,8 @@ class ImgCaptchaManager {
66
66
  salt
67
67
  );
68
68
  const currentTime = Date.now();
69
- const signedTimestamp = util$1.u8aToHex(
70
- this.pair.sign(util$1.stringToHex(currentTime.toString()))
69
+ const signedRequestHash = util$1.u8aToHex(
70
+ this.pair.sign(util$1.stringToHex(requestHash))
71
71
  );
72
72
  const timeLimit = captchas.map((captcha) => captcha.timeLimitMs || types.DEFAULT_IMAGE_CAPTCHA_TIMEOUT).reduce((a, b) => a + b, 0);
73
73
  const deadlineTs = timeLimit + currentTime;
@@ -77,13 +77,14 @@ class ImgCaptchaManager {
77
77
  requestHash,
78
78
  salt,
79
79
  deadlineTs,
80
- currentBlockNumber
80
+ currentTime,
81
+ ipAddress
81
82
  );
82
83
  return {
83
84
  captchas,
84
85
  requestHash,
85
86
  timestamp: currentTime,
86
- signedTimestamp
87
+ signedRequestHash
87
88
  };
88
89
  }
89
90
  /**
@@ -92,35 +93,36 @@ class ImgCaptchaManager {
92
93
  * @param {string} dappAccount
93
94
  * @param {string} requestHash
94
95
  * @param {JSON} captchas
95
- * @param {string} requestHashSignature
96
+ * @param {string} userRequestHashSignature
96
97
  * @param timestamp
97
- * @param timestampSignature
98
+ * @param providerRequestHashSignature
99
+ * @param ipAddress
98
100
  * @return {Promise<DappUserSolutionResult>} result containing the contract event
99
101
  */
100
- async dappUserSolution(userAccount, dappAccount, requestHash, captchas, requestHashSignature, timestamp, timestampSignature) {
102
+ async dappUserSolution(userAccount, dappAccount, requestHash, captchas, userRequestHashSignature, timestamp, providerRequestHashSignature, ipAddress) {
101
103
  const verification = utilCrypto.signatureVerify(
102
104
  util$1.stringToHex(requestHash),
103
- requestHashSignature,
105
+ userRequestHashSignature,
104
106
  userAccount
105
107
  );
106
108
  if (!verification.isValid) {
107
- this.logger.info("Invalid requestHash signature");
109
+ this.logger.info("Invalid user requestHash signature");
108
110
  throw new common.ProsopoEnvError("GENERAL.INVALID_SIGNATURE", {
109
111
  context: { failedFuncName: this.dappUserSolution.name, userAccount }
110
112
  });
111
113
  }
112
- const timestampSigVerify = utilCrypto.signatureVerify(
113
- util$1.stringToHex(timestamp.toString()),
114
- timestampSignature,
114
+ const providerRequestHashSignatureVerify = utilCrypto.signatureVerify(
115
+ util$1.stringToHex(requestHash.toString()),
116
+ providerRequestHashSignature,
115
117
  this.pair.address
116
118
  );
117
- if (!timestampSigVerify.isValid) {
118
- this.logger.info("Invalid timestamp signature");
119
+ if (!providerRequestHashSignatureVerify.isValid) {
120
+ this.logger.info("Invalid provider requestHash signature");
119
121
  throw new common.ProsopoEnvError("GENERAL.INVALID_SIGNATURE", {
120
122
  context: {
121
123
  failedFuncName: this.dappUserSolution.name,
122
124
  userAccount,
123
- error: "timestamp signature is invalid"
125
+ error: "requestHash signature is invalid"
124
126
  }
125
127
  });
126
128
  }
@@ -136,7 +138,6 @@ class ImgCaptchaManager {
136
138
  userAccount,
137
139
  unverifiedCaptchaIds
138
140
  );
139
- console.log("Pending request", pendingRequest);
140
141
  if (pendingRequest) {
141
142
  const { storedCaptchas, receivedCaptchas, captchaIds } = await this.validateReceivedCaptchasAgainstStoredCaptchas(captchas);
142
143
  const { tree, commitmentId } = imgCaptchaTasksUtils.buildTreeAndGetCommitmentId(receivedCaptchas);
@@ -146,28 +147,21 @@ class ImgCaptchaManager {
146
147
  context: { failedFuncName: this.dappUserSolution.name }
147
148
  });
148
149
  }
149
- const userSignature = util$1.hexToU8a(requestHashSignature);
150
150
  await this.db.updateDappUserPendingStatus(requestHash);
151
151
  const commit = {
152
152
  id: commitmentId,
153
153
  userAccount,
154
- dappContract: dappAccount,
154
+ dappAccount,
155
155
  providerAccount: this.pair.address,
156
156
  datasetId,
157
- status: types.CaptchaStatus.pending,
158
- userSignature: Array.from(userSignature),
159
- requestedAt: pendingRecord.requestedAtBlock,
160
- // TODO is this correct or should it be block number?
161
- completedAt: 0,
162
- //temp
163
- processed: false,
164
- batched: false,
165
- stored: false,
166
- requestedAtTimestamp: timestamp
157
+ result: { status: types.CaptchaStatus.pending },
158
+ userSignature: userRequestHashSignature,
159
+ userSubmitted: true,
160
+ serverChecked: false,
161
+ requestedAtTimestamp: timestamp,
162
+ ipAddress
167
163
  };
168
164
  await this.db.storeDappUserSolution(receivedCaptchas, commit);
169
- console.log(receivedCaptchas);
170
- console.log(storedCaptchas);
171
165
  if (datasets.compareCaptchaSolutions(receivedCaptchas, storedCaptchas)) {
172
166
  response = {
173
167
  captchas: captchaIds.map((id) => ({
@@ -178,6 +172,10 @@ class ImgCaptchaManager {
178
172
  };
179
173
  await this.db.approveDappUserCommitment(commitmentId);
180
174
  } else {
175
+ await this.db.disapproveDappUserCommitment(
176
+ commitmentId,
177
+ "CAPTCHA.INVALID_SOLUTION"
178
+ );
181
179
  response = {
182
180
  captchas: captchaIds.map((id) => ({
183
181
  captchaId: id,
@@ -262,11 +260,14 @@ class ImgCaptchaManager {
262
260
  return dappUserSolution;
263
261
  }
264
262
  /* Check if dapp user has verified solution in cache */
265
- async getDappUserCommitmentByAccount(userAccount) {
266
- const dappUserSolutions = await this.db.getDappUserCommitmentByAccount(userAccount);
263
+ async getDappUserCommitmentByAccount(userAccount, dappAccount) {
264
+ const dappUserSolutions = await this.db.getDappUserCommitmentByAccount(
265
+ userAccount,
266
+ dappAccount
267
+ );
267
268
  if (dappUserSolutions.length > 0) {
268
269
  for (const dappUserSolution of dappUserSolutions) {
269
- if (dappUserSolution.status === types.CaptchaStatus.approved) {
270
+ if (dappUserSolution.result.status === types.CaptchaStatus.approved) {
270
271
  return dappUserSolution;
271
272
  }
272
273
  }
@@ -5,6 +5,7 @@ const common = require("@prosopo/common");
5
5
  const types = require("@prosopo/types");
6
6
  const util$1 = require("@prosopo/util");
7
7
  const powTasksUtils = require("./powTasksUtils.cjs");
8
+ const logger = common.getLoggerDefault();
8
9
  class PowCaptchaManager {
9
10
  constructor(pair, db) {
10
11
  this.pair = pair;
@@ -20,18 +21,14 @@ class PowCaptchaManager {
20
21
  */
21
22
  async getPowCaptchaChallenge(userAccount, dappAccount, origin) {
22
23
  const difficulty = 4;
23
- const timestamp = Date.now();
24
- const challenge = `${timestamp}___${userAccount}___${dappAccount}`;
24
+ const requestedAtTimestamp = Date.now();
25
+ const challenge = `${requestedAtTimestamp}___${userAccount}___${dappAccount}`;
25
26
  const challengeSignature = util.u8aToHex(this.pair.sign(util.stringToHex(challenge)));
26
- const timestampSignature = util.u8aToHex(
27
- this.pair.sign(util.stringToHex(timestamp.toString()))
28
- );
29
27
  return {
30
28
  challenge,
31
29
  difficulty,
32
- signature: challengeSignature,
33
- timestamp,
34
- timestampSignature
30
+ providerSignature: challengeSignature,
31
+ requestedAtTimestamp
35
32
  };
36
33
  }
37
34
  /**
@@ -39,36 +36,62 @@ class PowCaptchaManager {
39
36
  *
40
37
  * @param {string} challenge - the starting string for the PoW challenge
41
38
  * @param {string} difficulty - how many leading zeroes the solution must have
42
- * @param {string} signature - proof that the Provider provided the challenge
39
+ * @param {string} providerChallengeSignature - proof that the Provider provided the challenge
43
40
  * @param {string} nonce - the string that the user has found that satisfies the PoW challenge
44
41
  * @param {number} timeout - the time in milliseconds since the Provider was selected to provide the PoW captcha
45
- * @param timestampSignature
42
+ * @param {string} userTimestampSignature
43
+ * @param ipAddress
46
44
  */
47
- async verifyPowCaptchaSolution(challenge, difficulty, signature, nonce, timeout, timestampSignature) {
48
- powTasksUtils.checkRecentPowSolution(challenge, timeout);
45
+ async verifyPowCaptchaSolution(challenge, difficulty, providerChallengeSignature, nonce, timeout, userTimestampSignature, ipAddress) {
46
+ powTasksUtils.checkPowSignature(
47
+ challenge,
48
+ providerChallengeSignature,
49
+ this.pair.address,
50
+ types.ApiParams.challenge
51
+ );
49
52
  const challengeSplit = challenge.split(this.POW_SEPARATOR);
50
53
  const timestamp = parseInt(util$1.at(challengeSplit, 0));
51
54
  const userAccount = util$1.at(challengeSplit, 1);
52
- const dappAccount = util$1.at(challengeSplit, 2);
53
55
  powTasksUtils.checkPowSignature(
54
56
  timestamp.toString(),
55
- timestampSignature,
57
+ userTimestampSignature,
56
58
  userAccount,
57
59
  types.ApiParams.timestamp
58
60
  );
59
- powTasksUtils.checkPowSignature(
60
- challenge,
61
- signature,
62
- this.pair.address,
63
- types.ApiParams.challenge
64
- );
65
- powTasksUtils.checkPowSolution(nonce, challenge, difficulty);
66
- await this.db.storePowCaptchaRecord(
61
+ const challengeRecord = await this.db.getPowCaptchaRecordByChallenge(challenge);
62
+ if (!challengeRecord) {
63
+ logger.debug("No record of this challenge");
64
+ return false;
65
+ }
66
+ if (!util$1.verifyRecency(challenge, timeout)) {
67
+ await this.db.updatePowCaptchaRecord(
68
+ challenge,
69
+ {
70
+ status: types.CaptchaStatus.disapproved,
71
+ reason: "CAPTCHA.INVALID_TIMESTAMP"
72
+ },
73
+ false,
74
+ true,
75
+ userTimestampSignature
76
+ );
77
+ return false;
78
+ }
79
+ const correct = powTasksUtils.validateSolution(nonce, challenge, difficulty);
80
+ let result = { status: types.CaptchaStatus.approved };
81
+ if (!correct) {
82
+ result = {
83
+ status: types.CaptchaStatus.disapproved,
84
+ reason: "CAPTCHA.INVALID_SOLUTION"
85
+ };
86
+ }
87
+ await this.db.updatePowCaptchaRecord(
67
88
  challenge,
68
- { timestamp, userAccount, dappAccount },
69
- false
89
+ result,
90
+ false,
91
+ true,
92
+ userTimestampSignature
70
93
  );
71
- return true;
94
+ return correct;
72
95
  }
73
96
  /**
74
97
  * @description Verifies a PoW Captcha for a given user and dapp. This is called by the server to verify the user's solution
@@ -88,7 +111,7 @@ class PowCaptchaManager {
88
111
  }
89
112
  });
90
113
  }
91
- if (challengeRecord.checked) return false;
114
+ if (challengeRecord.serverChecked) return false;
92
115
  const challengeDappAccount = challengeRecord.dappAccount;
93
116
  if (dappAccount !== challengeDappAccount) {
94
117
  throw new common.ProsopoEnvError("CAPTCHA.DAPP_USER_SOLUTION_NOT_FOUND", {
@@ -99,8 +122,10 @@ class PowCaptchaManager {
99
122
  }
100
123
  });
101
124
  }
102
- powTasksUtils.checkRecentPowSolution(challenge, timeout);
103
- await this.db.updatePowCaptchaRecord(challengeRecord.challenge, true);
125
+ util$1.verifyRecency(challenge, timeout);
126
+ await this.db.markDappUserPoWCommitmentsChecked([
127
+ challengeRecord.challenge
128
+ ]);
104
129
  return true;
105
130
  }
106
131
  }
@@ -4,22 +4,7 @@ const sha256 = require("@noble/hashes/sha256");
4
4
  const util = require("@polkadot/util");
5
5
  const utilCrypto = require("@polkadot/util-crypto");
6
6
  const common = require("@prosopo/common");
7
- const contract = require("@prosopo/contract");
8
7
  const validateSolution = (nonce, challenge, difficulty) => Array.from(sha256.sha256(new TextEncoder().encode(nonce + challenge))).map((byte) => byte.toString(16).padStart(2, "0")).join("").startsWith("0".repeat(difficulty));
9
- const checkPowSolution = (nonce, challenge, difficulty) => {
10
- const solutionValid = validateSolution(nonce, challenge, difficulty);
11
- if (!solutionValid) {
12
- throw new common.ProsopoContractError("API.CAPTCHA_FAILED", {
13
- context: {
14
- ERROR: "Captcha solution is invalid",
15
- failedFuncName: checkPowSolution.name,
16
- nonce,
17
- challenge,
18
- difficulty
19
- }
20
- });
21
- }
22
- };
23
8
  const checkPowSignature = (challenge, signature, address, signatureType) => {
24
9
  const signatureVerification = utilCrypto.signatureVerify(
25
10
  util.stringToHex(challenge),
@@ -37,19 +22,5 @@ const checkPowSignature = (challenge, signature, address, signatureType) => {
37
22
  });
38
23
  }
39
24
  };
40
- const checkRecentPowSolution = (challenge, timeout) => {
41
- const recent = contract.verifyRecency(challenge, timeout);
42
- if (!recent) {
43
- throw new common.ProsopoContractError("CONTRACT.INVALID_BLOCKHASH", {
44
- context: {
45
- ERROR: `Block in which the Provider was selected must be within the last ${timeout / 1e3} seconds`,
46
- failedFuncName: checkRecentPowSolution.name,
47
- challenge
48
- }
49
- });
50
- }
51
- };
52
25
  exports.checkPowSignature = checkPowSignature;
53
- exports.checkPowSolution = checkPowSolution;
54
- exports.checkRecentPowSolution = checkRecentPowSolution;
55
26
  exports.validateSolution = validateSolution;
package/dist/cjs/util.cjs CHANGED
@@ -26,27 +26,6 @@ function shuffleArray(array) {
26
26
  }
27
27
  return array;
28
28
  }
29
- async function promiseQueue(array) {
30
- const ret = [];
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
- );
45
- return ret;
46
- }
47
- function parseBlockNumber(blockNumberString) {
48
- return Number.parseInt(blockNumberString.replace(/,/g, ""));
49
- }
50
29
  async function checkIfTaskIsRunning(taskName, db) {
51
30
  const runningTask = await db.getLastScheduledTaskStatus(
52
31
  taskName,
@@ -54,7 +33,7 @@ async function checkIfTaskIsRunning(taskName, db) {
54
33
  );
55
34
  if (runningTask) {
56
35
  const completedTask = await db.getScheduledTaskStatus(
57
- runningTask.taskId,
36
+ runningTask.id,
58
37
  types.ScheduledTaskStatus.Completed
59
38
  );
60
39
  return !completedTask;
@@ -63,6 +42,4 @@ async function checkIfTaskIsRunning(taskName, db) {
63
42
  }
64
43
  exports.checkIfTaskIsRunning = checkIfTaskIsRunning;
65
44
  exports.encodeStringAddress = encodeStringAddress;
66
- exports.parseBlockNumber = parseBlockNumber;
67
- exports.promiseQueue = promiseQueue;
68
45
  exports.shuffleArray = shuffleArray;
@@ -1,6 +1,6 @@
1
- import type { Logger } from "@prosopo/common";
2
- import type { CaptchaConfig, DatasetRaw, ProsopoConfigOutput, StoredEvents } from "@prosopo/types";
1
+ import { CaptchaConfig, DatasetRaw, ProsopoConfigOutput, StoredEvents } from "@prosopo/types";
3
2
  import type { Database } from "@prosopo/types-database";
3
+ import type { Logger } from "@prosopo/common";
4
4
  export declare class DatasetManager {
5
5
  config: ProsopoConfigOutput;
6
6
  logger: Logger;
@@ -1 +1 @@
1
- {"version":3,"file":"datasetTasks.d.ts","sourceRoot":"","sources":["../../../src/tasks/dataset/datasetTasks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAgB9C,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EAEV,mBAAmB,EACnB,YAAY,EACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAwB,MAAM,yBAAyB,CAAC;AAG9E,qBAAa,cAAc;IACzB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,aAAa,CAAC;IAC7B,EAAE,EAAE,QAAQ,CAAC;gBAGX,MAAM,EAAE,mBAAmB,EAC3B,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,EAC5B,EAAE,EAAE,QAAQ;IAaR,0BAA0B,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrD,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBzD,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM;IAYxD,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;CAoBhD"}
1
+ {"version":3,"file":"datasetTasks.d.ts","sourceRoot":"","sources":["../../../src/tasks/dataset/datasetTasks.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,aAAa,EACb,UAAU,EACV,mBAAmB,EAGnB,YAAY,EACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAExD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAG9C,qBAAa,cAAc;IACzB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,aAAa,CAAC;IAC7B,EAAE,EAAE,QAAQ,CAAC;gBAGX,MAAM,EAAE,mBAAmB,EAC3B,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,EAC5B,EAAE,EAAE,QAAQ;IAaR,0BAA0B,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrD,kBAAkB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBzD,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM;IAYxD,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;CA8FhD"}
@@ -1,6 +1,7 @@
1
- import { saveCaptchaEvent, saveCaptchas } from "@prosopo/database";
2
1
  import { parseCaptchaDataset } from "@prosopo/datasets";
2
+ import { ScheduledTaskNames, ScheduledTaskStatus, } from "@prosopo/types";
3
3
  import { providerValidateDataset } from "./datasetTasksUtils.js";
4
+ import { saveCaptchaEvent, saveCaptchas } from "@prosopo/database";
4
5
  export class DatasetManager {
5
6
  constructor(config, logger, captchaConfig, db) {
6
7
  this.config = config;
@@ -28,13 +29,43 @@ export class DatasetManager {
28
29
  this.logger.info("Mongo env not set");
29
30
  return;
30
31
  }
31
- const commitments = await this.db.getUnstoredDappUserCommitments();
32
- this.logger.info(`Storing ${commitments.length} commitments externally`);
33
- const powRecords = await this.db.getUnstoredDappUserPoWCommitments();
34
- this.logger.info(`Storing ${powRecords.length} pow challenges externally`);
35
- await saveCaptchas(commitments, powRecords, this.config.mongoCaptchaUri);
36
- await this.db.markDappUserCommitmentsStored(commitments.map((commitment) => commitment.id));
37
- await this.db.markDappUserPoWCommitmentsStored(powRecords.map((powRecords) => powRecords.challenge));
32
+ const lastTask = await this.db.getLastScheduledTaskStatus(ScheduledTaskNames.StoreCommitmentsExternal, ScheduledTaskStatus.Completed);
33
+ const taskID = await this.db.createScheduledTaskStatus(ScheduledTaskNames.StoreCommitmentsExternal, ScheduledTaskStatus.Running);
34
+ try {
35
+ let commitments = await this.db.getUnstoredDappUserCommitments();
36
+ let powRecords = await this.db.getUnstoredDappUserPoWCommitments();
37
+ if (lastTask) {
38
+ this.logger.info(`Filtering records to only get updated records: ${JSON.stringify(lastTask)}`);
39
+ this.logger.info("Last task ran at ", new Date(lastTask.updated || 0), "Task ID", taskID);
40
+ commitments = commitments.filter((commitment) => lastTask.updated &&
41
+ commitment.lastUpdatedTimestamp &&
42
+ (commitment.lastUpdatedTimestamp > lastTask.updated ||
43
+ !commitment.lastUpdatedTimestamp));
44
+ powRecords = powRecords.filter((commitment) => {
45
+ return (lastTask.updated &&
46
+ commitment.lastUpdatedTimestamp &&
47
+ (commitment.lastUpdatedTimestamp > lastTask.updated ||
48
+ !commitment.lastUpdatedTimestamp));
49
+ });
50
+ }
51
+ if (commitments.length || powRecords.length) {
52
+ this.logger.info(`Storing ${commitments.length} commitments externally`);
53
+ this.logger.info(`Storing ${powRecords.length} pow challenges externally`);
54
+ await saveCaptchas(commitments, powRecords, this.config.mongoCaptchaUri);
55
+ await this.db.markDappUserCommitmentsStored(commitments.map((commitment) => commitment.id));
56
+ await this.db.markDappUserPoWCommitmentsStored(powRecords.map((powRecords) => powRecords.challenge));
57
+ }
58
+ await this.db.updateScheduledTaskStatus(taskID, ScheduledTaskStatus.Completed, {
59
+ data: {
60
+ commitments: commitments.map((c) => c.id),
61
+ powRecords: powRecords.map((pr) => pr.challenge),
62
+ },
63
+ });
64
+ }
65
+ catch (e) {
66
+ this.logger.error(e);
67
+ await this.db.updateScheduledTaskStatus(taskID, ScheduledTaskStatus.Failed, { error: e.toString() });
68
+ }
38
69
  }
39
70
  }
40
71
  //# sourceMappingURL=datasetTasks.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"datasetTasks.js","sourceRoot":"","sources":["../../../src/tasks/dataset/datasetTasks.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAcnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AASxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,MAAM,OAAO,cAAc;IAMzB,YACE,MAA2B,EAC3B,MAAc,EACd,aAA4B,EAC5B,EAAY;QAEZ,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACf,CAAC;IAOD,KAAK,CAAC,0BAA0B,CAAC,IAAU;QACzC,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;QAC7C,OAAO,MAAM,IAAI,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,UAAsB;QAC7C,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAC3C,UAAU,EACV,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,EAC/B,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAClC,CAAC;QAEF,MAAM,IAAI,CAAC,EAAE,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;IAWD,KAAK,CAAC,gBAAgB,CAAC,MAAoB,EAAE,SAAiB;QAC5D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE;YAClE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;YACxE,OAAO;SACR;QACD,MAAM,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IACxE,CAAC;IAMD,KAAK,CAAC,wBAAwB;QAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE;YAChC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACtC,OAAO;SACR;QAED,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,8BAA8B,EAAE,CAAC;QACnE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,WAAW,CAAC,MAAM,yBAAyB,CAAC,CAAC;QAEzE,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,iCAAiC,EAAE,CAAC;QACrE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,UAAU,CAAC,MAAM,4BAA4B,CAAC,CAAC;QAE3E,MAAM,YAAY,CAAC,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QACzE,MAAM,IAAI,CAAC,EAAE,CAAC,6BAA6B,CACzC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAC/C,CAAC;QACF,MAAM,IAAI,CAAC,EAAE,CAAC,gCAAgC,CAC5C,UAAU,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CACrD,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"datasetTasks.js","sourceRoot":"","sources":["../../../src/tasks/dataset/datasetTasks.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import type { KeyringPair } from "@polkadot/keyring/types";
2
2
  import { type Logger } from "@prosopo/common";
3
3
  import { type Captcha, type CaptchaConfig, type CaptchaSolution, type DappUserSolutionResult, type Hash, type PendingCaptchaRequest } from "@prosopo/types";
4
- import type { Database, UserCommitmentRecord } from "@prosopo/types-database";
4
+ import { Database, UserCommitment } from "@prosopo/types-database";
5
5
  export declare class ImgCaptchaManager {
6
6
  db: Database;
7
7
  pair: KeyringPair;
@@ -9,20 +9,20 @@ export declare class ImgCaptchaManager {
9
9
  captchaConfig: CaptchaConfig;
10
10
  constructor(db: Database, pair: KeyringPair, logger: Logger, captchaConfig: CaptchaConfig);
11
11
  getCaptchaWithProof(datasetId: Hash, solved: boolean, size: number): Promise<Captcha[]>;
12
- getRandomCaptchasAndRequestHash(datasetId: string, userAccount: string): Promise<{
12
+ getRandomCaptchasAndRequestHash(datasetId: string, userAccount: string, ipAddress: string): Promise<{
13
13
  captchas: Captcha[];
14
14
  requestHash: string;
15
15
  timestamp: number;
16
- signedTimestamp: string;
16
+ signedRequestHash: string;
17
17
  }>;
18
- dappUserSolution(userAccount: string, dappAccount: string, requestHash: string, captchas: CaptchaSolution[], requestHashSignature: string, timestamp: number, timestampSignature: string): Promise<DappUserSolutionResult>;
18
+ dappUserSolution(userAccount: string, dappAccount: string, requestHash: string, captchas: CaptchaSolution[], userRequestHashSignature: string, timestamp: number, providerRequestHashSignature: string, ipAddress: string): Promise<DappUserSolutionResult>;
19
19
  validateReceivedCaptchasAgainstStoredCaptchas(captchas: CaptchaSolution[]): Promise<{
20
20
  storedCaptchas: Captcha[];
21
21
  receivedCaptchas: CaptchaSolution[];
22
22
  captchaIds: string[];
23
23
  }>;
24
24
  validateDappUserSolutionRequestIsPending(requestHash: string, pendingRecord: PendingCaptchaRequest, userAccount: string, captchaIds: string[]): Promise<boolean>;
25
- getDappUserCommitmentById(commitmentId: string): Promise<UserCommitmentRecord>;
26
- getDappUserCommitmentByAccount(userAccount: string): Promise<UserCommitmentRecord | undefined>;
25
+ getDappUserCommitmentById(commitmentId: string): Promise<UserCommitment>;
26
+ getDappUserCommitmentByAccount(userAccount: string, dappAccount: string): Promise<UserCommitment | undefined>;
27
27
  }
28
28
  //# sourceMappingURL=imgCaptchaTasks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"imgCaptchaTasks.d.ts","sourceRoot":"","sources":["../../../src/tasks/imgCaptcha/imgCaptchaTasks.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAG3D,OAAO,EAAE,KAAK,MAAM,EAAmB,MAAM,iBAAiB,CAAC;AAM/D,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,aAAa,EAClB,KAAK,eAAe,EAGpB,KAAK,sBAAsB,EAC3B,KAAK,IAAI,EACT,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAK9E,qBAAa,iBAAiB;IAC5B,EAAE,EAAE,QAAQ,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,aAAa,CAAC;gBAG3B,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa;IAQxB,mBAAmB,CACvB,SAAS,EAAE,IAAI,EACf,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,EAAE,CAAC;IAgBf,+BAA+B,CACnC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;QACT,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;IA8EI,gBAAgB,CACpB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,eAAe,EAAE,EAC3B,oBAAoB,EAAE,MAAM,EAC5B,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,MAAM,GACzB,OAAO,CAAC,sBAAsB,CAAC;IAmH5B,6CAA6C,CACjD,QAAQ,EAAE,eAAe,EAAE,GAC1B,OAAO,CAAC;QACT,cAAc,EAAE,OAAO,EAAE,CAAC;QAC1B,gBAAgB,EAAE,eAAe,EAAE,CAAC;QACpC,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;IAqCI,wCAAwC,CAC5C,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,qBAAqB,EACpC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,OAAO,CAAC;IA2Bb,yBAAyB,CAC7B,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,oBAAoB,CAAC;IAe1B,8BAA8B,CAClC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC;CAY7C"}
1
+ {"version":3,"file":"imgCaptchaTasks.d.ts","sourceRoot":"","sources":["../../../src/tasks/imgCaptcha/imgCaptchaTasks.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAG3D,OAAO,EAAE,KAAK,MAAM,EAAmB,MAAM,iBAAiB,CAAC;AAM/D,OAAO,EACL,KAAK,OAAO,EACZ,KAAK,aAAa,EAClB,KAAK,eAAe,EAEpB,KAAK,sBAAsB,EAE3B,KAAK,IAAI,EACT,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,QAAQ,EAER,cAAc,EACf,MAAM,yBAAyB,CAAC;AAKjC,qBAAa,iBAAiB;IAC5B,EAAE,EAAE,QAAQ,CAAC;IACb,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,aAAa,CAAC;gBAG3B,EAAE,EAAE,QAAQ,EACZ,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa;IAQxB,mBAAmB,CACvB,SAAS,EAAE,IAAI,EACf,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,EAAE,CAAC;IAgBf,+BAA+B,CACnC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QACT,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;IAgFI,gBAAgB,CACpB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,eAAe,EAAE,EAC3B,wBAAwB,EAAE,MAAM,EAChC,SAAS,EAAE,MAAM,EACjB,4BAA4B,EAAE,MAAM,EACpC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,sBAAsB,CAAC;IAiH5B,6CAA6C,CACjD,QAAQ,EAAE,eAAe,EAAE,GAC1B,OAAO,CAAC;QACT,cAAc,EAAE,OAAO,EAAE,CAAC;QAC1B,gBAAgB,EAAE,eAAe,EAAE,CAAC;QACpC,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;IAqCI,wCAAwC,CAC5C,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,qBAAqB,EACpC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,OAAO,CAAC;IA2Bb,yBAAyB,CAC7B,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,cAAc,CAAC;IAepB,8BAA8B,CAClC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;CAcvC"}
@@ -1,4 +1,4 @@
1
- import { hexToU8a, stringToHex, u8aToHex } from "@polkadot/util";
1
+ import { stringToHex, u8aToHex } from "@polkadot/util";
2
2
  import { randomAsHex, signatureVerify } from "@polkadot/util-crypto";
3
3
  import { ProsopoEnvError } from "@prosopo/common";
4
4
  import { compareCaptchaSolutions, computePendingRequestHash, parseAndSortCaptchaSolutions, } from "@prosopo/datasets";
@@ -27,7 +27,7 @@ export class ImgCaptchaManager {
27
27
  }
28
28
  return captchaDocs;
29
29
  }
30
- async getRandomCaptchasAndRequestHash(datasetId, userAccount) {
30
+ async getRandomCaptchasAndRequestHash(datasetId, userAccount, ipAddress) {
31
31
  const dataset = await this.db.getDatasetDetails(datasetId);
32
32
  if (!dataset) {
33
33
  throw new ProsopoEnvError("DATABASE.DATASET_GET_FAILED", {
@@ -52,36 +52,36 @@ export class ImgCaptchaManager {
52
52
  const salt = randomAsHex();
53
53
  const requestHash = computePendingRequestHash(captchas.map((c) => c.captchaId), userAccount, salt);
54
54
  const currentTime = Date.now();
55
- const signedTimestamp = u8aToHex(this.pair.sign(stringToHex(currentTime.toString())));
55
+ const signedRequestHash = u8aToHex(this.pair.sign(stringToHex(requestHash)));
56
56
  const timeLimit = captchas
57
57
  .map((captcha) => captcha.timeLimitMs || DEFAULT_IMAGE_CAPTCHA_TIMEOUT)
58
58
  .reduce((a, b) => a + b, 0);
59
59
  const deadlineTs = timeLimit + currentTime;
60
60
  const currentBlockNumber = 0;
61
- await this.db.storeDappUserPending(userAccount, requestHash, salt, deadlineTs, currentBlockNumber);
61
+ await this.db.storeDappUserPending(userAccount, requestHash, salt, deadlineTs, currentTime, ipAddress);
62
62
  return {
63
63
  captchas,
64
64
  requestHash,
65
65
  timestamp: currentTime,
66
- signedTimestamp,
66
+ signedRequestHash,
67
67
  };
68
68
  }
69
- async dappUserSolution(userAccount, dappAccount, requestHash, captchas, requestHashSignature, timestamp, timestampSignature) {
70
- const verification = signatureVerify(stringToHex(requestHash), requestHashSignature, userAccount);
69
+ async dappUserSolution(userAccount, dappAccount, requestHash, captchas, userRequestHashSignature, timestamp, providerRequestHashSignature, ipAddress) {
70
+ const verification = signatureVerify(stringToHex(requestHash), userRequestHashSignature, userAccount);
71
71
  if (!verification.isValid) {
72
- this.logger.info("Invalid requestHash signature");
72
+ this.logger.info("Invalid user requestHash signature");
73
73
  throw new ProsopoEnvError("GENERAL.INVALID_SIGNATURE", {
74
74
  context: { failedFuncName: this.dappUserSolution.name, userAccount },
75
75
  });
76
76
  }
77
- const timestampSigVerify = signatureVerify(stringToHex(timestamp.toString()), timestampSignature, this.pair.address);
78
- if (!timestampSigVerify.isValid) {
79
- this.logger.info("Invalid timestamp signature");
77
+ const providerRequestHashSignatureVerify = signatureVerify(stringToHex(requestHash.toString()), providerRequestHashSignature, this.pair.address);
78
+ if (!providerRequestHashSignatureVerify.isValid) {
79
+ this.logger.info("Invalid provider requestHash signature");
80
80
  throw new ProsopoEnvError("GENERAL.INVALID_SIGNATURE", {
81
81
  context: {
82
82
  failedFuncName: this.dappUserSolution.name,
83
83
  userAccount,
84
- error: "timestamp signature is invalid",
84
+ error: "requestHash signature is invalid",
85
85
  },
86
86
  });
87
87
  }
@@ -92,7 +92,6 @@ export class ImgCaptchaManager {
92
92
  const pendingRecord = await this.db.getDappUserPending(requestHash);
93
93
  const unverifiedCaptchaIds = captchas.map((captcha) => captcha.captchaId);
94
94
  const pendingRequest = await this.validateDappUserSolutionRequestIsPending(requestHash, pendingRecord, userAccount, unverifiedCaptchaIds);
95
- console.log("Pending request", pendingRequest);
96
95
  if (pendingRequest) {
97
96
  const { storedCaptchas, receivedCaptchas, captchaIds } = await this.validateReceivedCaptchasAgainstStoredCaptchas(captchas);
98
97
  const { tree, commitmentId } = buildTreeAndGetCommitmentId(receivedCaptchas);
@@ -102,26 +101,21 @@ export class ImgCaptchaManager {
102
101
  context: { failedFuncName: this.dappUserSolution.name },
103
102
  });
104
103
  }
105
- const userSignature = hexToU8a(requestHashSignature);
106
104
  await this.db.updateDappUserPendingStatus(requestHash);
107
105
  const commit = {
108
106
  id: commitmentId,
109
107
  userAccount: userAccount,
110
- dappContract: dappAccount,
108
+ dappAccount,
111
109
  providerAccount: this.pair.address,
112
110
  datasetId,
113
- status: CaptchaStatus.pending,
114
- userSignature: Array.from(userSignature),
115
- requestedAt: pendingRecord.requestedAtBlock,
116
- completedAt: 0,
117
- processed: false,
118
- batched: false,
119
- stored: false,
111
+ result: { status: CaptchaStatus.pending },
112
+ userSignature: userRequestHashSignature,
113
+ userSubmitted: true,
114
+ serverChecked: false,
120
115
  requestedAtTimestamp: timestamp,
116
+ ipAddress,
121
117
  };
122
118
  await this.db.storeDappUserSolution(receivedCaptchas, commit);
123
- console.log(receivedCaptchas);
124
- console.log(storedCaptchas);
125
119
  if (compareCaptchaSolutions(receivedCaptchas, storedCaptchas)) {
126
120
  response = {
127
121
  captchas: captchaIds.map((id) => ({
@@ -133,6 +127,7 @@ export class ImgCaptchaManager {
133
127
  await this.db.approveDappUserCommitment(commitmentId);
134
128
  }
135
129
  else {
130
+ await this.db.disapproveDappUserCommitment(commitmentId, "CAPTCHA.INVALID_SOLUTION");
136
131
  response = {
137
132
  captchas: captchaIds.map((id) => ({
138
133
  captchaId: id,
@@ -197,11 +192,11 @@ export class ImgCaptchaManager {
197
192
  }
198
193
  return dappUserSolution;
199
194
  }
200
- async getDappUserCommitmentByAccount(userAccount) {
201
- const dappUserSolutions = await this.db.getDappUserCommitmentByAccount(userAccount);
195
+ async getDappUserCommitmentByAccount(userAccount, dappAccount) {
196
+ const dappUserSolutions = await this.db.getDappUserCommitmentByAccount(userAccount, dappAccount);
202
197
  if (dappUserSolutions.length > 0) {
203
198
  for (const dappUserSolution of dappUserSolutions) {
204
- if (dappUserSolution.status === CaptchaStatus.approved) {
199
+ if (dappUserSolution.result.status === CaptchaStatus.approved) {
205
200
  return dappUserSolution;
206
201
  }
207
202
  }