@prosopo/provider 4.15.13 → 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.
- package/.turbo/turbo-build$colon$cjs.log +106 -106
- package/.turbo/turbo-build$colon$tsc.log +24 -24
- package/.turbo/turbo-build.log +107 -104
- package/CHANGELOG.md +78 -0
- package/dist/_virtual/_rolldown/runtime.js +3 -0
- package/dist/api/admin/apiAdminRoutesProvider.js +27 -46
- package/dist/api/admin/apiClearAllCountersEndpoint.js +62 -57
- package/dist/api/admin/apiDnsEventEndpoint.js +79 -92
- package/dist/api/admin/apiGetAllDecisionMachinesEndpoint.js +43 -45
- package/dist/api/admin/apiGetDecisionMachineEndpoint.js +40 -40
- package/dist/api/admin/apiRegisterSiteKeyEndpoint.js +23 -22
- package/dist/api/admin/apiRegisterSiteKeysEndpoint.js +26 -30
- package/dist/api/admin/apiRemoveAllDecisionMachinesEndpoint.js +35 -37
- package/dist/api/admin/apiRemoveDecisionMachineEndpoint.js +40 -40
- package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts.map +1 -1
- package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js +29 -31
- package/dist/api/admin/apiRemoveSiteKeyEndpoint.js +33 -29
- package/dist/api/admin/apiRemoveSiteKeysEndpoint.js +32 -31
- package/dist/api/admin/apiToggleMaintenanceModeEndpoint.js +43 -35
- package/dist/api/admin/apiUpdateDecisionMachineEndpoint.js +43 -63
- package/dist/api/admin/apiUpdateDetectorKeyEndpoint.js +36 -35
- package/dist/api/admin/createApiAdminRoutesProvider.js +6 -8
- package/dist/api/blacklistRequestInspector.js +285 -377
- package/dist/api/block.js +17 -30
- package/dist/api/captcha/checkSpamEmail.js +88 -98
- package/dist/api/captcha/contextAwareValidation.js +21 -15
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/accessPolicy.js +126 -140
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/constants.js +11 -12
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js +236 -299
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.js +10 -13
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +336 -462
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/honeypotResponse.js +17 -14
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/sessionDedup.js +27 -27
- package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js +42 -63
- package/dist/api/captcha/getFrictionlessCaptchaChallenge.js +2 -4
- package/dist/api/captcha/getImageCaptchaChallenge.js +136 -207
- package/dist/api/captcha/getPoWCaptchaChallenge.js +128 -198
- package/dist/api/captcha/getPuzzleCaptchaChallenge.js +132 -201
- package/dist/api/captcha/maintenanceModeResponses.js +38 -47
- package/dist/api/captcha/submitImageCaptchaSolution.js +75 -101
- package/dist/api/captcha/submitPoWCaptchaSolution.js +137 -207
- package/dist/api/captcha/submitPuzzleCaptchaSolution.js +73 -105
- package/dist/api/captcha.js +76 -58
- package/dist/api/dnsEventUrl.js +20 -22
- package/dist/api/domainMiddleware.js +104 -115
- package/dist/api/forwardVerify.js +62 -48
- package/dist/api/handshakeTimingMiddleware.js +43 -62
- package/dist/api/hardBlockVerdictCache.js +114 -117
- package/dist/api/headerCheckMiddleware.js +34 -34
- package/dist/api/ignoreMiddleware.js +13 -15
- package/dist/api/ipInfoMiddleware.js +17 -19
- package/dist/api/ja4.js +149 -188
- package/dist/api/ja4Middleware.js +39 -54
- package/dist/api/metrics.js +245 -257
- package/dist/api/public.js +52 -54
- package/dist/api/robotsMiddleware.js +10 -10
- package/dist/api/startProviderApi.js +205 -232
- package/dist/api/testSiteKey.js +16 -16
- package/dist/api/validateAddress.js +23 -21
- package/dist/api/verify.js +334 -377
- package/dist/cjs/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/cjs/api/admin/apiAdminRoutesProvider.cjs +40 -59
- package/dist/cjs/api/admin/apiClearAllCountersEndpoint.cjs +63 -58
- package/dist/cjs/api/admin/apiDnsEventEndpoint.cjs +82 -93
- package/dist/cjs/api/admin/apiGetAllDecisionMachinesEndpoint.cjs +46 -48
- package/dist/cjs/api/admin/apiGetDecisionMachineEndpoint.cjs +41 -41
- package/dist/cjs/api/admin/apiRegisterSiteKeyEndpoint.cjs +25 -24
- package/dist/cjs/api/admin/apiRegisterSiteKeysEndpoint.cjs +28 -32
- package/dist/cjs/api/admin/apiRemoveAllDecisionMachinesEndpoint.cjs +38 -40
- package/dist/cjs/api/admin/apiRemoveDecisionMachineEndpoint.cjs +41 -41
- package/dist/cjs/api/admin/apiRemoveDetectorKeyEndpoint.cjs +31 -33
- package/dist/cjs/api/admin/apiRemoveSiteKeyEndpoint.cjs +35 -31
- package/dist/cjs/api/admin/apiRemoveSiteKeysEndpoint.cjs +34 -33
- package/dist/cjs/api/admin/apiToggleMaintenanceModeEndpoint.cjs +45 -35
- package/dist/cjs/api/admin/apiUpdateDecisionMachineEndpoint.cjs +45 -65
- package/dist/cjs/api/admin/apiUpdateDetectorKeyEndpoint.cjs +38 -37
- package/dist/cjs/api/admin/createApiAdminRoutesProvider.cjs +7 -8
- package/dist/cjs/api/blacklistRequestInspector.cjs +288 -376
- package/dist/cjs/api/block.cjs +18 -30
- package/dist/cjs/api/captcha/checkSpamEmail.cjs +90 -100
- package/dist/cjs/api/captcha/contextAwareValidation.cjs +21 -14
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/accessPolicy.cjs +125 -140
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/constants.cjs +10 -10
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.cjs +238 -301
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decryptSimdReadings.cjs +9 -12
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +349 -473
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/honeypotResponse.cjs +18 -14
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/sessionDedup.cjs +26 -26
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.cjs +42 -63
- package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge.cjs +2 -3
- package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +138 -208
- package/dist/cjs/api/captcha/getPoWCaptchaChallenge.cjs +131 -200
- package/dist/cjs/api/captcha/getPuzzleCaptchaChallenge.cjs +135 -203
- package/dist/cjs/api/captcha/maintenanceModeResponses.cjs +38 -44
- package/dist/cjs/api/captcha/submitImageCaptchaSolution.cjs +77 -102
- package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +140 -209
- package/dist/cjs/api/captcha/submitPuzzleCaptchaSolution.cjs +76 -107
- package/dist/cjs/api/captcha.cjs +79 -58
- package/dist/cjs/api/dnsEventUrl.cjs +20 -21
- package/dist/cjs/api/domainMiddleware.cjs +106 -117
- package/dist/cjs/api/forwardVerify.cjs +63 -49
- package/dist/cjs/api/handshakeTimingMiddleware.cjs +43 -61
- package/dist/cjs/api/hardBlockVerdictCache.cjs +114 -114
- package/dist/cjs/api/headerCheckMiddleware.cjs +34 -34
- package/dist/cjs/api/ignoreMiddleware.cjs +12 -14
- package/dist/cjs/api/ipInfoMiddleware.cjs +16 -18
- package/dist/cjs/api/ja4.cjs +149 -187
- package/dist/cjs/api/ja4Middleware.cjs +40 -53
- package/dist/cjs/api/metrics.cjs +229 -228
- package/dist/cjs/api/public.cjs +57 -57
- package/dist/cjs/api/robotsMiddleware.cjs +9 -9
- package/dist/cjs/api/startProviderApi.cjs +219 -237
- package/dist/cjs/api/testSiteKey.cjs +15 -14
- package/dist/cjs/api/validateAddress.cjs +24 -21
- package/dist/cjs/api/verify.cjs +338 -379
- package/dist/cjs/compositeIpAddress.cjs +40 -47
- package/dist/cjs/index.cjs +65 -71
- package/dist/cjs/pairs.cjs +31 -35
- package/dist/cjs/rules/lang.cjs +10 -14
- package/dist/cjs/schedulers/captchaScheduler.cjs +26 -32
- package/dist/cjs/schedulers/getClientList.cjs +35 -33
- package/dist/cjs/schedulers/setClientEntropy.cjs +35 -33
- package/dist/cjs/schedulers/updateSpamEmailDomains.cjs +39 -43
- package/dist/cjs/services/ipComparison.cjs +122 -119
- package/dist/cjs/tasks/captchaManager.cjs +407 -486
- package/dist/cjs/tasks/client/clientTasks.cjs +347 -470
- package/dist/cjs/tasks/dataset/datasetTasks.cjs +25 -29
- package/dist/cjs/tasks/dataset/datasetTasksUtils.cjs +16 -32
- package/dist/cjs/tasks/decisionMachine/decisionMachineRunner.cjs +220 -307
- package/dist/cjs/tasks/detection/decodeBehavior.cjs +408 -317
- package/dist/cjs/tasks/detection/decodePayload.cjs +686 -468
- package/dist/cjs/tasks/detection/decodeSimd.cjs +462 -304
- package/dist/cjs/tasks/detection/getBotScore.cjs +37 -43
- package/dist/cjs/tasks/dnsEvent/enrichDnsEvent.cjs +88 -71
- package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +348 -486
- package/dist/cjs/tasks/frictionless/frictionlessTasksUtils.cjs +13 -30
- package/dist/cjs/tasks/frictionless/routingMachine.cjs +71 -55
- package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +555 -806
- package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasksUtils.cjs +22 -23
- package/dist/cjs/tasks/index.cjs +2 -4
- package/dist/cjs/tasks/powCaptcha/powTasks.cjs +491 -687
- package/dist/cjs/tasks/powCaptcha/powTasksUtils.cjs +17 -29
- package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +422 -591
- package/dist/cjs/tasks/puzzleCaptcha/puzzleTasksUtils.cjs +8 -5
- package/dist/cjs/tasks/spam/checkSpamEmail.cjs +133 -141
- package/dist/cjs/tasks/spam/checkTrafficFilter.cjs +118 -76
- package/dist/cjs/tasks/spam/evaluateEmailSpamRules.cjs +75 -84
- package/dist/cjs/tasks/spam/updateSpamEmailDomains.cjs +40 -56
- package/dist/cjs/tasks/tasks.cjs +107 -158
- package/dist/cjs/util/usageCounters.cjs +220 -211
- package/dist/cjs/util.cjs +329 -359
- package/dist/cjs/utils/devicePlatform.cjs +14 -8
- package/dist/cjs/utils/dns.cjs +68 -93
- package/dist/cjs/utils/hashUserAgent.cjs +14 -7
- package/dist/cjs/utils/hashUserIp.cjs +14 -6
- package/dist/cjs/utils/honeypot/encoders.cjs +74 -80
- package/dist/cjs/utils/honeypot/phraseBank.cjs +51 -44
- package/dist/cjs/utils/normalizeRequestIp.cjs +33 -25
- package/dist/compositeIpAddress.js +38 -46
- package/dist/index.js +12 -56
- package/dist/pairs.js +31 -37
- package/dist/rules/lang.js +11 -15
- package/dist/schedulers/captchaScheduler.js +25 -31
- package/dist/schedulers/getClientList.js +34 -32
- package/dist/schedulers/setClientEntropy.js +34 -32
- package/dist/schedulers/updateSpamEmailDomains.js +38 -42
- package/dist/services/ipComparison.js +122 -119
- package/dist/tasks/captchaManager.js +403 -483
- package/dist/tasks/client/clientTasks.js +343 -467
- package/dist/tasks/dataset/datasetTasks.js +24 -28
- package/dist/tasks/dataset/datasetTasksUtils.js +15 -31
- package/dist/tasks/decisionMachine/decisionMachineRunner.js +217 -306
- package/dist/tasks/detection/getBotScore.js +37 -43
- package/dist/tasks/dnsEvent/enrichDnsEvent.d.ts.map +1 -1
- package/dist/tasks/dnsEvent/enrichDnsEvent.js +88 -74
- package/dist/tasks/dnsEvent/enrichDnsEvent.js.map +1 -1
- package/dist/tasks/frictionless/frictionlessTasks.js +342 -479
- package/dist/tasks/frictionless/frictionlessTasksUtils.js +14 -32
- package/dist/tasks/frictionless/routingMachine.js +72 -56
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +550 -801
- package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.js +21 -22
- package/dist/tasks/index.js +1 -3
- package/dist/tasks/powCaptcha/powTasks.d.ts.map +1 -1
- package/dist/tasks/powCaptcha/powTasks.js +486 -682
- package/dist/tasks/powCaptcha/powTasks.js.map +1 -1
- package/dist/tasks/powCaptcha/powTasksUtils.js +15 -28
- package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts.map +1 -1
- package/dist/tasks/puzzleCaptcha/puzzleTasks.js +417 -586
- package/dist/tasks/puzzleCaptcha/puzzleTasks.js.map +1 -1
- package/dist/tasks/puzzleCaptcha/puzzleTasksUtils.js +9 -6
- package/dist/tasks/spam/checkSpamEmail.js +133 -141
- package/dist/tasks/spam/checkTrafficFilter.d.ts +1 -0
- package/dist/tasks/spam/checkTrafficFilter.d.ts.map +1 -1
- package/dist/tasks/spam/checkTrafficFilter.js +117 -77
- package/dist/tasks/spam/checkTrafficFilter.js.map +1 -1
- package/dist/tasks/spam/evaluateEmailSpamRules.js +75 -86
- package/dist/tasks/spam/updateSpamEmailDomains.js +36 -54
- package/dist/tasks/tasks.js +98 -150
- package/dist/tests/integration/api/blacklistRequestInspector.integration.test.js +4 -1
- package/dist/tests/integration/api/blacklistRequestInspector.integration.test.js.map +1 -1
- package/dist/tests/unit/api/block.unit.test.js +8 -4
- package/dist/tests/unit/api/block.unit.test.js.map +1 -1
- package/dist/tests/unit/api/captcha/maintenanceModeShortCircuit.unit.test.js +8 -6
- package/dist/tests/unit/api/captcha/maintenanceModeShortCircuit.unit.test.js.map +1 -1
- package/dist/tests/unit/api/forwardVerify.unit.test.js +3 -1
- package/dist/tests/unit/api/forwardVerify.unit.test.js.map +1 -1
- package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js +15 -7
- package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js.map +1 -1
- package/dist/tests/unit/schedulers/captchaScheduler.unit.test.js +24 -18
- package/dist/tests/unit/schedulers/captchaScheduler.unit.test.js.map +1 -1
- package/dist/tests/unit/schedulers/getClientList.unit.test.js +19 -13
- package/dist/tests/unit/schedulers/getClientList.unit.test.js.map +1 -1
- package/dist/tests/unit/schedulers/setClientEntropy.unit.test.js +19 -13
- package/dist/tests/unit/schedulers/setClientEntropy.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/client/clientTasks.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js +22 -16
- package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js +6 -0
- package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/puzzleCaptcha/puzzleTasks.unit.test.js +60 -1
- package/dist/tests/unit/tasks/puzzleCaptcha/puzzleTasks.unit.test.js.map +1 -1
- package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js +140 -0
- package/dist/tests/unit/tasks/spam/checkTrafficFilter.unit.test.js.map +1 -1
- package/dist/tests/unit/testUtils/mockProviderEnv.d.ts +7 -7
- package/dist/util/usageCounters.js +220 -212
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +327 -364
- package/dist/util.js.map +1 -1
- package/dist/utils/devicePlatform.js +15 -9
- package/dist/utils/dns.js +64 -77
- package/dist/utils/hashUserAgent.js +14 -7
- package/dist/utils/hashUserIp.js +14 -6
- package/dist/utils/honeypot/encoders.js +74 -80
- package/dist/utils/honeypot/phraseBank.js +49 -44
- package/dist/utils/normalizeRequestIp.js +34 -26
- package/package.json +24 -24
|
@@ -1,592 +1,423 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
dnsPathValid: enrichedDnsEvent?.pathValid
|
|
424
|
-
}
|
|
425
|
-
}));
|
|
426
|
-
const blockedResult = {
|
|
427
|
-
status: types.CaptchaStatus.disapproved,
|
|
428
|
-
reason: check.reason
|
|
429
|
-
};
|
|
430
|
-
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, {
|
|
431
|
-
result: blockedResult
|
|
432
|
-
});
|
|
433
|
-
if (challengeRecord.sessionId) {
|
|
434
|
-
await this.updateSessionRecordWithCache(challengeRecord.sessionId, {
|
|
435
|
-
serverChecked: true,
|
|
436
|
-
result: blockedResult
|
|
437
|
-
});
|
|
438
|
-
}
|
|
439
|
-
return notVerifiedResponse;
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
if (storeMetadata && email) {
|
|
443
|
-
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, {
|
|
444
|
-
metadata: { email }
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
if (ip) {
|
|
448
|
-
const challengeIpAddress = compositeIpAddress.getIpAddressFromComposite(
|
|
449
|
-
challengeRecord.ipAddress
|
|
450
|
-
);
|
|
451
|
-
const clientRecord = await this.db.getClientRecord(dappAccount);
|
|
452
|
-
const ipValidationRules = clientRecord?.settings?.ipValidationRules;
|
|
453
|
-
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, {
|
|
454
|
-
providedIp: compositeIpAddress.getCompositeIpAddress(ip)
|
|
455
|
-
});
|
|
456
|
-
if (ipValidationRules?.enabled === true) {
|
|
457
|
-
const ipValidation = await util$2.deepValidateIpAddress(
|
|
458
|
-
ip,
|
|
459
|
-
challengeIpAddress,
|
|
460
|
-
logger,
|
|
461
|
-
env.ipInfoService,
|
|
462
|
-
ipValidationRules,
|
|
463
|
-
enrichedDnsEvent?.peerIp
|
|
464
|
-
);
|
|
465
|
-
if (!ipValidation.isValid) {
|
|
466
|
-
logger.error(() => ({
|
|
467
|
-
msg: "IP validation failed for puzzle captcha",
|
|
468
|
-
data: {
|
|
469
|
-
ip,
|
|
470
|
-
challengeIp: challengeIpAddress.address,
|
|
471
|
-
error: ipValidation.errorMessage,
|
|
472
|
-
distanceKm: ipValidation.distanceKm
|
|
473
|
-
}
|
|
474
|
-
}));
|
|
475
|
-
const ipFailResult = {
|
|
476
|
-
status: types.CaptchaStatus.disapproved,
|
|
477
|
-
reason: types.ResultReason.FAILED_IP_VALIDATION
|
|
478
|
-
};
|
|
479
|
-
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, {
|
|
480
|
-
result: ipFailResult
|
|
481
|
-
});
|
|
482
|
-
if (challengeRecord.sessionId) {
|
|
483
|
-
await this.updateSessionRecordWithCache(challengeRecord.sessionId, {
|
|
484
|
-
serverChecked: true,
|
|
485
|
-
result: ipFailResult
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
return notVerifiedResponse;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
let score;
|
|
493
|
-
if (sessionRecord) {
|
|
494
|
-
const dnsAsymmetry = enrichDnsEvent.computeDnsAsymmetry(
|
|
495
|
-
enrichedDnsEvent,
|
|
496
|
-
challengeRecord.ipInfo,
|
|
497
|
-
trafficFilter
|
|
498
|
-
);
|
|
499
|
-
if (dnsAsymmetry > 0) {
|
|
500
|
-
sessionRecord.scoreComponents = {
|
|
501
|
-
...sessionRecord.scoreComponents,
|
|
502
|
-
dnsAsymmetry
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
score = frictionlessTasksUtils.computeFrictionlessScore(sessionRecord?.scoreComponents);
|
|
506
|
-
logger.info(() => ({
|
|
507
|
-
data: {
|
|
508
|
-
scoreComponents: { ...sessionRecord?.scoreComponents || {} },
|
|
509
|
-
score,
|
|
510
|
-
dnsPeerAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.peerIpInfo),
|
|
511
|
-
dnsResolverAsn: enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.resolverIpInfo)
|
|
512
|
-
}
|
|
513
|
-
}));
|
|
514
|
-
}
|
|
515
|
-
try {
|
|
516
|
-
const decisionInput = {
|
|
517
|
-
userAccount: challengeRecord.userAccount,
|
|
518
|
-
dappAccount: challengeRecord.dappAccount,
|
|
519
|
-
captchaResult: "passed",
|
|
520
|
-
headers: challengeRecord.headers,
|
|
521
|
-
captchaType: types.CaptchaType.puzzle,
|
|
522
|
-
behavioralDataPacked: challengeRecord.behavioralDataPacked,
|
|
523
|
-
deviceCapability: challengeRecord.deviceCapability,
|
|
524
|
-
countryCode: challengeRecord.ipInfo?.isValid ? challengeRecord.ipInfo.countryCode : void 0,
|
|
525
|
-
ipInfo: challengeRecord.ipInfo,
|
|
526
|
-
dnsEvent: enrichedDnsEvent,
|
|
527
|
-
score,
|
|
528
|
-
threshold: sessionRecord?.threshold,
|
|
529
|
-
scoreComponents: sessionRecord?.scoreComponents,
|
|
530
|
-
decryptedHeadHash: sessionRecord?.decryptedHeadHash,
|
|
531
|
-
userSitekeyIpHash: sessionRecord?.userSitekeyIpHash,
|
|
532
|
-
simdReadings: sessionRecord?.simdReadings,
|
|
533
|
-
frictionlessReason: sessionRecord?.reason,
|
|
534
|
-
ruleType: sessionRecord?.ruleType,
|
|
535
|
-
webView: sessionRecord?.webView,
|
|
536
|
-
iFrame: sessionRecord?.iFrame,
|
|
537
|
-
coords: challengeRecord.coords,
|
|
538
|
-
puzzleEvents: challengeRecord.puzzleEvents
|
|
539
|
-
};
|
|
540
|
-
const decision = await this.decisionMachineRunner.decide(
|
|
541
|
-
decisionInput,
|
|
542
|
-
logger
|
|
543
|
-
);
|
|
544
|
-
if (decision.decision === types.DecisionMachineDecision.Deny) {
|
|
545
|
-
logger.info(() => ({
|
|
546
|
-
msg: "Decision machine denied puzzle captcha in server verification",
|
|
547
|
-
data: {
|
|
548
|
-
userAccount: challengeRecord.userAccount,
|
|
549
|
-
reason: decision.reason,
|
|
550
|
-
score: decision.score,
|
|
551
|
-
tags: decision.tags
|
|
552
|
-
}
|
|
553
|
-
}));
|
|
554
|
-
const dmResult = {
|
|
555
|
-
status: types.CaptchaStatus.disapproved,
|
|
556
|
-
reason: decision.reason || types.ResultReason.CAPTCHA_DECISION_MACHINE_DENIED
|
|
557
|
-
};
|
|
558
|
-
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, {
|
|
559
|
-
result: dmResult
|
|
560
|
-
});
|
|
561
|
-
if (challengeRecord.sessionId) {
|
|
562
|
-
await this.updateSessionRecordWithCache(challengeRecord.sessionId, {
|
|
563
|
-
serverChecked: true,
|
|
564
|
-
result: dmResult
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
return notVerifiedResponse;
|
|
568
|
-
}
|
|
569
|
-
logger.debug(() => ({
|
|
570
|
-
msg: "Decision machine allowed puzzle captcha",
|
|
571
|
-
data: {
|
|
572
|
-
reason: decision.reason,
|
|
573
|
-
score: decision.score,
|
|
574
|
-
tags: decision.tags
|
|
575
|
-
}
|
|
576
|
-
}));
|
|
577
|
-
} catch (error) {
|
|
578
|
-
logger.error(() => ({
|
|
579
|
-
msg: "Failed to run decision machine in server puzzle verification",
|
|
580
|
-
err: error
|
|
581
|
-
}));
|
|
582
|
-
}
|
|
583
|
-
if (challengeRecord.sessionId) {
|
|
584
|
-
await this.updateSessionRecordWithCache(challengeRecord.sessionId, {
|
|
585
|
-
serverChecked: true,
|
|
586
|
-
result: { status: types.CaptchaStatus.approved }
|
|
587
|
-
});
|
|
588
|
-
}
|
|
589
|
-
return { verified: true, ...score ? { score } : {} };
|
|
590
|
-
}
|
|
591
|
-
}
|
|
1
|
+
const require_usageCounters = require("../../util/usageCounters.cjs");
|
|
2
|
+
const require_decisionMachineRunner = require("../decisionMachine/decisionMachineRunner.cjs");
|
|
3
|
+
const require_compositeIpAddress = require("../../compositeIpAddress.cjs");
|
|
4
|
+
const require_enrichDnsEvent = require("../dnsEvent/enrichDnsEvent.cjs");
|
|
5
|
+
const require_captchaManager = require("../captchaManager.cjs");
|
|
6
|
+
const require_util = require("../../util.cjs");
|
|
7
|
+
const require_frictionlessTasksUtils = require("../frictionless/frictionlessTasksUtils.cjs");
|
|
8
|
+
const require_powTasksUtils = require("../powCaptcha/powTasksUtils.cjs");
|
|
9
|
+
const require_puzzleTasksUtils = require("./puzzleTasksUtils.cjs");
|
|
10
|
+
let _prosopo_common = require("@prosopo/common");
|
|
11
|
+
let _prosopo_types = require("@prosopo/types");
|
|
12
|
+
let _prosopo_util = require("@prosopo/util");
|
|
13
|
+
let _polkadot_util = require("@polkadot/util");
|
|
14
|
+
//#region src/tasks/puzzleCaptcha/puzzleTasks.ts
|
|
15
|
+
var PuzzleCaptchaManager = class extends require_captchaManager.CaptchaManager {
|
|
16
|
+
constructor(db, pair, config, logger, usageCounters) {
|
|
17
|
+
super(db, pair, config, logger);
|
|
18
|
+
this.POW_SEPARATOR = _prosopo_types.POW_SEPARATOR;
|
|
19
|
+
this.decisionMachineRunner = new require_decisionMachineRunner.DecisionMachineRunner(db);
|
|
20
|
+
this.usageCounters = usageCounters ?? null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* @description Generates a Puzzle Captcha challenge for a given user and dapp
|
|
24
|
+
*
|
|
25
|
+
* @param {string} userAccount - user that is solving the captcha
|
|
26
|
+
* @param {string} dappAccount - dapp that is requesting the captcha
|
|
27
|
+
* @param origin - not currently used
|
|
28
|
+
* @param tolerance
|
|
29
|
+
*/
|
|
30
|
+
async getPuzzleCaptchaChallenge(userAccount, dappAccount, origin, tolerance) {
|
|
31
|
+
const resolvedTolerance = tolerance ?? _prosopo_types.puzzleToleranceDefault;
|
|
32
|
+
const requestedAtTimestamp = Date.now();
|
|
33
|
+
const challenge = `${requestedAtTimestamp}___${userAccount}___${dappAccount}___${Math.floor(Math.random() * 1e6)}`;
|
|
34
|
+
const challengeSignature = (0, _polkadot_util.u8aToHex)(this.pair.sign((0, _polkadot_util.stringToHex)(challenge)));
|
|
35
|
+
return {
|
|
36
|
+
challenge,
|
|
37
|
+
targetX: Math.floor(Math.random() * 131) + 150,
|
|
38
|
+
targetY: Math.floor(Math.random() * 141) + 30,
|
|
39
|
+
originX: Math.floor(Math.random() * 111) + 20,
|
|
40
|
+
originY: Math.floor(Math.random() * 141) + 30,
|
|
41
|
+
tolerance: resolvedTolerance,
|
|
42
|
+
providerSignature: challengeSignature,
|
|
43
|
+
requestedAtTimestamp
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* @description Verifies a Puzzle Captcha solution for a given user and dapp
|
|
48
|
+
*
|
|
49
|
+
* @param {string} challenge - the challenge string
|
|
50
|
+
* @param {string} providerChallengeSignature - proof that the Provider provided the challenge
|
|
51
|
+
* @param {number} finalX - the final X coordinate of the puzzle
|
|
52
|
+
* @param {number} finalY - the final Y coordinate of the puzzle
|
|
53
|
+
* @param {PuzzleEvent[]} puzzleEvents - the puzzle event trail
|
|
54
|
+
* @param {number} timeout - the time in milliseconds since the Provider was selected to provide the captcha
|
|
55
|
+
* @param {string} userTimestampSignature
|
|
56
|
+
* @param ipAddress
|
|
57
|
+
* @param headers
|
|
58
|
+
* @param behavioralData
|
|
59
|
+
*/
|
|
60
|
+
async verifyPuzzleCaptchaSolution(challenge, providerChallengeSignature, finalX, finalY, puzzleEvents, timeout, userTimestampSignature, ipAddress, headers, behavioralData, salt, simdReadings, clientMetaData) {
|
|
61
|
+
require_powTasksUtils.checkPowSignature(challenge, providerChallengeSignature, this.pair.address, _prosopo_types.ApiParams.challenge);
|
|
62
|
+
const challengeSplit = challenge.split(this.POW_SEPARATOR);
|
|
63
|
+
const timestamp = Number.parseInt((0, _prosopo_util.at)(challengeSplit, 0));
|
|
64
|
+
const userAccount = (0, _prosopo_util.at)(challengeSplit, 1);
|
|
65
|
+
require_powTasksUtils.checkPowSignature(timestamp.toString(), userTimestampSignature, userAccount, _prosopo_types.ApiParams.timestamp);
|
|
66
|
+
const challengeRecord = await this.db.getPuzzleCaptchaRecordByChallenge(challenge);
|
|
67
|
+
if (!challengeRecord) {
|
|
68
|
+
this.logger.debug(() => ({ msg: `No record of this challenge: ${challenge}` }));
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
let coords;
|
|
72
|
+
let saltDecodeError;
|
|
73
|
+
if (salt) try {
|
|
74
|
+
const extractedData = (0, _prosopo_util.extractData)(salt);
|
|
75
|
+
if (extractedData.length >= 2) {
|
|
76
|
+
const built = [[[extractedData[0], extractedData[1]]]];
|
|
77
|
+
(0, _prosopo_util.assertCoordsSafe)(built, "coords");
|
|
78
|
+
coords = built;
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
saltDecodeError = error;
|
|
82
|
+
this.logger.warn(() => ({
|
|
83
|
+
msg: "Failed to extract coordinates from salt",
|
|
84
|
+
error,
|
|
85
|
+
salt
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
if (challengeRecord.userSubmitted) {
|
|
89
|
+
this.logger.debug(() => ({ msg: `Challenge already submitted: ${challenge}` }));
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
if (saltDecodeError) {
|
|
93
|
+
const badSaltResult = {
|
|
94
|
+
status: _prosopo_types.CaptchaStatus.disapproved,
|
|
95
|
+
reason: _prosopo_types.ResultReason.CAPTCHA_INVALID_SALT
|
|
96
|
+
};
|
|
97
|
+
await this.db.updatePuzzleCaptchaRecordResult(challenge, badSaltResult, false, true, userTimestampSignature, void 0);
|
|
98
|
+
if (challengeRecord.sessionId) await this.updateSessionRecordWithCache(challengeRecord.sessionId, {
|
|
99
|
+
userSubmitted: true,
|
|
100
|
+
result: badSaltResult
|
|
101
|
+
});
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
if (!(0, _prosopo_util.verifyRecency)(challenge, timeout)) {
|
|
105
|
+
const timeoutResult = {
|
|
106
|
+
status: _prosopo_types.CaptchaStatus.disapproved,
|
|
107
|
+
reason: _prosopo_types.ResultReason.CAPTCHA_INVALID_TIMESTAMP
|
|
108
|
+
};
|
|
109
|
+
await this.db.updatePuzzleCaptchaRecordResult(challenge, timeoutResult, false, true, userTimestampSignature, coords);
|
|
110
|
+
if (challengeRecord.sessionId) await this.updateSessionRecordWithCache(challengeRecord.sessionId, {
|
|
111
|
+
userSubmitted: true,
|
|
112
|
+
result: timeoutResult
|
|
113
|
+
});
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const correct = require_puzzleTasksUtils.validatePuzzleSolution(finalX, finalY, challengeRecord.targetX, challengeRecord.targetY, challengeRecord.tolerance);
|
|
117
|
+
let result = { status: _prosopo_types.CaptchaStatus.approved };
|
|
118
|
+
if (!correct) result = {
|
|
119
|
+
status: _prosopo_types.CaptchaStatus.disapproved,
|
|
120
|
+
reason: _prosopo_types.ResultReason.CAPTCHA_INVALID_SOLUTION
|
|
121
|
+
};
|
|
122
|
+
if (correct && this.usageCounters) {
|
|
123
|
+
const dappAccount = (0, _prosopo_util.at)(challengeSplit, 2);
|
|
124
|
+
this.usageCounters.incrManyAsync(dappAccount, require_usageCounters.buildAllWindowIncrements("solved", _prosopo_types.CaptchaType.puzzle, ipAddress.address, userAccount));
|
|
125
|
+
}
|
|
126
|
+
if (behavioralData) try {
|
|
127
|
+
const decryptKeys = [...await this.getDetectorKeys(), process.env.BOT_DECRYPTION_KEY];
|
|
128
|
+
const decryptedData = await this.decryptBehavioralData(behavioralData, decryptKeys);
|
|
129
|
+
if (decryptedData) {
|
|
130
|
+
const dappAccount = (0, _prosopo_util.at)(challengeSplit, 2);
|
|
131
|
+
this.logger?.info(() => ({
|
|
132
|
+
msg: "Behavioral analysis completed",
|
|
133
|
+
data: {
|
|
134
|
+
userAccount,
|
|
135
|
+
dappAccount,
|
|
136
|
+
challenge,
|
|
137
|
+
mouseEventsCount: decryptedData.collector1?.length || 0,
|
|
138
|
+
touchEventsCount: decryptedData.collector2?.length || 0,
|
|
139
|
+
clickEventsCount: decryptedData.collector3?.length || 0,
|
|
140
|
+
deviceCapability: decryptedData.deviceCapability,
|
|
141
|
+
captchaResult: correct ? "passed" : "failed"
|
|
142
|
+
}
|
|
143
|
+
}));
|
|
144
|
+
const packedData = {
|
|
145
|
+
c1: decryptedData.collector1 || [],
|
|
146
|
+
c2: decryptedData.collector2 || [],
|
|
147
|
+
c3: decryptedData.collector3 || [],
|
|
148
|
+
d: decryptedData.deviceCapability
|
|
149
|
+
};
|
|
150
|
+
await this.db.updatePuzzleCaptchaRecord(challenge, {
|
|
151
|
+
behavioralDataPacked: packedData,
|
|
152
|
+
deviceCapability: decryptedData.deviceCapability,
|
|
153
|
+
puzzleEvents
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
} catch (error) {
|
|
157
|
+
this.logger?.error(() => ({
|
|
158
|
+
msg: "Failed to process behavioral data",
|
|
159
|
+
err: error
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
162
|
+
else await this.db.updatePuzzleCaptchaRecord(challenge, { puzzleEvents });
|
|
163
|
+
if (clientMetaData?.hp) await this.db.updatePuzzleCaptchaRecord(challenge, { clientMetaData: { hp: clientMetaData.hp } });
|
|
164
|
+
await this.db.updatePuzzleCaptchaRecordResult(challenge, result, false, true, userTimestampSignature, coords);
|
|
165
|
+
if (challengeRecord.sessionId) {
|
|
166
|
+
const linkedSessionId = challengeRecord.sessionId;
|
|
167
|
+
await this.updateSessionRecordWithCache(linkedSessionId, {
|
|
168
|
+
userSubmitted: true,
|
|
169
|
+
result
|
|
170
|
+
});
|
|
171
|
+
if (simdReadings) await this.decryptAndAttachSimdReadingsIfAbsent(linkedSessionId, simdReadings, _prosopo_types.SimdReadingsStage.submit);
|
|
172
|
+
}
|
|
173
|
+
return correct;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* @description Verifies a Puzzle Captcha for a given user and dapp. This is called by the server to verify the user's solution
|
|
177
|
+
* and update the record in the database to show that the user has solved the captcha
|
|
178
|
+
*
|
|
179
|
+
* @param {string} dappAccount - the dapp that is requesting the captcha
|
|
180
|
+
* @param {string} challenge - the challenge string
|
|
181
|
+
* @param {number} timeout - the time in milliseconds since the Provider was selected to provide the captcha
|
|
182
|
+
* @param env - provider environment
|
|
183
|
+
* @param ip - optional IP address for validation
|
|
184
|
+
* @param userAccessRulesStorage - storage for querying user access policies
|
|
185
|
+
* @param email
|
|
186
|
+
* @param spamEmailDomainCheckingEnabled
|
|
187
|
+
* @param trafficFilter
|
|
188
|
+
* @param storeMetadata - when true, persists the dapp-server-provided
|
|
189
|
+
* `email` on the captcha record for spam-rate analysis.
|
|
190
|
+
*/
|
|
191
|
+
async serverVerifyPuzzleCaptchaSolution(dappAccount, challenge, timeout, env, ip, userAccessRulesStorage, email, spamEmailDomainCheckingEnabled = false, trafficFilter, storeMetadata = false) {
|
|
192
|
+
const notVerifiedResponse = { verified: false };
|
|
193
|
+
const logger = this.logger.with({
|
|
194
|
+
challenge,
|
|
195
|
+
dappAccount
|
|
196
|
+
});
|
|
197
|
+
const challengeRecord = await this.db.getPuzzleCaptchaRecordByChallenge(challenge);
|
|
198
|
+
if (!challengeRecord) {
|
|
199
|
+
logger.debug(() => ({ msg: `No record of this challenge: ${challenge}` }));
|
|
200
|
+
return notVerifiedResponse;
|
|
201
|
+
}
|
|
202
|
+
if (challengeRecord.result.status !== _prosopo_types.CaptchaStatus.approved) throw new _prosopo_common.ProsopoApiError("CAPTCHA.INVALID_SOLUTION", { context: {
|
|
203
|
+
code: 400,
|
|
204
|
+
failedFuncName: this.serverVerifyPuzzleCaptchaSolution.name,
|
|
205
|
+
challenge
|
|
206
|
+
} });
|
|
207
|
+
if (challengeRecord.serverChecked) return notVerifiedResponse;
|
|
208
|
+
const challengeDappAccount = challengeRecord.dappAccount;
|
|
209
|
+
if (dappAccount !== challengeDappAccount) throw new _prosopo_common.ProsopoEnvError("CAPTCHA.DAPP_USER_SOLUTION_NOT_FOUND", { context: {
|
|
210
|
+
failedFuncName: this.serverVerifyPuzzleCaptchaSolution.name,
|
|
211
|
+
dappAccount,
|
|
212
|
+
challengeDappAccount
|
|
213
|
+
} });
|
|
214
|
+
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, {
|
|
215
|
+
serverChecked: true,
|
|
216
|
+
lastUpdatedTimestamp: /* @__PURE__ */ new Date()
|
|
217
|
+
});
|
|
218
|
+
const submittedAt = challengeRecord.submittedAtTimestamp;
|
|
219
|
+
if ((submittedAt instanceof Date ? Date.now() - submittedAt.getTime() : Number.POSITIVE_INFINITY) > timeout) {
|
|
220
|
+
const disapprovedResult = {
|
|
221
|
+
status: _prosopo_types.CaptchaStatus.disapproved,
|
|
222
|
+
reason: _prosopo_types.ResultReason.TIMESTAMP_TOO_OLD
|
|
223
|
+
};
|
|
224
|
+
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, { result: disapprovedResult });
|
|
225
|
+
if (challengeRecord.sessionId) await this.updateSessionRecordWithCache(challengeRecord.sessionId, {
|
|
226
|
+
serverChecked: true,
|
|
227
|
+
result: disapprovedResult
|
|
228
|
+
});
|
|
229
|
+
return notVerifiedResponse;
|
|
230
|
+
}
|
|
231
|
+
if (userAccessRulesStorage) try {
|
|
232
|
+
const blockPolicy = await this.checkForHardBlock(userAccessRulesStorage, challengeRecord, challengeRecord.userAccount, challengeRecord.headers, challengeRecord.coords, challengeRecord.ipInfo?.isValid ? challengeRecord.ipInfo.countryCode : void 0, challengeRecord.ipInfo?.isValid ? challengeRecord.ipInfo.asnNumber : void 0);
|
|
233
|
+
if (blockPolicy) {
|
|
234
|
+
logger.info(() => ({
|
|
235
|
+
msg: "User blocked by access policy in server puzzle verification",
|
|
236
|
+
data: {
|
|
237
|
+
userAccount: challengeRecord.userAccount,
|
|
238
|
+
policy: blockPolicy
|
|
239
|
+
}
|
|
240
|
+
}));
|
|
241
|
+
const blockedResult = {
|
|
242
|
+
status: _prosopo_types.CaptchaStatus.disapproved,
|
|
243
|
+
reason: _prosopo_types.ResultReason.ACCESS_POLICY_BLOCK
|
|
244
|
+
};
|
|
245
|
+
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, { result: blockedResult });
|
|
246
|
+
if (challengeRecord.sessionId) await this.updateSessionRecordWithCache(challengeRecord.sessionId, {
|
|
247
|
+
serverChecked: true,
|
|
248
|
+
result: blockedResult
|
|
249
|
+
});
|
|
250
|
+
return notVerifiedResponse;
|
|
251
|
+
}
|
|
252
|
+
} catch (error) {
|
|
253
|
+
logger.warn(() => ({
|
|
254
|
+
msg: "Failed to check user access policies in server puzzle verification",
|
|
255
|
+
error
|
|
256
|
+
}));
|
|
257
|
+
}
|
|
258
|
+
if (email && spamEmailDomainCheckingEnabled) try {
|
|
259
|
+
if (await this.checkSpamEmail(email)) {
|
|
260
|
+
const emailDomain = email.split("@")[1] || "unknown";
|
|
261
|
+
logger.info(() => ({
|
|
262
|
+
msg: "Spam email domain detected in server puzzle verification",
|
|
263
|
+
data: { emailDomain }
|
|
264
|
+
}));
|
|
265
|
+
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, { result: {
|
|
266
|
+
status: _prosopo_types.CaptchaStatus.disapproved,
|
|
267
|
+
reason: _prosopo_types.ResultReason.SPAM_EMAIL_DOMAIN
|
|
268
|
+
} });
|
|
269
|
+
return notVerifiedResponse;
|
|
270
|
+
}
|
|
271
|
+
} catch (error) {
|
|
272
|
+
logger.warn(() => ({
|
|
273
|
+
msg: "Failed to check spam email domain in server puzzle verification",
|
|
274
|
+
error
|
|
275
|
+
}));
|
|
276
|
+
}
|
|
277
|
+
const sessionRecord = challengeRecord.sessionId ? await this.db.getSessionRecordBySessionId(challengeRecord.sessionId) : void 0;
|
|
278
|
+
const enrichedDnsEvent = await require_enrichDnsEvent.enrichDnsEvent(sessionRecord?.dnsEvent, env.ipInfoService, ip ?? challengeRecord.ipInfo?.ip);
|
|
279
|
+
{
|
|
280
|
+
const check = await this.resolveTrafficFilterCheck(env, challengeRecord.ipInfo, trafficFilter, ip, enrichedDnsEvent);
|
|
281
|
+
if (check.isBlocked) {
|
|
282
|
+
logger.info(() => ({
|
|
283
|
+
msg: "Traffic filter rejected request in puzzle verification",
|
|
284
|
+
data: {
|
|
285
|
+
ip,
|
|
286
|
+
reason: check.reason,
|
|
287
|
+
dnsPeerIp: enrichedDnsEvent?.peerIp,
|
|
288
|
+
dnsResolverIp: enrichedDnsEvent?.resolverIp,
|
|
289
|
+
dnsPeerAsn: require_enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.peerIpInfo),
|
|
290
|
+
dnsResolverAsn: require_enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.resolverIpInfo),
|
|
291
|
+
dnsPathValid: enrichedDnsEvent?.pathValid
|
|
292
|
+
}
|
|
293
|
+
}));
|
|
294
|
+
const blockedResult = {
|
|
295
|
+
status: _prosopo_types.CaptchaStatus.disapproved,
|
|
296
|
+
reason: check.reason
|
|
297
|
+
};
|
|
298
|
+
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, { result: blockedResult });
|
|
299
|
+
if (challengeRecord.sessionId) await this.updateSessionRecordWithCache(challengeRecord.sessionId, {
|
|
300
|
+
serverChecked: true,
|
|
301
|
+
result: blockedResult
|
|
302
|
+
});
|
|
303
|
+
return notVerifiedResponse;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if (storeMetadata && email) await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, { metadata: { email } });
|
|
307
|
+
if (ip) {
|
|
308
|
+
const challengeIpAddress = require_compositeIpAddress.getIpAddressFromComposite(challengeRecord.ipAddress);
|
|
309
|
+
const ipValidationRules = (await this.db.getClientRecord(dappAccount))?.settings?.ipValidationRules;
|
|
310
|
+
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, { providedIp: require_compositeIpAddress.getCompositeIpAddress(ip) });
|
|
311
|
+
if (ipValidationRules?.enabled === true) {
|
|
312
|
+
const ipValidation = await require_util.deepValidateIpAddress(ip, challengeIpAddress, logger, env.ipInfoService, ipValidationRules, enrichedDnsEvent?.peerIp);
|
|
313
|
+
if (!ipValidation.isValid) {
|
|
314
|
+
logger.error(() => ({
|
|
315
|
+
msg: "IP validation failed for puzzle captcha",
|
|
316
|
+
data: {
|
|
317
|
+
ip,
|
|
318
|
+
challengeIp: challengeIpAddress.address,
|
|
319
|
+
error: ipValidation.errorMessage,
|
|
320
|
+
distanceKm: ipValidation.distanceKm
|
|
321
|
+
}
|
|
322
|
+
}));
|
|
323
|
+
const ipFailResult = {
|
|
324
|
+
status: _prosopo_types.CaptchaStatus.disapproved,
|
|
325
|
+
reason: _prosopo_types.ResultReason.FAILED_IP_VALIDATION
|
|
326
|
+
};
|
|
327
|
+
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, { result: ipFailResult });
|
|
328
|
+
if (challengeRecord.sessionId) await this.updateSessionRecordWithCache(challengeRecord.sessionId, {
|
|
329
|
+
serverChecked: true,
|
|
330
|
+
result: ipFailResult
|
|
331
|
+
});
|
|
332
|
+
return notVerifiedResponse;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
let score;
|
|
337
|
+
if (sessionRecord) {
|
|
338
|
+
const dnsAsymmetry = require_enrichDnsEvent.computeDnsAsymmetry(enrichedDnsEvent, challengeRecord.ipInfo, trafficFilter);
|
|
339
|
+
if (dnsAsymmetry > 0) sessionRecord.scoreComponents = {
|
|
340
|
+
...sessionRecord.scoreComponents,
|
|
341
|
+
dnsAsymmetry
|
|
342
|
+
};
|
|
343
|
+
score = require_frictionlessTasksUtils.computeFrictionlessScore(sessionRecord?.scoreComponents);
|
|
344
|
+
logger.info(() => ({ data: {
|
|
345
|
+
scoreComponents: { ...sessionRecord?.scoreComponents || {} },
|
|
346
|
+
score,
|
|
347
|
+
dnsPeerAsn: require_enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.peerIpInfo),
|
|
348
|
+
dnsResolverAsn: require_enrichDnsEvent.getIpInfoAsn(enrichedDnsEvent?.resolverIpInfo)
|
|
349
|
+
} }));
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
352
|
+
const decisionInput = {
|
|
353
|
+
userAccount: challengeRecord.userAccount,
|
|
354
|
+
dappAccount: challengeRecord.dappAccount,
|
|
355
|
+
captchaResult: "passed",
|
|
356
|
+
headers: challengeRecord.headers,
|
|
357
|
+
captchaType: _prosopo_types.CaptchaType.puzzle,
|
|
358
|
+
behavioralDataPacked: challengeRecord.behavioralDataPacked,
|
|
359
|
+
deviceCapability: challengeRecord.deviceCapability,
|
|
360
|
+
countryCode: challengeRecord.ipInfo?.isValid ? challengeRecord.ipInfo.countryCode : void 0,
|
|
361
|
+
ipInfo: challengeRecord.ipInfo,
|
|
362
|
+
dnsEvent: enrichedDnsEvent,
|
|
363
|
+
score,
|
|
364
|
+
threshold: sessionRecord?.threshold,
|
|
365
|
+
scoreComponents: sessionRecord?.scoreComponents,
|
|
366
|
+
decryptedHeadHash: sessionRecord?.decryptedHeadHash,
|
|
367
|
+
userSitekeyIpHash: sessionRecord?.userSitekeyIpHash,
|
|
368
|
+
simdReadings: sessionRecord?.simdReadings,
|
|
369
|
+
frictionlessReason: sessionRecord?.reason,
|
|
370
|
+
ruleType: sessionRecord?.ruleType,
|
|
371
|
+
webView: sessionRecord?.webView,
|
|
372
|
+
iFrame: sessionRecord?.iFrame,
|
|
373
|
+
coords: challengeRecord.coords,
|
|
374
|
+
puzzleEvents: challengeRecord.puzzleEvents
|
|
375
|
+
};
|
|
376
|
+
const decision = await this.decisionMachineRunner.decide(decisionInput, logger);
|
|
377
|
+
if (decision.decision === _prosopo_types.DecisionMachineDecision.Deny) {
|
|
378
|
+
logger.info(() => ({
|
|
379
|
+
msg: "Decision machine denied puzzle captcha in server verification",
|
|
380
|
+
data: {
|
|
381
|
+
userAccount: challengeRecord.userAccount,
|
|
382
|
+
reason: decision.reason,
|
|
383
|
+
score: decision.score,
|
|
384
|
+
tags: decision.tags
|
|
385
|
+
}
|
|
386
|
+
}));
|
|
387
|
+
const dmResult = {
|
|
388
|
+
status: _prosopo_types.CaptchaStatus.disapproved,
|
|
389
|
+
reason: decision.reason || _prosopo_types.ResultReason.CAPTCHA_DECISION_MACHINE_DENIED
|
|
390
|
+
};
|
|
391
|
+
await this.db.updatePuzzleCaptchaRecord(challengeRecord.challenge, { result: dmResult });
|
|
392
|
+
if (challengeRecord.sessionId) await this.updateSessionRecordWithCache(challengeRecord.sessionId, {
|
|
393
|
+
serverChecked: true,
|
|
394
|
+
result: dmResult
|
|
395
|
+
});
|
|
396
|
+
return notVerifiedResponse;
|
|
397
|
+
}
|
|
398
|
+
logger.debug(() => ({
|
|
399
|
+
msg: "Decision machine allowed puzzle captcha",
|
|
400
|
+
data: {
|
|
401
|
+
reason: decision.reason,
|
|
402
|
+
score: decision.score,
|
|
403
|
+
tags: decision.tags
|
|
404
|
+
}
|
|
405
|
+
}));
|
|
406
|
+
} catch (error) {
|
|
407
|
+
logger.error(() => ({
|
|
408
|
+
msg: "Failed to run decision machine in server puzzle verification",
|
|
409
|
+
err: error
|
|
410
|
+
}));
|
|
411
|
+
}
|
|
412
|
+
if (challengeRecord.sessionId) await this.updateSessionRecordWithCache(challengeRecord.sessionId, {
|
|
413
|
+
serverChecked: true,
|
|
414
|
+
result: { status: _prosopo_types.CaptchaStatus.approved }
|
|
415
|
+
});
|
|
416
|
+
return {
|
|
417
|
+
verified: true,
|
|
418
|
+
...score ? { score } : {}
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
//#endregion
|
|
592
423
|
exports.PuzzleCaptchaManager = PuzzleCaptchaManager;
|