@prosopo/provider 3.12.3 → 3.13.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 (49) hide show
  1. package/CHANGELOG.md +214 -0
  2. package/dist/api/admin/apiAdminRoutesProvider.js +13 -18
  3. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.js +40 -0
  4. package/dist/api/blacklistRequestInspector.js +4 -4
  5. package/dist/api/captcha/getFrictionlessCaptchaChallenge.js +338 -0
  6. package/dist/api/captcha/getImageCaptchaChallenge.js +150 -0
  7. package/dist/api/captcha/getPoWCaptchaChallenge.js +156 -0
  8. package/dist/api/captcha/submitImageCaptchaSolution.js +87 -0
  9. package/dist/api/captcha/submitPoWCaptchaSolution.js +77 -0
  10. package/dist/api/captcha.js +18 -606
  11. package/dist/api/verify.js +24 -1
  12. package/dist/cjs/api/admin/apiAdminRoutesProvider.cjs +13 -18
  13. package/dist/cjs/api/admin/apiRegisterSiteKeyEndpoint.cjs +2 -1
  14. package/dist/cjs/api/admin/apiRemoveDetectorKeyEndpoint.cjs +3 -2
  15. package/dist/cjs/api/admin/apiToggleMaintenanceModeEndpoint.cjs +41 -0
  16. package/dist/cjs/api/blacklistRequestInspector.cjs +3 -3
  17. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge.cjs +337 -0
  18. package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +149 -0
  19. package/dist/cjs/api/captcha/getPoWCaptchaChallenge.cjs +155 -0
  20. package/dist/cjs/api/captcha/submitImageCaptchaSolution.cjs +86 -0
  21. package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +76 -0
  22. package/dist/cjs/api/captcha.cjs +17 -605
  23. package/dist/cjs/api/ja4Middleware.cjs +2 -1
  24. package/dist/cjs/api/verify.cjs +24 -1
  25. package/dist/cjs/index.cjs +2 -0
  26. package/dist/cjs/schedulers/setClientEntropy.cjs +36 -0
  27. package/dist/cjs/tasks/captchaManager.cjs +7 -22
  28. package/dist/cjs/tasks/client/clientTasks.cjs +18 -36
  29. package/dist/cjs/tasks/detection/decodePayload.cjs +385 -714
  30. package/dist/cjs/tasks/detection/getBotScore.cjs +15 -2
  31. package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +136 -30
  32. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +25 -13
  33. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +8 -8
  34. package/dist/cjs/tasks/tasks.cjs +1 -0
  35. package/dist/cjs/util.cjs +14 -1
  36. package/dist/cjs/utils/hashUserIp.cjs +9 -0
  37. package/dist/index.js +2 -0
  38. package/dist/schedulers/setClientEntropy.js +36 -0
  39. package/dist/tasks/captchaManager.js +5 -21
  40. package/dist/tasks/client/clientTasks.js +19 -37
  41. package/dist/tasks/detection/decodePayload.js +385 -714
  42. package/dist/tasks/detection/getBotScore.js +17 -4
  43. package/dist/tasks/frictionless/frictionlessTasks.js +137 -31
  44. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +25 -13
  45. package/dist/tasks/powCaptcha/powTasks.js +8 -8
  46. package/dist/tasks/tasks.js +1 -0
  47. package/dist/util.js +14 -1
  48. package/dist/utils/hashUserIp.js +9 -0
  49. package/package.json +24 -25
@@ -10,6 +10,7 @@ const _public = require("./api/public.cjs");
10
10
  const domainMiddleware = require("./api/domainMiddleware.cjs");
11
11
  const captchaScheduler = require("./schedulers/captchaScheduler.cjs");
12
12
  const getClientList = require("./schedulers/getClientList.cjs");
13
+ const setClientEntropy = require("./schedulers/setClientEntropy.cjs");
13
14
  const headerCheckMiddleware = require("./api/headerCheckMiddleware.cjs");
14
15
  const createApiAdminRoutesProvider = require("./api/admin/createApiAdminRoutesProvider.cjs");
15
16
  const ignoreMiddleware = require("./api/ignoreMiddleware.cjs");
@@ -35,6 +36,7 @@ exports.publicRouter = _public.publicRouter;
35
36
  exports.domainMiddleware = domainMiddleware.domainMiddleware;
36
37
  exports.storeCaptchasExternally = captchaScheduler.storeCaptchasExternally;
37
38
  exports.getClientList = getClientList.getClientList;
39
+ exports.setClientEntropy = setClientEntropy.setClientEntropy;
38
40
  exports.headerCheckMiddleware = headerCheckMiddleware.headerCheckMiddleware;
39
41
  exports.createApiAdminRoutesProvider = createApiAdminRoutesProvider.createApiAdminRoutesProvider;
40
42
  exports.ignoreMiddleware = ignoreMiddleware.ignoreMiddleware;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const env = require("@prosopo/env");
4
+ const types = require("@prosopo/types");
5
+ const cron = require("cron");
6
+ const tasks = require("../tasks/tasks.cjs");
7
+ const util = require("../util.cjs");
8
+ async function setClientEntropy(pair, cronSchedule, config) {
9
+ const env$1 = new env.ProviderEnvironment(config, pair);
10
+ await env$1.isReady();
11
+ const tasks$1 = new tasks.Tasks(env$1);
12
+ const job = new cron.CronJob(cronSchedule, async () => {
13
+ const taskRunning = await util.checkIfTaskIsRunning(
14
+ types.ScheduledTaskNames.SetClientEntropy,
15
+ env$1.getDb()
16
+ );
17
+ env$1.logger.info(() => ({
18
+ msg: `${types.ScheduledTaskNames.SetClientEntropy} task running: ${taskRunning}`,
19
+ data: { taskRunning }
20
+ }));
21
+ if (!taskRunning) {
22
+ env$1.logger.info(() => ({
23
+ msg: `${types.ScheduledTaskNames.SetClientEntropy} task....`,
24
+ data: {}
25
+ }));
26
+ await tasks$1.clientTaskManager.calculateClientEntropy().catch((err) => {
27
+ env$1.logger.error(() => ({
28
+ err,
29
+ msg: "Error setting client entropy"
30
+ }));
31
+ });
32
+ }
33
+ });
34
+ job.start();
35
+ }
36
+ exports.setClientEntropy = setClientEntropy;
@@ -3,29 +3,15 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const common = require("@prosopo/common");
4
4
  const types = require("@prosopo/types");
5
5
  const blacklistRequestInspector = require("../api/blacklistRequestInspector.cjs");
6
+ var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
6
7
  class CaptchaManager {
7
- constructor(db, pair, logger) {
8
+ constructor(db, pair, config, logger) {
8
9
  this.pair = pair;
9
10
  this.db = db;
10
- this.logger = logger || common.getLogger("info", module);
11
+ this.config = config;
12
+ this.logger = logger || common.getLogger("info", typeof document === "undefined" ? require("url").pathToFileURL(__filename).href : _documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === "SCRIPT" && _documentCurrentScript.src || new URL("tasks/captchaManager.cjs", document.baseURI).href);
11
13
  }
12
- async getFrictionlessTokenIdFromSession(sessionRecord) {
13
- const tokenRecord = await this.db.getFrictionlessTokenRecordByTokenId(
14
- sessionRecord.tokenId
15
- );
16
- return tokenRecord ? tokenRecord._id : void 0;
17
- }
18
- async validateFrictionlessTokenIP(sessionRecord, currentIP, env) {
19
- const tokenRecord = await this.db.getFrictionlessTokenRecordByTokenId(
20
- sessionRecord.tokenId
21
- );
22
- if (!tokenRecord) {
23
- this.logger.info(() => ({
24
- msg: "No frictionless token found for session",
25
- data: { sessionId: sessionRecord.sessionId }
26
- }));
27
- return { valid: false, reason: "CAPTCHA.NO_SESSION_FOUND" };
28
- }
14
+ async validateSessionIP(sessionRecord, currentIP, env) {
29
15
  return { valid: true };
30
16
  }
31
17
  async isValidRequest(clientSettings, requestedCaptchaType, env, sessionId, userAccessPolicy, currentIP) {
@@ -68,7 +54,7 @@ class CaptchaManager {
68
54
  };
69
55
  }
70
56
  if (currentIP) {
71
- const ipValidation = await this.validateFrictionlessTokenIP(
57
+ const ipValidation = await this.validateSessionIP(
72
58
  sessionRecord,
73
59
  currentIP,
74
60
  env
@@ -81,7 +67,6 @@ class CaptchaManager {
81
67
  };
82
68
  }
83
69
  }
84
- const frictionlessTokenId = await this.getFrictionlessTokenIdFromSession(sessionRecord);
85
70
  if (sessionRecord.captchaType !== requestedCaptchaType) {
86
71
  this.logger.warn(() => ({
87
72
  msg: "Invalid frictionless request",
@@ -98,7 +83,7 @@ class CaptchaManager {
98
83
  }
99
84
  return {
100
85
  valid: true,
101
- frictionlessTokenId,
86
+ sessionId: sessionRecord.sessionId,
102
87
  type: requestedCaptchaType,
103
88
  ...sessionRecord.powDifficulty && {
104
89
  powDifficulty: sessionRecord.powDifficulty
@@ -102,44 +102,11 @@ class ClientTaskManager {
102
102
  async (skip) => await this.providerDB.getUnstoredSessionRecords(BATCH_SIZE, skip),
103
103
  async (batch) => {
104
104
  const filteredBatch = lastTask?.updated ? batch.filter((record) => this.isRecordUpdated(record)) : batch;
105
- const frictionlessTokenRecords = await this.providerDB.getFrictionlessTokenRecordsByTokenIds(
106
- filteredBatch.map((record) => record.tokenId)
107
- );
108
- this.logger.info(() => ({
109
- msg: `Frictionless token records: ${frictionlessTokenRecords.length}`
110
- }));
111
- const filteredBatchWithScores = filteredBatch.map((record) => {
112
- const tokenRecord = frictionlessTokenRecords.find(
113
- (tokenRecord2) => tokenRecord2._id?.toString() === record.tokenId.toString()
114
- );
115
- if (!tokenRecord) {
116
- this.logger.error(() => ({
117
- msg: "No token record found",
118
- data: { tokenId: record.tokenId }
119
- }));
120
- return {
121
- ...record,
122
- score: 0,
123
- scoreComponents: {
124
- baseScore: 0
125
- },
126
- threshold: 0
127
- };
128
- }
129
- const { _id, token, ...tokenRecordWithoutId } = tokenRecord;
130
- return {
131
- ...record,
132
- ...tokenRecordWithoutId
133
- };
134
- });
135
105
  if (filteredBatch.length > 0) {
136
- await captchaDB.saveCaptchas(filteredBatchWithScores, [], []);
106
+ await captchaDB.saveCaptchas(filteredBatch, [], []);
137
107
  await this.providerDB.markSessionRecordsStored(
138
108
  filteredBatch.map((record) => record.sessionId)
139
109
  );
140
- await this.providerDB.markFrictionlessTokenRecordsStored(
141
- filteredBatch.map((record) => record.tokenId).filter((id) => !!id)
142
- );
143
110
  }
144
111
  processedSessionRecords += filteredBatch.length;
145
112
  }
@@ -196,7 +163,7 @@ class ClientTaskManager {
196
163
  this.logger
197
164
  );
198
165
  const tenMinuteWindow = 10 * 60 * 1e3;
199
- const updatedAtTimestamp = lastTask?.updated ? lastTask.updated - tenMinuteWindow || 0 : 0;
166
+ const updatedAtTimestamp = lastTask?.updated ? lastTask.updated.getTime() - tenMinuteWindow || 0 : 0;
200
167
  this.logger.info(() => ({
201
168
  msg: `Getting updated client records since ${new Date(updatedAtTimestamp).toDateString()}`
202
169
  }));
@@ -229,6 +196,21 @@ class ClientTaskManager {
229
196
  );
230
197
  }
231
198
  }
199
+ /**
200
+ * @description Calculate client entropy scores and update in db
201
+ * @returns Promise<void>
202
+ */
203
+ async calculateClientEntropy() {
204
+ const clients = await this.providerDB.getAllClientRecords();
205
+ for (const client of clients) {
206
+ const sampleEntropies = await this.providerDB.sampleEntropy(
207
+ 100,
208
+ client.account
209
+ );
210
+ const avgEntropy = util.majorityAverage(sampleEntropies);
211
+ await this.providerDB.setClientEntropy(client.account, avgEntropy);
212
+ }
213
+ }
232
214
  async registerSiteKey(siteKey, tier, settings) {
233
215
  validateAddress.validateSiteKey(siteKey);
234
216
  await this.providerDB.updateClientRecords([
@@ -295,7 +277,7 @@ class ClientTaskManager {
295
277
  }
296
278
  isRecordUpdated(record) {
297
279
  const { lastUpdatedTimestamp, storedAtTimestamp } = record;
298
- return !lastUpdatedTimestamp || !storedAtTimestamp || lastUpdatedTimestamp > storedAtTimestamp;
280
+ return !lastUpdatedTimestamp || !storedAtTimestamp || lastUpdatedTimestamp.getTime() > storedAtTimestamp.getTime();
299
281
  }
300
282
  async processBatchesWithCursor(fetchBatch, processBatch) {
301
283
  let skip = 0;