@prosopo/provider 4.15.14 → 4.15.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (232) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +106 -106
  2. package/.turbo/turbo-build$colon$tsc.log +24 -24
  3. package/.turbo/turbo-build.log +107 -104
  4. package/CHANGELOG.md +49 -0
  5. package/dist/_virtual/_rolldown/runtime.js +3 -0
  6. package/dist/api/admin/apiAdminRoutesProvider.js +27 -46
  7. package/dist/api/admin/apiClearAllCountersEndpoint.js +62 -57
  8. package/dist/api/admin/apiDnsEventEndpoint.js +79 -92
  9. package/dist/api/admin/apiGetAllDecisionMachinesEndpoint.js +43 -45
  10. package/dist/api/admin/apiGetDecisionMachineEndpoint.js +40 -40
  11. package/dist/api/admin/apiRegisterSiteKeyEndpoint.js +23 -22
  12. package/dist/api/admin/apiRegisterSiteKeysEndpoint.js +26 -30
  13. package/dist/api/admin/apiRemoveAllDecisionMachinesEndpoint.js +35 -37
  14. package/dist/api/admin/apiRemoveDecisionMachineEndpoint.js +40 -40
  15. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts.map +1 -1
  16. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js +29 -31
  17. package/dist/api/admin/apiRemoveSiteKeyEndpoint.js +33 -29
  18. package/dist/api/admin/apiRemoveSiteKeysEndpoint.js +32 -31
  19. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.js +43 -35
  20. package/dist/api/admin/apiUpdateDecisionMachineEndpoint.js +43 -63
  21. package/dist/api/admin/apiUpdateDetectorKeyEndpoint.js +36 -35
  22. package/dist/api/admin/createApiAdminRoutesProvider.js +6 -8
  23. package/dist/api/blacklistRequestInspector.js +285 -377
  24. package/dist/api/block.js +17 -30
  25. package/dist/api/captcha/checkSpamEmail.js +88 -98
  26. package/dist/api/captcha/contextAwareValidation.js +21 -15
  27. package/dist/api/captcha/getFrictionlessCaptchaChallenge/accessPolicy.js +126 -140
  28. package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.js +11 -12
  29. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js +236 -299
  30. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.js +10 -13
  31. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +336 -462
  32. package/dist/api/captcha/getFrictionlessCaptchaChallenge/honeypotResponse.js +17 -14
  33. package/dist/api/captcha/getFrictionlessCaptchaChallenge/sessionDedup.js +27 -27
  34. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js +42 -63
  35. package/dist/api/captcha/getFrictionlessCaptchaChallenge.js +2 -4
  36. package/dist/api/captcha/getImageCaptchaChallenge.js +136 -207
  37. package/dist/api/captcha/getPoWCaptchaChallenge.js +128 -198
  38. package/dist/api/captcha/getPuzzleCaptchaChallenge.js +132 -201
  39. package/dist/api/captcha/maintenanceModeResponses.js +38 -47
  40. package/dist/api/captcha/submitImageCaptchaSolution.js +75 -101
  41. package/dist/api/captcha/submitPoWCaptchaSolution.js +137 -207
  42. package/dist/api/captcha/submitPuzzleCaptchaSolution.js +73 -105
  43. package/dist/api/captcha.js +76 -58
  44. package/dist/api/dnsEventUrl.js +20 -22
  45. package/dist/api/domainMiddleware.js +104 -115
  46. package/dist/api/forwardVerify.js +62 -48
  47. package/dist/api/handshakeTimingMiddleware.js +43 -62
  48. package/dist/api/hardBlockVerdictCache.js +114 -117
  49. package/dist/api/headerCheckMiddleware.js +34 -34
  50. package/dist/api/ignoreMiddleware.js +13 -15
  51. package/dist/api/ipInfoMiddleware.js +17 -19
  52. package/dist/api/ja4.js +149 -188
  53. package/dist/api/ja4Middleware.js +39 -54
  54. package/dist/api/metrics.js +245 -257
  55. package/dist/api/public.js +52 -54
  56. package/dist/api/robotsMiddleware.js +10 -10
  57. package/dist/api/startProviderApi.js +205 -232
  58. package/dist/api/testSiteKey.js +16 -16
  59. package/dist/api/validateAddress.js +23 -21
  60. package/dist/api/verify.js +334 -377
  61. package/dist/cjs/_virtual/_rolldown/runtime.cjs +23 -0
  62. package/dist/cjs/api/admin/apiAdminRoutesProvider.cjs +40 -59
  63. package/dist/cjs/api/admin/apiClearAllCountersEndpoint.cjs +63 -58
  64. package/dist/cjs/api/admin/apiDnsEventEndpoint.cjs +82 -93
  65. package/dist/cjs/api/admin/apiGetAllDecisionMachinesEndpoint.cjs +46 -48
  66. package/dist/cjs/api/admin/apiGetDecisionMachineEndpoint.cjs +41 -41
  67. package/dist/cjs/api/admin/apiRegisterSiteKeyEndpoint.cjs +25 -24
  68. package/dist/cjs/api/admin/apiRegisterSiteKeysEndpoint.cjs +28 -32
  69. package/dist/cjs/api/admin/apiRemoveAllDecisionMachinesEndpoint.cjs +38 -40
  70. package/dist/cjs/api/admin/apiRemoveDecisionMachineEndpoint.cjs +41 -41
  71. package/dist/cjs/api/admin/apiRemoveDetectorKeyEndpoint.cjs +31 -33
  72. package/dist/cjs/api/admin/apiRemoveSiteKeyEndpoint.cjs +35 -31
  73. package/dist/cjs/api/admin/apiRemoveSiteKeysEndpoint.cjs +34 -33
  74. package/dist/cjs/api/admin/apiToggleMaintenanceModeEndpoint.cjs +45 -35
  75. package/dist/cjs/api/admin/apiUpdateDecisionMachineEndpoint.cjs +45 -65
  76. package/dist/cjs/api/admin/apiUpdateDetectorKeyEndpoint.cjs +38 -37
  77. package/dist/cjs/api/admin/createApiAdminRoutesProvider.cjs +7 -8
  78. package/dist/cjs/api/blacklistRequestInspector.cjs +288 -376
  79. package/dist/cjs/api/block.cjs +18 -30
  80. package/dist/cjs/api/captcha/checkSpamEmail.cjs +90 -100
  81. package/dist/cjs/api/captcha/contextAwareValidation.cjs +21 -14
  82. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/accessPolicy.cjs +125 -140
  83. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/constants.cjs +10 -10
  84. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.cjs +238 -301
  85. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.cjs +9 -12
  86. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +349 -473
  87. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/honeypotResponse.cjs +18 -14
  88. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/sessionDedup.cjs +26 -26
  89. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.cjs +42 -63
  90. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge.cjs +2 -3
  91. package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +138 -208
  92. package/dist/cjs/api/captcha/getPoWCaptchaChallenge.cjs +131 -200
  93. package/dist/cjs/api/captcha/getPuzzleCaptchaChallenge.cjs +135 -203
  94. package/dist/cjs/api/captcha/maintenanceModeResponses.cjs +38 -44
  95. package/dist/cjs/api/captcha/submitImageCaptchaSolution.cjs +77 -102
  96. package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +140 -209
  97. package/dist/cjs/api/captcha/submitPuzzleCaptchaSolution.cjs +76 -107
  98. package/dist/cjs/api/captcha.cjs +79 -58
  99. package/dist/cjs/api/dnsEventUrl.cjs +20 -21
  100. package/dist/cjs/api/domainMiddleware.cjs +106 -117
  101. package/dist/cjs/api/forwardVerify.cjs +63 -49
  102. package/dist/cjs/api/handshakeTimingMiddleware.cjs +43 -61
  103. package/dist/cjs/api/hardBlockVerdictCache.cjs +114 -114
  104. package/dist/cjs/api/headerCheckMiddleware.cjs +34 -34
  105. package/dist/cjs/api/ignoreMiddleware.cjs +12 -14
  106. package/dist/cjs/api/ipInfoMiddleware.cjs +16 -18
  107. package/dist/cjs/api/ja4.cjs +149 -187
  108. package/dist/cjs/api/ja4Middleware.cjs +40 -53
  109. package/dist/cjs/api/metrics.cjs +229 -228
  110. package/dist/cjs/api/public.cjs +57 -57
  111. package/dist/cjs/api/robotsMiddleware.cjs +9 -9
  112. package/dist/cjs/api/startProviderApi.cjs +219 -237
  113. package/dist/cjs/api/testSiteKey.cjs +15 -14
  114. package/dist/cjs/api/validateAddress.cjs +24 -21
  115. package/dist/cjs/api/verify.cjs +338 -379
  116. package/dist/cjs/compositeIpAddress.cjs +40 -47
  117. package/dist/cjs/index.cjs +65 -71
  118. package/dist/cjs/pairs.cjs +31 -35
  119. package/dist/cjs/rules/lang.cjs +10 -14
  120. package/dist/cjs/schedulers/captchaScheduler.cjs +26 -32
  121. package/dist/cjs/schedulers/getClientList.cjs +35 -33
  122. package/dist/cjs/schedulers/setClientEntropy.cjs +35 -33
  123. package/dist/cjs/schedulers/updateSpamEmailDomains.cjs +39 -43
  124. package/dist/cjs/services/ipComparison.cjs +122 -119
  125. package/dist/cjs/tasks/captchaManager.cjs +407 -486
  126. package/dist/cjs/tasks/client/clientTasks.cjs +347 -470
  127. package/dist/cjs/tasks/dataset/datasetTasks.cjs +25 -29
  128. package/dist/cjs/tasks/dataset/datasetTasksUtils.cjs +16 -32
  129. package/dist/cjs/tasks/decisionMachine/decisionMachineRunner.cjs +220 -307
  130. package/dist/cjs/tasks/detection/decodeBehavior.cjs +408 -317
  131. package/dist/cjs/tasks/detection/decodePayload.cjs +686 -468
  132. package/dist/cjs/tasks/detection/decodeSimd.cjs +462 -304
  133. package/dist/cjs/tasks/detection/getBotScore.cjs +37 -43
  134. package/dist/cjs/tasks/dnsEvent/enrichDnsEvent.cjs +88 -71
  135. package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +348 -486
  136. package/dist/cjs/tasks/frictionless/frictionlessTasksUtils.cjs +13 -30
  137. package/dist/cjs/tasks/frictionless/routingMachine.cjs +71 -55
  138. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +555 -806
  139. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasksUtils.cjs +22 -23
  140. package/dist/cjs/tasks/index.cjs +2 -4
  141. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +491 -687
  142. package/dist/cjs/tasks/powCaptcha/powTasksUtils.cjs +17 -29
  143. package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +422 -591
  144. package/dist/cjs/tasks/puzzleCaptcha/puzzleTasksUtils.cjs +8 -5
  145. package/dist/cjs/tasks/spam/checkSpamEmail.cjs +133 -141
  146. package/dist/cjs/tasks/spam/checkTrafficFilter.cjs +118 -76
  147. package/dist/cjs/tasks/spam/evaluateEmailSpamRules.cjs +75 -84
  148. package/dist/cjs/tasks/spam/updateSpamEmailDomains.cjs +40 -56
  149. package/dist/cjs/tasks/tasks.cjs +107 -158
  150. package/dist/cjs/util/usageCounters.cjs +220 -211
  151. package/dist/cjs/util.cjs +329 -359
  152. package/dist/cjs/utils/devicePlatform.cjs +14 -8
  153. package/dist/cjs/utils/dns.cjs +68 -93
  154. package/dist/cjs/utils/hashUserAgent.cjs +14 -7
  155. package/dist/cjs/utils/hashUserIp.cjs +14 -6
  156. package/dist/cjs/utils/honeypot/encoders.cjs +74 -80
  157. package/dist/cjs/utils/honeypot/phraseBank.cjs +51 -44
  158. package/dist/cjs/utils/normalizeRequestIp.cjs +33 -25
  159. package/dist/compositeIpAddress.js +38 -46
  160. package/dist/index.js +12 -56
  161. package/dist/pairs.js +31 -37
  162. package/dist/rules/lang.js +11 -15
  163. package/dist/schedulers/captchaScheduler.js +25 -31
  164. package/dist/schedulers/getClientList.js +34 -32
  165. package/dist/schedulers/setClientEntropy.js +34 -32
  166. package/dist/schedulers/updateSpamEmailDomains.js +38 -42
  167. package/dist/services/ipComparison.js +122 -119
  168. package/dist/tasks/captchaManager.js +403 -483
  169. package/dist/tasks/client/clientTasks.js +343 -467
  170. package/dist/tasks/dataset/datasetTasks.js +24 -28
  171. package/dist/tasks/dataset/datasetTasksUtils.js +15 -31
  172. package/dist/tasks/decisionMachine/decisionMachineRunner.js +217 -306
  173. package/dist/tasks/detection/getBotScore.js +37 -43
  174. package/dist/tasks/dnsEvent/enrichDnsEvent.d.ts.map +1 -1
  175. package/dist/tasks/dnsEvent/enrichDnsEvent.js +88 -74
  176. package/dist/tasks/dnsEvent/enrichDnsEvent.js.map +1 -1
  177. package/dist/tasks/frictionless/frictionlessTasks.js +342 -479
  178. package/dist/tasks/frictionless/frictionlessTasksUtils.js +14 -32
  179. package/dist/tasks/frictionless/routingMachine.js +72 -56
  180. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +550 -801
  181. package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.js +21 -22
  182. package/dist/tasks/index.js +1 -3
  183. package/dist/tasks/powCaptcha/powTasks.d.ts.map +1 -1
  184. package/dist/tasks/powCaptcha/powTasks.js +486 -682
  185. package/dist/tasks/powCaptcha/powTasks.js.map +1 -1
  186. package/dist/tasks/powCaptcha/powTasksUtils.js +15 -28
  187. package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts.map +1 -1
  188. package/dist/tasks/puzzleCaptcha/puzzleTasks.js +417 -586
  189. package/dist/tasks/puzzleCaptcha/puzzleTasks.js.map +1 -1
  190. package/dist/tasks/puzzleCaptcha/puzzleTasksUtils.js +9 -6
  191. package/dist/tasks/spam/checkSpamEmail.js +133 -141
  192. package/dist/tasks/spam/checkTrafficFilter.d.ts +1 -0
  193. package/dist/tasks/spam/checkTrafficFilter.d.ts.map +1 -1
  194. package/dist/tasks/spam/checkTrafficFilter.js +117 -77
  195. package/dist/tasks/spam/checkTrafficFilter.js.map +1 -1
  196. package/dist/tasks/spam/evaluateEmailSpamRules.js +75 -86
  197. package/dist/tasks/spam/updateSpamEmailDomains.js +36 -54
  198. package/dist/tasks/tasks.js +98 -150
  199. package/dist/tests/integration/api/blacklistRequestInspector.integration.test.js +4 -1
  200. package/dist/tests/integration/api/blacklistRequestInspector.integration.test.js.map +1 -1
  201. package/dist/tests/unit/api/block.unit.test.js +8 -4
  202. package/dist/tests/unit/api/block.unit.test.js.map +1 -1
  203. package/dist/tests/unit/api/captcha/maintenanceModeShortCircuit.unit.test.js +8 -6
  204. package/dist/tests/unit/api/captcha/maintenanceModeShortCircuit.unit.test.js.map +1 -1
  205. package/dist/tests/unit/api/forwardVerify.unit.test.js +3 -1
  206. package/dist/tests/unit/api/forwardVerify.unit.test.js.map +1 -1
  207. package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js +15 -7
  208. package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js.map +1 -1
  209. package/dist/tests/unit/schedulers/captchaScheduler.unit.test.js +24 -18
  210. package/dist/tests/unit/schedulers/captchaScheduler.unit.test.js.map +1 -1
  211. package/dist/tests/unit/schedulers/getClientList.unit.test.js +19 -13
  212. package/dist/tests/unit/schedulers/getClientList.unit.test.js.map +1 -1
  213. package/dist/tests/unit/schedulers/setClientEntropy.unit.test.js +19 -13
  214. package/dist/tests/unit/schedulers/setClientEntropy.unit.test.js.map +1 -1
  215. package/dist/tests/unit/tasks/client/clientTasks.unit.test.js.map +1 -1
  216. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js +22 -16
  217. package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js.map +1 -1
  218. package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js +140 -0
  219. package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js.map +1 -1
  220. package/dist/tests/unit/testUtils/mockProviderEnv.d.ts +7 -7
  221. package/dist/util/usageCounters.js +220 -212
  222. package/dist/util.d.ts.map +1 -1
  223. package/dist/util.js +327 -364
  224. package/dist/util.js.map +1 -1
  225. package/dist/utils/devicePlatform.js +15 -9
  226. package/dist/utils/dns.js +64 -77
  227. package/dist/utils/hashUserAgent.js +14 -7
  228. package/dist/utils/hashUserIp.js +14 -6
  229. package/dist/utils/honeypot/encoders.js +74 -80
  230. package/dist/utils/honeypot/phraseBank.js +49 -44
  231. package/dist/utils/normalizeRequestIp.js +34 -26
  232. package/package.json +24 -24
@@ -1,472 +1,349 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const node_crypto = require("node:crypto");
4
- const common = require("@prosopo/common");
5
- const database = require("@prosopo/database");
6
- const types = require("@prosopo/types");
7
- const util = require("@prosopo/util");
8
- const validateAddress = require("../../api/validateAddress.cjs");
9
- const SAMPLE_SIZE = 75;
10
- const isValidPrivateKey = (privateKeyString) => {
11
- const privateKey = Buffer.from(privateKeyString, "base64").toString("ascii");
12
- try {
13
- node_crypto.createPrivateKey({
14
- key: privateKey,
15
- format: "pem",
16
- type: "pkcs8"
17
- });
18
- return true;
19
- } catch (error) {
20
- return false;
21
- }
1
+ const require_validateAddress = require("../../api/validateAddress.cjs");
2
+ let _prosopo_common = require("@prosopo/common");
3
+ let _prosopo_database = require("@prosopo/database");
4
+ let _prosopo_types = require("@prosopo/types");
5
+ let node_crypto = require("node:crypto");
6
+ let _prosopo_util = require("@prosopo/util");
7
+ //#region src/tasks/client/clientTasks.ts
8
+ var SAMPLE_SIZE = 75;
9
+ var isValidPrivateKey = (privateKeyString) => {
10
+ const privateKey = Buffer.from(privateKeyString, "base64").toString("ascii");
11
+ try {
12
+ (0, node_crypto.createPrivateKey)({
13
+ key: privateKey,
14
+ format: "pem",
15
+ type: "pkcs8"
16
+ });
17
+ return true;
18
+ } catch (error) {
19
+ return false;
20
+ }
22
21
  };
23
- class ClientTaskManager {
24
- constructor(config, logger, db) {
25
- this.config = config;
26
- this.logger = logger;
27
- this.providerDB = db;
28
- }
29
- /**
30
- * @description Get the captcha database connection or create a new one
31
- * @returns CaptchaDatabase
32
- */
33
- getCaptchaDB(mongoCaptchaUri) {
34
- if (this.captchaDB) {
35
- return this.captchaDB;
36
- }
37
- if (!this.captchaDB) {
38
- this.captchaDB = new database.CaptchaDatabase(
39
- mongoCaptchaUri,
40
- void 0,
41
- void 0,
42
- this.logger
43
- );
44
- }
45
- return this.captchaDB;
46
- }
47
- /**
48
- * @description Store commitments externally in the database (Sends image captcha data to the big Mongo Cloud DB)
49
- * @returns Promise<void>
50
- */
51
- async storeCommitmentsExternal() {
52
- if (!this.config.mongoCaptchaUri) {
53
- this.logger.info(() => ({ msg: "Mongo env not set" }));
54
- return;
55
- }
56
- const lastTask = await this.providerDB.getLastScheduledTaskStatus(
57
- types.ScheduledTaskNames.StoreCommitmentsExternal,
58
- types.ScheduledTaskStatus.Completed
59
- );
60
- const taskID = await this.providerDB.createScheduledTaskStatus(
61
- types.ScheduledTaskNames.StoreCommitmentsExternal,
62
- types.ScheduledTaskStatus.Running
63
- );
64
- try {
65
- const BATCH_SIZE = 1e3;
66
- const captchaDB = this.getCaptchaDB(this.config.mongoCaptchaUri);
67
- const sweepStartedAt = /* @__PURE__ */ new Date();
68
- let processedCommitments = 0;
69
- await this.processBatchesWithCursor(
70
- async (skip) => await this.providerDB.getUnstoredDappUserCommitments(
71
- BATCH_SIZE,
72
- skip
73
- ),
74
- async (batch) => {
75
- const filteredBatch = (lastTask?.updated ? batch.filter((commitment) => this.isRecordUpdated(commitment)) : batch).filter((commitment) => commitment.id !== "");
76
- if (filteredBatch.length > 0) {
77
- await captchaDB.saveCaptchas([], filteredBatch, []);
78
- await this.providerDB.markDappUserCommitmentsStored(
79
- filteredBatch.map((commitment) => commitment.id),
80
- sweepStartedAt
81
- );
82
- }
83
- processedCommitments += filteredBatch.length;
84
- }
85
- );
86
- let processedPowRecords = 0;
87
- await this.processBatchesWithCursor(
88
- async (skip) => await this.providerDB.getUnstoredDappUserPoWCommitments(
89
- BATCH_SIZE,
90
- skip
91
- ),
92
- async (batch) => {
93
- const filteredBatch = lastTask?.updated ? batch.filter((record) => this.isRecordUpdated(record)) : batch;
94
- if (filteredBatch.length > 0) {
95
- await captchaDB.saveCaptchas([], [], filteredBatch);
96
- await this.providerDB.markDappUserPoWCommitmentsStored(
97
- filteredBatch.map((record) => record.challenge),
98
- sweepStartedAt
99
- );
100
- }
101
- processedPowRecords += filteredBatch.length;
102
- }
103
- );
104
- let processedSessionRecords = 0;
105
- await this.processBatchesWithCursor(
106
- async (skip) => await this.providerDB.getUnstoredSessionRecords(BATCH_SIZE, skip),
107
- async (batch) => {
108
- const filteredBatch = lastTask?.updated ? batch.filter((record) => this.isRecordUpdated(record)) : batch;
109
- if (filteredBatch.length > 0) {
110
- await captchaDB.saveCaptchas(filteredBatch, [], []);
111
- await this.providerDB.markSessionRecordsStored(
112
- filteredBatch.map((record) => record.sessionId),
113
- sweepStartedAt
114
- );
115
- }
116
- processedSessionRecords += filteredBatch.length;
117
- }
118
- );
119
- await this.providerDB.updateScheduledTaskStatus(
120
- taskID,
121
- types.ScheduledTaskStatus.Completed,
122
- {
123
- data: {
124
- processedSessionRecords,
125
- processedCommitments,
126
- processedPowRecords
127
- }
128
- }
129
- );
130
- this.captchaDB?.close();
131
- } catch (e) {
132
- this.logger.error(() => ({
133
- err: e,
134
- msg: "Error processing client tasks"
135
- }));
136
- this.captchaDB?.close();
137
- await this.providerDB.updateScheduledTaskStatus(
138
- taskID,
139
- types.ScheduledTaskStatus.Failed,
140
- { error: String(e) }
141
- );
142
- }
143
- }
144
- /**
145
- * @description Get a list of client accounts and their settings from the client database
146
- * @returns Promise<void>
147
- */
148
- async getClientList() {
149
- if (!this.config.mongoClientUri) {
150
- this.logger.info(() => ({ msg: "Mongo env not set" }));
151
- return;
152
- }
153
- const lastTask = await this.providerDB.getLastScheduledTaskStatus(
154
- types.ScheduledTaskNames.GetClientList,
155
- types.ScheduledTaskStatus.Completed
156
- );
157
- const taskID = await this.providerDB.createScheduledTaskStatus(
158
- types.ScheduledTaskNames.GetClientList,
159
- types.ScheduledTaskStatus.Running
160
- );
161
- try {
162
- const clientDB = new database.ClientDatabase(
163
- this.config.mongoClientUri,
164
- void 0,
165
- // expected to come from URI
166
- void 0,
167
- // expected to come from URI
168
- this.logger
169
- );
170
- const tenMinuteWindow = 10 * 60 * 1e3;
171
- const updatedAtTimestamp = (() => {
172
- const raw = lastTask?.updated;
173
- if (!raw) return 0;
174
- const ts = raw instanceof Date ? raw.getTime() : Date.parse(String(raw));
175
- if (Number.isNaN(ts)) return 0;
176
- return Math.max(ts - tenMinuteWindow, 0);
177
- })();
178
- this.logger.info(() => ({
179
- msg: `Getting updated client records since ${new Date(updatedAtTimestamp).toDateString()}`
180
- }));
181
- const newClientRecords = await clientDB.getUpdatedClients(updatedAtTimestamp);
182
- if (newClientRecords) {
183
- await this.providerDB.updateClientRecords(newClientRecords);
184
- }
185
- await this.providerDB.updateScheduledTaskStatus(
186
- taskID,
187
- types.ScheduledTaskStatus.Completed,
188
- {
189
- data: {
190
- clientRecords: newClientRecords.length
191
- }
192
- }
193
- );
194
- } catch (e) {
195
- const getClientListError = new common.ProsopoApiError("DATABASE.UNKNOWN", {
196
- context: { error: e },
197
- logger: this.logger
198
- });
199
- this.logger.error(() => ({
200
- err: getClientListError,
201
- msg: "Error getting client list"
202
- }));
203
- await this.providerDB.updateScheduledTaskStatus(
204
- taskID,
205
- types.ScheduledTaskStatus.Failed,
206
- { error: String(e) }
207
- );
208
- }
209
- }
210
- /**
211
- * @description Calculate client entropy scores and update in db
212
- * @returns Promise<void>
213
- */
214
- async calculateClientEntropy() {
215
- const taskID = await this.providerDB.createScheduledTaskStatus(
216
- types.ScheduledTaskNames.SetClientEntropy,
217
- types.ScheduledTaskStatus.Running
218
- );
219
- try {
220
- let clients = await this.providerDB.getAllClientRecords();
221
- clients = clients.filter((client) => client.tier !== types.Tier.Free);
222
- this.logger.info(() => ({
223
- msg: `Calculating entropies for ${clients.length} clients`
224
- }));
225
- for (const client of clients) {
226
- if (client.settings?.contextAware?.enabled) {
227
- const contextTypes = Object.keys(
228
- client.settings.contextAware.contexts ?? {}
229
- );
230
- for (const contextType of contextTypes) {
231
- const contextSamples = await this.providerDB.sampleContextEntropy(
232
- SAMPLE_SIZE,
233
- client.account,
234
- contextType
235
- );
236
- if (contextSamples.length < SAMPLE_SIZE) {
237
- this.logger.info(() => ({
238
- msg: `Skipping ${contextType} entropy calculation for client ${client.account} due to insufficient samples (${contextSamples.length}/${SAMPLE_SIZE})`
239
- }));
240
- continue;
241
- }
242
- const contextAvgEntropy = util.majorityAverage(contextSamples);
243
- this.logger.info(() => ({
244
- msg: `Calculated ${contextType} entropy for client ${client.account}: ${contextAvgEntropy}`
245
- }));
246
- await this.providerDB.setClientContextEntropy(
247
- client.account,
248
- contextType,
249
- contextAvgEntropy
250
- );
251
- }
252
- }
253
- }
254
- await this.providerDB.updateScheduledTaskStatus(
255
- taskID,
256
- types.ScheduledTaskStatus.Completed,
257
- {
258
- data: {
259
- clientRecords: clients.length
260
- }
261
- }
262
- );
263
- } catch (e) {
264
- const calculateClientEntropiesError = new common.ProsopoApiError(
265
- "DATABASE.UNKNOWN",
266
- {
267
- context: { error: e },
268
- logger: this.logger
269
- }
270
- );
271
- this.logger.error(() => ({
272
- err: calculateClientEntropiesError,
273
- msg: "Error calculating client entropy"
274
- }));
275
- await this.providerDB.updateScheduledTaskStatus(
276
- taskID,
277
- types.ScheduledTaskStatus.Failed,
278
- { error: String(e) }
279
- );
280
- }
281
- }
282
- async registerSiteKey(siteKey, tier, settings) {
283
- validateAddress.validateSiteKey(siteKey);
284
- await this.providerDB.updateClientRecords([
285
- {
286
- account: siteKey,
287
- tier,
288
- settings
289
- }
290
- ]);
291
- }
292
- async registerSiteKeys(siteKeys) {
293
- const records = [];
294
- for (const { siteKey, tier, settings } of siteKeys) {
295
- validateAddress.validateSiteKey(siteKey);
296
- records.push({
297
- account: siteKey,
298
- tier,
299
- settings
300
- });
301
- }
302
- await this.providerDB.updateClientRecords(records);
303
- }
304
- async removeSiteKey(siteKey) {
305
- validateAddress.validateSiteKey(siteKey);
306
- await this.providerDB.removeClientRecords([siteKey]);
307
- }
308
- async removeSiteKeys(siteKeys) {
309
- const accounts = [];
310
- for (const { siteKey } of siteKeys) {
311
- validateAddress.validateSiteKey(siteKey);
312
- accounts.push(siteKey);
313
- }
314
- await this.providerDB.removeClientRecords(accounts);
315
- }
316
- async updateDetectorKey(detectorKey) {
317
- if (!isValidPrivateKey(detectorKey)) {
318
- throw new common.ProsopoApiError("INVALID_DETECTOR_KEY", {
319
- context: { detectorKey },
320
- logger: this.logger
321
- });
322
- }
323
- await this.providerDB.storeDetectorKey(detectorKey);
324
- const activeDetectorKeys = await this.providerDB.getDetectorKeys();
325
- return activeDetectorKeys;
326
- }
327
- async removeDetectorKey(detectorKey, expirationInSeconds) {
328
- if (!isValidPrivateKey(detectorKey)) {
329
- throw new common.ProsopoApiError("INVALID_DETECTOR_KEY", {
330
- context: { detectorKey },
331
- logger: this.logger
332
- });
333
- }
334
- await this.providerDB.removeDetectorKey(detectorKey, expirationInSeconds);
335
- }
336
- async updateDecisionMachine(scope, runtime, source, dappAccount, language, name, version, captchaType, kind) {
337
- if (scope === types.DecisionMachineScope.Dapp && !dappAccount) {
338
- throw new common.ProsopoApiError("API.BAD_REQUEST", {
339
- context: { scope, dappAccount },
340
- logger: this.logger
341
- });
342
- }
343
- const now = /* @__PURE__ */ new Date();
344
- await this.providerDB.upsertDecisionMachineArtifact({
345
- scope,
346
- dappAccount,
347
- kind,
348
- runtime,
349
- language,
350
- source,
351
- name,
352
- version,
353
- captchaType,
354
- createdAt: now,
355
- updatedAt: now
356
- });
357
- return {
358
- scope,
359
- dappAccount,
360
- kind,
361
- updatedAt: now.toISOString()
362
- };
363
- }
364
- async getAllDecisionMachines() {
365
- const artifacts = await this.providerDB.getAllDecisionMachineArtifacts();
366
- return artifacts.map((artifact) => ({
367
- _id: artifact._id.toString(),
368
- scope: artifact.scope,
369
- dappAccount: artifact.dappAccount,
370
- kind: artifact.kind,
371
- runtime: artifact.runtime,
372
- language: artifact.language,
373
- name: artifact.name,
374
- version: artifact.version,
375
- captchaType: artifact.captchaType,
376
- source: artifact.source,
377
- createdAt: artifact.createdAt.toISOString(),
378
- updatedAt: artifact.updatedAt.toISOString()
379
- }));
380
- }
381
- async getDecisionMachine(id) {
382
- const artifact = await this.providerDB.getDecisionMachineArtifactById(id);
383
- if (!artifact) {
384
- throw new common.ProsopoApiError("API.BAD_REQUEST", {
385
- context: { id },
386
- logger: this.logger
387
- });
388
- }
389
- return {
390
- _id: artifact._id.toString(),
391
- scope: artifact.scope,
392
- dappAccount: artifact.dappAccount,
393
- kind: artifact.kind,
394
- runtime: artifact.runtime,
395
- language: artifact.language,
396
- source: artifact.source,
397
- name: artifact.name,
398
- version: artifact.version,
399
- captchaType: artifact.captchaType,
400
- createdAt: artifact.createdAt.toISOString(),
401
- updatedAt: artifact.updatedAt.toISOString()
402
- };
403
- }
404
- async removeDecisionMachine(id) {
405
- const success = await this.providerDB.removeDecisionMachineArtifact(id);
406
- if (!success) {
407
- throw new common.ProsopoApiError("API.BAD_REQUEST", {
408
- context: { id, message: "Decision machine not found" },
409
- logger: this.logger
410
- });
411
- }
412
- return {
413
- success,
414
- deletedId: id
415
- };
416
- }
417
- async removeAllDecisionMachines() {
418
- const deletedCount = await this.providerDB.removeAllDecisionMachineArtifacts();
419
- return {
420
- success: true,
421
- deletedCount
422
- };
423
- }
424
- /**
425
- * Matches a request referrer against an allowed domain pattern.
426
- * Supports global '*', subdomain '*.example.com', glob '*example*',
427
- * plain domains (exact or subdomain), and 'localhost'.
428
- */
429
- domainPatternMatcher(referrer, clientDomain) {
430
- if (!referrer || !clientDomain) return false;
431
- try {
432
- const referrerHost = util.parseUrl(referrer).hostname.replace(/\.$/, "");
433
- const pattern = clientDomain.trim().toLowerCase();
434
- if (pattern === "*") return true;
435
- if (pattern === "localhost") {
436
- return referrerHost === "localhost" || referrerHost.startsWith("localhost:");
437
- }
438
- if (pattern.startsWith("*.")) {
439
- const suffix = pattern.slice(2);
440
- const allowed = util.parseUrl(suffix).hostname.replace(/\.$/, "");
441
- return referrerHost.endsWith(`.${allowed}`) || referrerHost === allowed;
442
- }
443
- if (pattern.includes("*")) {
444
- const escaped = pattern.replace(/[.+?^${}()|\[\]\\]/g, "\\$&").replace(/\*/g, ".*");
445
- const regex = new RegExp(`^${escaped}$`, "i");
446
- return regex.test(referrerHost);
447
- }
448
- const allowedHost = util.parseUrl(pattern).hostname.replace(/\.$/, "");
449
- return referrerHost === allowedHost || referrerHost.endsWith(`.${allowedHost}`);
450
- } catch (e) {
451
- this.logger.error(() => ({
452
- msg: "Error in domainPatternMatcher",
453
- data: { referrer, clientDomain }
454
- }));
455
- return false;
456
- }
457
- }
458
- isRecordUpdated(record) {
459
- const { lastUpdatedTimestamp, storedAtTimestamp } = record;
460
- return !lastUpdatedTimestamp || !storedAtTimestamp || lastUpdatedTimestamp.getTime() > storedAtTimestamp.getTime();
461
- }
462
- async processBatchesWithCursor(fetchBatch, processBatch) {
463
- let skip = 0;
464
- while (true) {
465
- const batch = await fetchBatch(skip);
466
- if (!batch.length) break;
467
- await processBatch(batch);
468
- skip += batch.length;
469
- }
470
- }
471
- }
22
+ var ClientTaskManager = class {
23
+ constructor(config, logger, db) {
24
+ this.config = config;
25
+ this.logger = logger;
26
+ this.providerDB = db;
27
+ }
28
+ /**
29
+ * @description Get the captcha database connection or create a new one
30
+ * @returns CaptchaDatabase
31
+ */
32
+ getCaptchaDB(mongoCaptchaUri) {
33
+ if (this.captchaDB) return this.captchaDB;
34
+ if (!this.captchaDB) this.captchaDB = new _prosopo_database.CaptchaDatabase(mongoCaptchaUri, void 0, void 0, this.logger);
35
+ return this.captchaDB;
36
+ }
37
+ /**
38
+ * @description Store commitments externally in the database (Sends image captcha data to the big Mongo Cloud DB)
39
+ * @returns Promise<void>
40
+ */
41
+ async storeCommitmentsExternal() {
42
+ if (!this.config.mongoCaptchaUri) {
43
+ this.logger.info(() => ({ msg: "Mongo env not set" }));
44
+ return;
45
+ }
46
+ const lastTask = await this.providerDB.getLastScheduledTaskStatus(_prosopo_types.ScheduledTaskNames.StoreCommitmentsExternal, _prosopo_types.ScheduledTaskStatus.Completed);
47
+ const taskID = await this.providerDB.createScheduledTaskStatus(_prosopo_types.ScheduledTaskNames.StoreCommitmentsExternal, _prosopo_types.ScheduledTaskStatus.Running);
48
+ try {
49
+ const BATCH_SIZE = 1e3;
50
+ const captchaDB = this.getCaptchaDB(this.config.mongoCaptchaUri);
51
+ const sweepStartedAt = /* @__PURE__ */ new Date();
52
+ let processedCommitments = 0;
53
+ await this.processBatchesWithCursor(async (skip) => await this.providerDB.getUnstoredDappUserCommitments(BATCH_SIZE, skip), async (batch) => {
54
+ const filteredBatch = (lastTask?.updated ? batch.filter((commitment) => this.isRecordUpdated(commitment)) : batch).filter((commitment) => commitment.id !== "");
55
+ if (filteredBatch.length > 0) {
56
+ await captchaDB.saveCaptchas([], filteredBatch, []);
57
+ await this.providerDB.markDappUserCommitmentsStored(filteredBatch.map((commitment) => commitment.id), sweepStartedAt);
58
+ }
59
+ processedCommitments += filteredBatch.length;
60
+ });
61
+ let processedPowRecords = 0;
62
+ await this.processBatchesWithCursor(async (skip) => await this.providerDB.getUnstoredDappUserPoWCommitments(BATCH_SIZE, skip), async (batch) => {
63
+ const filteredBatch = lastTask?.updated ? batch.filter((record) => this.isRecordUpdated(record)) : batch;
64
+ if (filteredBatch.length > 0) {
65
+ await captchaDB.saveCaptchas([], [], filteredBatch);
66
+ await this.providerDB.markDappUserPoWCommitmentsStored(filteredBatch.map((record) => record.challenge), sweepStartedAt);
67
+ }
68
+ processedPowRecords += filteredBatch.length;
69
+ });
70
+ let processedSessionRecords = 0;
71
+ await this.processBatchesWithCursor(async (skip) => await this.providerDB.getUnstoredSessionRecords(BATCH_SIZE, skip), async (batch) => {
72
+ const filteredBatch = lastTask?.updated ? batch.filter((record) => this.isRecordUpdated(record)) : batch;
73
+ if (filteredBatch.length > 0) {
74
+ await captchaDB.saveCaptchas(filteredBatch, [], []);
75
+ await this.providerDB.markSessionRecordsStored(filteredBatch.map((record) => record.sessionId), sweepStartedAt);
76
+ }
77
+ processedSessionRecords += filteredBatch.length;
78
+ });
79
+ await this.providerDB.updateScheduledTaskStatus(taskID, _prosopo_types.ScheduledTaskStatus.Completed, { data: {
80
+ processedSessionRecords,
81
+ processedCommitments,
82
+ processedPowRecords
83
+ } });
84
+ this.captchaDB?.close();
85
+ } catch (e) {
86
+ this.logger.error(() => ({
87
+ err: e,
88
+ msg: "Error processing client tasks"
89
+ }));
90
+ this.captchaDB?.close();
91
+ await this.providerDB.updateScheduledTaskStatus(taskID, _prosopo_types.ScheduledTaskStatus.Failed, { error: String(e) });
92
+ }
93
+ }
94
+ /**
95
+ * @description Get a list of client accounts and their settings from the client database
96
+ * @returns Promise<void>
97
+ */
98
+ async getClientList() {
99
+ if (!this.config.mongoClientUri) {
100
+ this.logger.info(() => ({ msg: "Mongo env not set" }));
101
+ return;
102
+ }
103
+ const lastTask = await this.providerDB.getLastScheduledTaskStatus(_prosopo_types.ScheduledTaskNames.GetClientList, _prosopo_types.ScheduledTaskStatus.Completed);
104
+ const taskID = await this.providerDB.createScheduledTaskStatus(_prosopo_types.ScheduledTaskNames.GetClientList, _prosopo_types.ScheduledTaskStatus.Running);
105
+ try {
106
+ const clientDB = new _prosopo_database.ClientDatabase(this.config.mongoClientUri, void 0, void 0, this.logger);
107
+ const tenMinuteWindow = 600 * 1e3;
108
+ const updatedAtTimestamp = (() => {
109
+ const raw = lastTask?.updated;
110
+ if (!raw) return 0;
111
+ const ts = raw instanceof Date ? raw.getTime() : Date.parse(String(raw));
112
+ if (Number.isNaN(ts)) return 0;
113
+ return Math.max(ts - tenMinuteWindow, 0);
114
+ })();
115
+ this.logger.info(() => ({ msg: `Getting updated client records since ${new Date(updatedAtTimestamp).toDateString()}` }));
116
+ const newClientRecords = await clientDB.getUpdatedClients(updatedAtTimestamp);
117
+ if (newClientRecords) await this.providerDB.updateClientRecords(newClientRecords);
118
+ await this.providerDB.updateScheduledTaskStatus(taskID, _prosopo_types.ScheduledTaskStatus.Completed, { data: { clientRecords: newClientRecords.length } });
119
+ } catch (e) {
120
+ const getClientListError = new _prosopo_common.ProsopoApiError("DATABASE.UNKNOWN", {
121
+ context: { error: e },
122
+ logger: this.logger
123
+ });
124
+ this.logger.error(() => ({
125
+ err: getClientListError,
126
+ msg: "Error getting client list"
127
+ }));
128
+ await this.providerDB.updateScheduledTaskStatus(taskID, _prosopo_types.ScheduledTaskStatus.Failed, { error: String(e) });
129
+ }
130
+ }
131
+ /**
132
+ * @description Calculate client entropy scores and update in db
133
+ * @returns Promise<void>
134
+ */
135
+ async calculateClientEntropy() {
136
+ const taskID = await this.providerDB.createScheduledTaskStatus(_prosopo_types.ScheduledTaskNames.SetClientEntropy, _prosopo_types.ScheduledTaskStatus.Running);
137
+ try {
138
+ let clients = await this.providerDB.getAllClientRecords();
139
+ clients = clients.filter((client) => client.tier !== _prosopo_types.Tier.Free);
140
+ this.logger.info(() => ({ msg: `Calculating entropies for ${clients.length} clients` }));
141
+ for (const client of clients) if (client.settings?.contextAware?.enabled) {
142
+ const contextTypes = Object.keys(client.settings.contextAware.contexts ?? {});
143
+ for (const contextType of contextTypes) {
144
+ const contextSamples = await this.providerDB.sampleContextEntropy(SAMPLE_SIZE, client.account, contextType);
145
+ if (contextSamples.length < SAMPLE_SIZE) {
146
+ this.logger.info(() => ({ msg: `Skipping ${contextType} entropy calculation for client ${client.account} due to insufficient samples (${contextSamples.length}/${SAMPLE_SIZE})` }));
147
+ continue;
148
+ }
149
+ const contextAvgEntropy = (0, _prosopo_util.majorityAverage)(contextSamples);
150
+ this.logger.info(() => ({ msg: `Calculated ${contextType} entropy for client ${client.account}: ${contextAvgEntropy}` }));
151
+ await this.providerDB.setClientContextEntropy(client.account, contextType, contextAvgEntropy);
152
+ }
153
+ }
154
+ await this.providerDB.updateScheduledTaskStatus(taskID, _prosopo_types.ScheduledTaskStatus.Completed, { data: { clientRecords: clients.length } });
155
+ } catch (e) {
156
+ const calculateClientEntropiesError = new _prosopo_common.ProsopoApiError("DATABASE.UNKNOWN", {
157
+ context: { error: e },
158
+ logger: this.logger
159
+ });
160
+ this.logger.error(() => ({
161
+ err: calculateClientEntropiesError,
162
+ msg: "Error calculating client entropy"
163
+ }));
164
+ await this.providerDB.updateScheduledTaskStatus(taskID, _prosopo_types.ScheduledTaskStatus.Failed, { error: String(e) });
165
+ }
166
+ }
167
+ async registerSiteKey(siteKey, tier, settings) {
168
+ require_validateAddress.validateSiteKey(siteKey);
169
+ await this.providerDB.updateClientRecords([{
170
+ account: siteKey,
171
+ tier,
172
+ settings
173
+ }]);
174
+ }
175
+ async registerSiteKeys(siteKeys) {
176
+ const records = [];
177
+ for (const { siteKey, tier, settings } of siteKeys) {
178
+ require_validateAddress.validateSiteKey(siteKey);
179
+ records.push({
180
+ account: siteKey,
181
+ tier,
182
+ settings
183
+ });
184
+ }
185
+ await this.providerDB.updateClientRecords(records);
186
+ }
187
+ async removeSiteKey(siteKey) {
188
+ require_validateAddress.validateSiteKey(siteKey);
189
+ await this.providerDB.removeClientRecords([siteKey]);
190
+ }
191
+ async removeSiteKeys(siteKeys) {
192
+ const accounts = [];
193
+ for (const { siteKey } of siteKeys) {
194
+ require_validateAddress.validateSiteKey(siteKey);
195
+ accounts.push(siteKey);
196
+ }
197
+ await this.providerDB.removeClientRecords(accounts);
198
+ }
199
+ async updateDetectorKey(detectorKey) {
200
+ if (!isValidPrivateKey(detectorKey)) throw new _prosopo_common.ProsopoApiError("INVALID_DETECTOR_KEY", {
201
+ context: { detectorKey },
202
+ logger: this.logger
203
+ });
204
+ await this.providerDB.storeDetectorKey(detectorKey);
205
+ return await this.providerDB.getDetectorKeys();
206
+ }
207
+ async removeDetectorKey(detectorKey, expirationInSeconds) {
208
+ if (!isValidPrivateKey(detectorKey)) throw new _prosopo_common.ProsopoApiError("INVALID_DETECTOR_KEY", {
209
+ context: { detectorKey },
210
+ logger: this.logger
211
+ });
212
+ await this.providerDB.removeDetectorKey(detectorKey, expirationInSeconds);
213
+ }
214
+ async updateDecisionMachine(scope, runtime, source, dappAccount, language, name, version, captchaType, kind) {
215
+ if (scope === _prosopo_types.DecisionMachineScope.Dapp && !dappAccount) throw new _prosopo_common.ProsopoApiError("API.BAD_REQUEST", {
216
+ context: {
217
+ scope,
218
+ dappAccount
219
+ },
220
+ logger: this.logger
221
+ });
222
+ const now = /* @__PURE__ */ new Date();
223
+ await this.providerDB.upsertDecisionMachineArtifact({
224
+ scope,
225
+ dappAccount,
226
+ kind,
227
+ runtime,
228
+ language,
229
+ source,
230
+ name,
231
+ version,
232
+ captchaType,
233
+ createdAt: now,
234
+ updatedAt: now
235
+ });
236
+ return {
237
+ scope,
238
+ dappAccount,
239
+ kind,
240
+ updatedAt: now.toISOString()
241
+ };
242
+ }
243
+ async getAllDecisionMachines() {
244
+ return (await this.providerDB.getAllDecisionMachineArtifacts()).map((artifact) => ({
245
+ _id: artifact._id.toString(),
246
+ scope: artifact.scope,
247
+ dappAccount: artifact.dappAccount,
248
+ kind: artifact.kind,
249
+ runtime: artifact.runtime,
250
+ language: artifact.language,
251
+ name: artifact.name,
252
+ version: artifact.version,
253
+ captchaType: artifact.captchaType,
254
+ source: artifact.source,
255
+ createdAt: artifact.createdAt.toISOString(),
256
+ updatedAt: artifact.updatedAt.toISOString()
257
+ }));
258
+ }
259
+ async getDecisionMachine(id) {
260
+ const artifact = await this.providerDB.getDecisionMachineArtifactById(id);
261
+ if (!artifact) throw new _prosopo_common.ProsopoApiError("API.BAD_REQUEST", {
262
+ context: { id },
263
+ logger: this.logger
264
+ });
265
+ return {
266
+ _id: artifact._id.toString(),
267
+ scope: artifact.scope,
268
+ dappAccount: artifact.dappAccount,
269
+ kind: artifact.kind,
270
+ runtime: artifact.runtime,
271
+ language: artifact.language,
272
+ source: artifact.source,
273
+ name: artifact.name,
274
+ version: artifact.version,
275
+ captchaType: artifact.captchaType,
276
+ createdAt: artifact.createdAt.toISOString(),
277
+ updatedAt: artifact.updatedAt.toISOString()
278
+ };
279
+ }
280
+ async removeDecisionMachine(id) {
281
+ const success = await this.providerDB.removeDecisionMachineArtifact(id);
282
+ if (!success) throw new _prosopo_common.ProsopoApiError("API.BAD_REQUEST", {
283
+ context: {
284
+ id,
285
+ message: "Decision machine not found"
286
+ },
287
+ logger: this.logger
288
+ });
289
+ return {
290
+ success,
291
+ deletedId: id
292
+ };
293
+ }
294
+ async removeAllDecisionMachines() {
295
+ return {
296
+ success: true,
297
+ deletedCount: await this.providerDB.removeAllDecisionMachineArtifacts()
298
+ };
299
+ }
300
+ /**
301
+ * Matches a request referrer against an allowed domain pattern.
302
+ * Supports global '*', subdomain '*.example.com', glob '*example*',
303
+ * plain domains (exact or subdomain), and 'localhost'.
304
+ */
305
+ domainPatternMatcher(referrer, clientDomain) {
306
+ if (!referrer || !clientDomain) return false;
307
+ try {
308
+ const referrerHost = (0, _prosopo_util.parseUrl)(referrer).hostname.replace(/\.$/, "");
309
+ const pattern = clientDomain.trim().toLowerCase();
310
+ if (pattern === "*") return true;
311
+ if (pattern === "localhost") return referrerHost === "localhost" || referrerHost.startsWith("localhost:");
312
+ if (pattern.startsWith("*.")) {
313
+ const suffix = pattern.slice(2);
314
+ const allowed = (0, _prosopo_util.parseUrl)(suffix).hostname.replace(/\.$/, "");
315
+ return referrerHost.endsWith(`.${allowed}`) || referrerHost === allowed;
316
+ }
317
+ if (pattern.includes("*")) {
318
+ const escaped = pattern.replace(/[.+?^${}()|\[\]\\]/g, "\\$&").replace(/\*/g, ".*");
319
+ return new RegExp(`^${escaped}$`, "i").test(referrerHost);
320
+ }
321
+ const allowedHost = (0, _prosopo_util.parseUrl)(pattern).hostname.replace(/\.$/, "");
322
+ return referrerHost === allowedHost || referrerHost.endsWith(`.${allowedHost}`);
323
+ } catch (e) {
324
+ this.logger.error(() => ({
325
+ msg: "Error in domainPatternMatcher",
326
+ data: {
327
+ referrer,
328
+ clientDomain
329
+ }
330
+ }));
331
+ return false;
332
+ }
333
+ }
334
+ isRecordUpdated(record) {
335
+ const { lastUpdatedTimestamp, storedAtTimestamp } = record;
336
+ return !lastUpdatedTimestamp || !storedAtTimestamp || lastUpdatedTimestamp.getTime() > storedAtTimestamp.getTime();
337
+ }
338
+ async processBatchesWithCursor(fetchBatch, processBatch) {
339
+ let skip = 0;
340
+ while (true) {
341
+ const batch = await fetchBatch(skip);
342
+ if (!batch.length) break;
343
+ await processBatch(batch);
344
+ skip += batch.length;
345
+ }
346
+ }
347
+ };
348
+ //#endregion
472
349
  exports.ClientTaskManager = ClientTaskManager;