@prosopo/provider 5.15.0 → 5.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +50 -32
  2. package/.turbo/turbo-build$colon$tsc.log +36 -30
  3. package/.turbo/turbo-build.log +51 -33
  4. package/CHANGELOG.md +65 -0
  5. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.d.ts +4 -0
  6. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.d.ts.map +1 -1
  7. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.js +63 -3
  8. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.js.map +1 -1
  9. package/dist/api/blacklistRequestInspector.js +2 -2
  10. package/dist/api/captcha/getAudioCaptchaChallenge.d.ts +5 -0
  11. package/dist/api/captcha/getAudioCaptchaChallenge.d.ts.map +1 -0
  12. package/dist/api/captcha/getAudioCaptchaChallenge.js +37 -0
  13. package/dist/api/captcha/getAudioCaptchaChallenge.js.map +1 -0
  14. package/dist/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.js +1 -1
  15. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.d.ts.map +1 -1
  16. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js +11 -7
  17. package/dist/api/captcha/getFrictionlessCaptchaChallenge/handler.js.map +1 -1
  18. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.d.ts.map +1 -1
  19. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js +1 -0
  20. package/dist/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.js.map +1 -1
  21. package/dist/api/captcha/getIconOrderCaptchaChallenge.d.ts +5 -0
  22. package/dist/api/captcha/getIconOrderCaptchaChallenge.d.ts.map +1 -0
  23. package/dist/api/captcha/getIconOrderCaptchaChallenge.js +37 -0
  24. package/dist/api/captcha/getIconOrderCaptchaChallenge.js.map +1 -0
  25. package/dist/api/captcha/getImageCaptchaChallenge.js +2 -2
  26. package/dist/api/captcha/getPoWCaptchaChallenge.js +4 -4
  27. package/dist/api/captcha/getPuzzleCaptchaChallenge.d.ts +1 -3
  28. package/dist/api/captcha/getPuzzleCaptchaChallenge.d.ts.map +1 -1
  29. package/dist/api/captcha/getPuzzleCaptchaChallenge.js +52 -169
  30. package/dist/api/captcha/getPuzzleCaptchaChallenge.js.map +1 -1
  31. package/dist/api/captcha/interactiveCaptchaChallenge.d.ts +42 -0
  32. package/dist/api/captcha/interactiveCaptchaChallenge.d.ts.map +1 -0
  33. package/dist/api/captcha/interactiveCaptchaChallenge.js +154 -0
  34. package/dist/api/captcha/interactiveCaptchaChallenge.js.map +1 -0
  35. package/dist/api/captcha/interactiveCaptchaSolution.d.ts +14 -0
  36. package/dist/api/captcha/interactiveCaptchaSolution.d.ts.map +1 -0
  37. package/dist/api/captcha/interactiveCaptchaSolution.js +77 -0
  38. package/dist/api/captcha/interactiveCaptchaSolution.js.map +1 -0
  39. package/dist/api/captcha/maintenanceModeResponses.d.ts +4 -2
  40. package/dist/api/captcha/maintenanceModeResponses.d.ts.map +1 -1
  41. package/dist/api/captcha/maintenanceModeResponses.js +28 -1
  42. package/dist/api/captcha/maintenanceModeResponses.js.map +1 -1
  43. package/dist/api/captcha/submitAudioCaptchaSolution.d.ts +4 -0
  44. package/dist/api/captcha/submitAudioCaptchaSolution.d.ts.map +1 -0
  45. package/dist/api/captcha/submitAudioCaptchaSolution.js +11 -0
  46. package/dist/api/captcha/submitAudioCaptchaSolution.js.map +1 -0
  47. package/dist/api/captcha/submitIconOrderCaptchaSolution.d.ts +4 -0
  48. package/dist/api/captcha/submitIconOrderCaptchaSolution.d.ts.map +1 -0
  49. package/dist/api/captcha/submitIconOrderCaptchaSolution.js +11 -0
  50. package/dist/api/captcha/submitIconOrderCaptchaSolution.js.map +1 -0
  51. package/dist/api/captcha/submitPoWCaptchaSolution.js +2 -2
  52. package/dist/api/captcha/submitPuzzleCaptchaSolution.d.ts +1 -3
  53. package/dist/api/captcha/submitPuzzleCaptchaSolution.d.ts.map +1 -1
  54. package/dist/api/captcha/submitPuzzleCaptchaSolution.js +6 -73
  55. package/dist/api/captcha/submitPuzzleCaptchaSolution.js.map +1 -1
  56. package/dist/api/captcha/trafficFilterRequestTime.d.ts +4 -1
  57. package/dist/api/captcha/trafficFilterRequestTime.d.ts.map +1 -1
  58. package/dist/api/captcha/trafficFilterRequestTime.js +3 -0
  59. package/dist/api/captcha/trafficFilterRequestTime.js.map +1 -1
  60. package/dist/api/captcha.d.ts.map +1 -1
  61. package/dist/api/captcha.js +8 -0
  62. package/dist/api/captcha.js.map +1 -1
  63. package/dist/api/domainMiddleware.js +1 -1
  64. package/dist/api/ja4Middleware.js +1 -1
  65. package/dist/api/startProviderApi.js +1 -1
  66. package/dist/api/verify.d.ts.map +1 -1
  67. package/dist/api/verify.js +153 -96
  68. package/dist/api/verify.js.map +1 -1
  69. package/dist/cjs/api/admin/apiToggleMaintenanceModeEndpoint.cjs +65 -2
  70. package/dist/cjs/api/blacklistRequestInspector.cjs +2 -2
  71. package/dist/cjs/api/captcha/getAudioCaptchaChallenge.cjs +37 -0
  72. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/decisionMachine.cjs +1 -1
  73. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/handler.cjs +11 -7
  74. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.cjs +1 -0
  75. package/dist/cjs/api/captcha/getIconOrderCaptchaChallenge.cjs +37 -0
  76. package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +2 -2
  77. package/dist/cjs/api/captcha/getPoWCaptchaChallenge.cjs +4 -4
  78. package/dist/cjs/api/captcha/getPuzzleCaptchaChallenge.cjs +51 -168
  79. package/dist/cjs/api/captcha/interactiveCaptchaChallenge.cjs +154 -0
  80. package/dist/cjs/api/captcha/interactiveCaptchaSolution.cjs +77 -0
  81. package/dist/cjs/api/captcha/maintenanceModeResponses.cjs +29 -0
  82. package/dist/cjs/api/captcha/submitAudioCaptchaSolution.cjs +11 -0
  83. package/dist/cjs/api/captcha/submitIconOrderCaptchaSolution.cjs +11 -0
  84. package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +2 -2
  85. package/dist/cjs/api/captcha/submitPuzzleCaptchaSolution.cjs +6 -73
  86. package/dist/cjs/api/captcha/trafficFilterRequestTime.cjs +3 -0
  87. package/dist/cjs/api/captcha.cjs +8 -0
  88. package/dist/cjs/api/domainMiddleware.cjs +1 -1
  89. package/dist/cjs/api/ja4Middleware.cjs +1 -1
  90. package/dist/cjs/api/startProviderApi.cjs +1 -1
  91. package/dist/cjs/api/verify.cjs +152 -95
  92. package/dist/cjs/index.cjs +1 -1
  93. package/dist/cjs/tasks/audio/audioBuffer.cjs +72 -0
  94. package/dist/cjs/tasks/audio/audioRenderer.cjs +32 -0
  95. package/dist/cjs/tasks/audioAlternative.cjs +23 -0
  96. package/dist/cjs/tasks/audioCaptcha/audioTasks.cjs +65 -0
  97. package/dist/cjs/tasks/audioCaptcha/audioTasksUtils.cjs +19 -0
  98. package/dist/cjs/tasks/captchaManager.cjs +14 -2
  99. package/dist/cjs/tasks/captchaTypeSelection.cjs +10 -3
  100. package/dist/cjs/tasks/client/clientTasks.cjs +2 -2
  101. package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +26 -6
  102. package/dist/cjs/tasks/iconOrder/iconOrderRenderer.cjs +42 -0
  103. package/dist/cjs/tasks/iconOrderCaptcha/iconOrderTasks.cjs +69 -0
  104. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +8 -8
  105. package/dist/cjs/tasks/interactiveCaptcha/interactiveCaptchaManager.cjs +423 -0
  106. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +8 -8
  107. package/dist/cjs/tasks/powCaptcha/powTasksUtils.cjs +1 -1
  108. package/dist/cjs/tasks/puzzleCaptcha/puzzleTasks.cjs +40 -486
  109. package/dist/cjs/tasks/spam/checkTrafficFilter.cjs +18 -1
  110. package/dist/cjs/tasks/tasks.cjs +6 -0
  111. package/dist/cjs/util.cjs +1 -1
  112. package/dist/index.js +2 -2
  113. package/dist/tasks/audio/audioBuffer.d.ts +23 -0
  114. package/dist/tasks/audio/audioBuffer.d.ts.map +1 -0
  115. package/dist/tasks/audio/audioBuffer.js +70 -0
  116. package/dist/tasks/audio/audioBuffer.js.map +1 -0
  117. package/dist/tasks/audio/audioRenderer.d.ts +11 -0
  118. package/dist/tasks/audio/audioRenderer.d.ts.map +1 -0
  119. package/dist/tasks/audio/audioRenderer.js +31 -0
  120. package/dist/tasks/audio/audioRenderer.js.map +1 -0
  121. package/dist/tasks/audioAlternative.d.ts +8 -0
  122. package/dist/tasks/audioAlternative.d.ts.map +1 -0
  123. package/dist/tasks/audioAlternative.js +20 -0
  124. package/dist/tasks/audioAlternative.js.map +1 -0
  125. package/dist/tasks/audioCaptcha/audioTasks.d.ts +19 -0
  126. package/dist/tasks/audioCaptcha/audioTasks.d.ts.map +1 -0
  127. package/dist/tasks/audioCaptcha/audioTasks.js +65 -0
  128. package/dist/tasks/audioCaptcha/audioTasks.js.map +1 -0
  129. package/dist/tasks/audioCaptcha/audioTasksUtils.d.ts +3 -0
  130. package/dist/tasks/audioCaptcha/audioTasksUtils.d.ts.map +1 -0
  131. package/dist/tasks/audioCaptcha/audioTasksUtils.js +18 -0
  132. package/dist/tasks/audioCaptcha/audioTasksUtils.js.map +1 -0
  133. package/dist/tasks/captchaManager.d.ts +9 -3
  134. package/dist/tasks/captchaManager.d.ts.map +1 -1
  135. package/dist/tasks/captchaManager.js +15 -3
  136. package/dist/tasks/captchaManager.js.map +1 -1
  137. package/dist/tasks/captchaTypeSelection.d.ts +1 -1
  138. package/dist/tasks/captchaTypeSelection.d.ts.map +1 -1
  139. package/dist/tasks/captchaTypeSelection.js +11 -4
  140. package/dist/tasks/captchaTypeSelection.js.map +1 -1
  141. package/dist/tasks/client/clientTasks.js +2 -2
  142. package/dist/tasks/frictionless/frictionlessTasks.d.ts +3 -0
  143. package/dist/tasks/frictionless/frictionlessTasks.d.ts.map +1 -1
  144. package/dist/tasks/frictionless/frictionlessTasks.js +26 -6
  145. package/dist/tasks/frictionless/frictionlessTasks.js.map +1 -1
  146. package/dist/tasks/iconOrder/iconOrderRenderer.d.ts +12 -0
  147. package/dist/tasks/iconOrder/iconOrderRenderer.d.ts.map +1 -0
  148. package/dist/tasks/iconOrder/iconOrderRenderer.js +40 -0
  149. package/dist/tasks/iconOrder/iconOrderRenderer.js.map +1 -0
  150. package/dist/tasks/iconOrderCaptcha/iconOrderTasks.d.ts +22 -0
  151. package/dist/tasks/iconOrderCaptcha/iconOrderTasks.d.ts.map +1 -0
  152. package/dist/tasks/iconOrderCaptcha/iconOrderTasks.js +69 -0
  153. package/dist/tasks/iconOrderCaptcha/iconOrderTasks.js.map +1 -0
  154. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +8 -8
  155. package/dist/tasks/interactiveCaptcha/interactiveCaptchaManager.d.ts +52 -0
  156. package/dist/tasks/interactiveCaptcha/interactiveCaptchaManager.d.ts.map +1 -0
  157. package/dist/tasks/interactiveCaptcha/interactiveCaptchaManager.js +423 -0
  158. package/dist/tasks/interactiveCaptcha/interactiveCaptchaManager.js.map +1 -0
  159. package/dist/tasks/powCaptcha/powTasks.js +8 -8
  160. package/dist/tasks/powCaptcha/powTasksUtils.js +1 -1
  161. package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts +14 -16
  162. package/dist/tasks/puzzleCaptcha/puzzleTasks.d.ts.map +1 -1
  163. package/dist/tasks/puzzleCaptcha/puzzleTasks.js +41 -487
  164. package/dist/tasks/puzzleCaptcha/puzzleTasks.js.map +1 -1
  165. package/dist/tasks/spam/checkTrafficFilter.d.ts +4 -1
  166. package/dist/tasks/spam/checkTrafficFilter.d.ts.map +1 -1
  167. package/dist/tasks/spam/checkTrafficFilter.js +18 -1
  168. package/dist/tasks/spam/checkTrafficFilter.js.map +1 -1
  169. package/dist/tasks/tasks.d.ts +4 -0
  170. package/dist/tasks/tasks.d.ts.map +1 -1
  171. package/dist/tasks/tasks.js +6 -0
  172. package/dist/tasks/tasks.js.map +1 -1
  173. package/dist/tests/integration/api/admin/apiRegisterSiteKeyEndpoint.integration.test.js +7 -3
  174. package/dist/tests/integration/api/admin/apiRegisterSiteKeyEndpoint.integration.test.js.map +1 -1
  175. package/dist/tests/integration/clientSettingsPersistence.integration.test.js +43 -3
  176. package/dist/tests/integration/clientSettingsPersistence.integration.test.js.map +1 -1
  177. package/dist/tests/unit/api/admin/apiRegisterSiteKeyEndpoint.unit.test.js +4 -2
  178. package/dist/tests/unit/api/admin/apiRegisterSiteKeyEndpoint.unit.test.js.map +1 -1
  179. package/dist/tests/unit/api/admin/apiToggleMaintenanceModeEndpoint.unit.test.js +76 -1
  180. package/dist/tests/unit/api/admin/apiToggleMaintenanceModeEndpoint.unit.test.js.map +1 -1
  181. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/constants.unit.test.js +27 -8
  182. package/dist/tests/unit/api/captcha/getFrictionlessCaptchaChallenge/constants.unit.test.js.map +1 -1
  183. package/dist/tests/unit/api/captcha/maintenanceModeShortCircuit.unit.test.js +20 -0
  184. package/dist/tests/unit/api/captcha/maintenanceModeShortCircuit.unit.test.js.map +1 -1
  185. package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js +28 -2
  186. package/dist/tests/unit/api/getFrictionlessCaptchaChallenge.unit.test.js.map +1 -1
  187. package/dist/tests/unit/tasks/audio/audioBuffer.unit.test.d.ts +2 -0
  188. package/dist/tests/unit/tasks/audio/audioBuffer.unit.test.d.ts.map +1 -0
  189. package/dist/tests/unit/tasks/audio/audioBuffer.unit.test.js +105 -0
  190. package/dist/tests/unit/tasks/audio/audioBuffer.unit.test.js.map +1 -0
  191. package/dist/tests/unit/tasks/audioAlternative.unit.test.d.ts +2 -0
  192. package/dist/tests/unit/tasks/audioAlternative.unit.test.d.ts.map +1 -0
  193. package/dist/tests/unit/tasks/audioAlternative.unit.test.js +76 -0
  194. package/dist/tests/unit/tasks/audioAlternative.unit.test.js.map +1 -0
  195. package/dist/tests/unit/tasks/audioCaptcha/audioTasks.unit.test.d.ts +2 -0
  196. package/dist/tests/unit/tasks/audioCaptcha/audioTasks.unit.test.d.ts.map +1 -0
  197. package/dist/tests/unit/tasks/audioCaptcha/audioTasks.unit.test.js +259 -0
  198. package/dist/tests/unit/tasks/audioCaptcha/audioTasks.unit.test.js.map +1 -0
  199. package/dist/tests/unit/tasks/audioCaptcha/audioTasksUtils.unit.test.d.ts +2 -0
  200. package/dist/tests/unit/tasks/audioCaptcha/audioTasksUtils.unit.test.d.ts.map +1 -0
  201. package/dist/tests/unit/tasks/audioCaptcha/audioTasksUtils.unit.test.js +52 -0
  202. package/dist/tests/unit/tasks/audioCaptcha/audioTasksUtils.unit.test.js.map +1 -0
  203. package/dist/tests/unit/tasks/captchaManager.unit.test.js +120 -2
  204. package/dist/tests/unit/tasks/captchaManager.unit.test.js.map +1 -1
  205. package/dist/tests/unit/tasks/captchaTypeSelection.unit.test.js +48 -5
  206. package/dist/tests/unit/tasks/captchaTypeSelection.unit.test.js.map +1 -1
  207. package/dist/tests/unit/tasks/frictionless/allowedCaptchaTypes.unit.test.js +29 -0
  208. package/dist/tests/unit/tasks/frictionless/allowedCaptchaTypes.unit.test.js.map +1 -1
  209. package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.js +31 -0
  210. package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.js.map +1 -1
  211. package/dist/tests/unit/tasks/frictionless/refreshSwitch.unit.test.js +1 -1
  212. package/dist/tests/unit/tasks/frictionless/refreshSwitch.unit.test.js.map +1 -1
  213. package/dist/tests/unit/tasks/frictionless/routerPuzzleOverrides.unit.test.js +28 -0
  214. package/dist/tests/unit/tasks/frictionless/routerPuzzleOverrides.unit.test.js.map +1 -1
  215. package/dist/tests/unit/tasks/iconOrder/iconOrderRenderer.unit.test.d.ts +2 -0
  216. package/dist/tests/unit/tasks/iconOrder/iconOrderRenderer.unit.test.d.ts.map +1 -0
  217. package/dist/tests/unit/tasks/iconOrder/iconOrderRenderer.unit.test.js +60 -0
  218. package/dist/tests/unit/tasks/iconOrder/iconOrderRenderer.unit.test.js.map +1 -0
  219. package/dist/tests/unit/tasks/iconOrderCaptcha/iconOrderTasks.unit.test.d.ts +2 -0
  220. package/dist/tests/unit/tasks/iconOrderCaptcha/iconOrderTasks.unit.test.d.ts.map +1 -0
  221. package/dist/tests/unit/tasks/iconOrderCaptcha/iconOrderTasks.unit.test.js +225 -0
  222. package/dist/tests/unit/tasks/iconOrderCaptcha/iconOrderTasks.unit.test.js.map +1 -0
  223. package/dist/util.js +1 -1
  224. package/package.json +19 -17
@@ -2,10 +2,14 @@ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
2
  const require_tarpitPadding = require("../utils/tarpitPadding.cjs");
3
3
  const require_assignDetectorBundle = require("./captcha/assignDetectorBundle.cjs");
4
4
  const require_checkSpamEmail = require("./captcha/checkSpamEmail.cjs");
5
+ const require_getAudioCaptchaChallenge = require("./captcha/getAudioCaptchaChallenge.cjs");
5
6
  const require_handler = require("./captcha/getFrictionlessCaptchaChallenge/handler.cjs");
7
+ const require_getIconOrderCaptchaChallenge = require("./captcha/getIconOrderCaptchaChallenge.cjs");
6
8
  const require_getImageCaptchaChallenge = require("./captcha/getImageCaptchaChallenge.cjs");
7
9
  const require_getPoWCaptchaChallenge = require("./captcha/getPoWCaptchaChallenge.cjs");
8
10
  const require_getPuzzleCaptchaChallenge = require("./captcha/getPuzzleCaptchaChallenge.cjs");
11
+ const require_submitAudioCaptchaSolution = require("./captcha/submitAudioCaptchaSolution.cjs");
12
+ const require_submitIconOrderCaptchaSolution = require("./captcha/submitIconOrderCaptchaSolution.cjs");
9
13
  const require_submitImageCaptchaSolution = require("./captcha/submitImageCaptchaSolution.cjs");
10
14
  const require_submitPoWCaptchaSolution = require("./captcha/submitPoWCaptchaSolution.cjs");
11
15
  const require_submitPuzzleCaptchaSolution = require("./captcha/submitPuzzleCaptchaSolution.cjs");
@@ -80,6 +84,10 @@ function prosopoRouter(env) {
80
84
  * Verifies a user's Puzzle solution as being approved or not
81
85
  */
82
86
  router.post(_prosopo_types.ClientApiPaths.SubmitPuzzleCaptchaSolution, asyncHandler(require_submitPuzzleCaptchaSolution.default(env)));
87
+ router.post(_prosopo_types.ClientApiPaths.GetAudioCaptchaChallenge, asyncHandler(require_getAudioCaptchaChallenge.default(env, userAccessRulesStorage)));
88
+ router.post(_prosopo_types.ClientApiPaths.SubmitAudioCaptchaSolution, asyncHandler(require_submitAudioCaptchaSolution.default(env)));
89
+ router.post(_prosopo_types.ClientApiPaths.GetIconOrderCaptchaChallenge, asyncHandler(require_getIconOrderCaptchaChallenge.default(env, userAccessRulesStorage)));
90
+ router.post(_prosopo_types.ClientApiPaths.SubmitIconOrderCaptchaSolution, asyncHandler(require_submitIconOrderCaptchaSolution.default(env)));
83
91
  /**
84
92
  * Checks if an email domain is spam
85
93
  */
@@ -4,9 +4,9 @@ const require_apiToggleMaintenanceModeEndpoint = require("./admin/apiToggleMaint
4
4
  const require_testSiteKey = require("./testSiteKey.cjs");
5
5
  let _prosopo_common = require("@prosopo/common");
6
6
  let _prosopo_util = require("@prosopo/util");
7
+ let _prosopo_api_express_router = require("@prosopo/api-express-router");
7
8
  let _prosopo_util_crypto = require("@prosopo/util-crypto");
8
9
  let zod = require("zod");
9
- let _prosopo_api_express_router = require("@prosopo/api-express-router");
10
10
  //#region src/api/domainMiddleware.ts
11
11
  var domainMiddleware = (env) => {
12
12
  let cachedTasks;
@@ -1,7 +1,7 @@
1
1
  const require_ja4 = require("./ja4.cjs");
2
2
  let _prosopo_logger = require("@prosopo/logger");
3
- let _prosopo_util_crypto = require("@prosopo/util-crypto");
4
3
  let _prosopo_api_express_router = require("@prosopo/api-express-router");
4
+ let _prosopo_util_crypto = require("@prosopo/util-crypto");
5
5
  //#region src/api/ja4Middleware.ts
6
6
  var DEFAULT_JA4 = "ja4";
7
7
  var getJA4 = async (headers, logger) => {
@@ -1,6 +1,6 @@
1
1
  const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
2
- const require_metrics = require("./metrics.cjs");
3
2
  const require_rawTlsSignalsMiddleware = require("./rawTlsSignalsMiddleware.cjs");
3
+ const require_metrics = require("./metrics.cjs");
4
4
  const require_blacklistRequestInspector = require("./blacklistRequestInspector.cjs");
5
5
  const require_bundlePool = require("../tasks/detection/bundlePool.cjs");
6
6
  const require_block = require("./block.cjs");
@@ -3,13 +3,13 @@ const require_metrics = require("./metrics.cjs");
3
3
  const require_tasks = require("../tasks/tasks.cjs");
4
4
  const require_apiToggleMaintenanceModeEndpoint = require("./admin/apiToggleMaintenanceModeEndpoint.cjs");
5
5
  const require_testSiteKey = require("./testSiteKey.cjs");
6
- const require_maintenanceModeResponses = require("./captcha/maintenanceModeResponses.cjs");
7
6
  const require_requestBodySummary = require("./requestBodySummary.cjs");
7
+ const require_maintenanceModeResponses = require("./captcha/maintenanceModeResponses.cjs");
8
8
  const require_forwardVerify = require("./forwardVerify.cjs");
9
9
  let _prosopo_common = require("@prosopo/common");
10
10
  let _prosopo_types = require("@prosopo/types");
11
- let _prosopo_util_crypto = require("@prosopo/util-crypto");
12
11
  let _prosopo_api_express_router = require("@prosopo/api-express-router");
12
+ let _prosopo_util_crypto = require("@prosopo/util-crypto");
13
13
  let express = require("express");
14
14
  express = require_runtime.__toESM(express, 1);
15
15
  let _prosopo_api = require("@prosopo/api");
@@ -28,7 +28,9 @@ var deriveVerifySource = (body) => {
28
28
  var VERIFY_PATH_TYPE = {
29
29
  [_prosopo_types.ClientApiPaths.VerifyImageCaptchaSolutionDapp]: _prosopo_types.CaptchaType.image,
30
30
  [_prosopo_types.ClientApiPaths.VerifyPowCaptchaSolution]: _prosopo_types.CaptchaType.pow,
31
- [_prosopo_types.ClientApiPaths.VerifyPuzzleCaptchaSolution]: _prosopo_types.CaptchaType.puzzle
31
+ [_prosopo_types.ClientApiPaths.VerifyPuzzleCaptchaSolution]: _prosopo_types.CaptchaType.puzzle,
32
+ [_prosopo_types.ClientApiPaths.VerifyAudioCaptchaSolution]: _prosopo_types.CaptchaType.audio,
33
+ [_prosopo_types.ClientApiPaths.VerifyIconOrderCaptchaSolution]: _prosopo_types.CaptchaType.iconOrder
32
34
  };
33
35
  var decodeTokenOr400 = (token, i18n, logger, next) => {
34
36
  try {
@@ -61,6 +63,105 @@ var dappSignatureError = (signature, message, pair, req) => {
61
63
  }
62
64
  };
63
65
  /**
66
+ * Verifies a dapp's token for an interactive captcha type as approved or not.
67
+ * The body carries the token, the dapp's signature over it, and optional
68
+ * `ip`, `email` and `clientSessionId`.
69
+ */
70
+ var interactiveVerifyHandler = ({ env, userAccessRulesStorage, path, label, handlerName, manager }) => async (req, res, next) => {
71
+ if (require_apiToggleMaintenanceModeEndpoint.getMaintenanceMode()) {
72
+ req.logger.info(() => ({ msg: `Maintenance mode active - returning verified for ${label} captcha verification` }));
73
+ const verificationResponse = require_maintenanceModeResponses.buildMaintenanceVerificationResponse(req.i18n.t);
74
+ return res.json(verificationResponse);
75
+ }
76
+ let parsed;
77
+ try {
78
+ parsed = _prosopo_types.ServerPuzzleCaptchaVerifyRequestBody.parse(req.body);
79
+ } catch (err) {
80
+ return next(new _prosopo_common.ProsopoApiError("CAPTCHA.PARSE_ERROR", {
81
+ context: {
82
+ code: 400,
83
+ error: err,
84
+ body: require_requestBodySummary.summariseRequestBody(req)
85
+ },
86
+ i18n: req.i18n,
87
+ logger: req.logger
88
+ }));
89
+ }
90
+ try {
91
+ const { token, dappSignature, ip, email, clientSessionId } = parsed;
92
+ const decoded = decodeTokenOr400(token, req.i18n, req.logger, next);
93
+ if (decoded === null) return;
94
+ const { dapp, user, timestamp, challenge, providerUrl } = decoded;
95
+ const testVerdict = require_testSiteKey.resolveTestSiteKeyVerdict(dapp, req.logger);
96
+ if (testVerdict !== null) {
97
+ const verificationResponse = {
98
+ status: "ok",
99
+ verified: testVerdict
100
+ };
101
+ return res.json(verificationResponse);
102
+ }
103
+ const forwarded = await require_forwardVerify.forwardVerifyIfNotIssuer({
104
+ env,
105
+ logger: req.logger,
106
+ path,
107
+ providerUrl,
108
+ dapp,
109
+ user,
110
+ body: parsed,
111
+ alreadyForwarded: req.headers[_prosopo_api.VERIFY_FORWARDED_HEADER] !== void 0
112
+ });
113
+ if (forwarded) return res.json(forwarded);
114
+ const tasks = new require_tasks.Tasks(env, req.logger);
115
+ (0, _prosopo_util_crypto.validateAddress)(dapp, false, 42);
116
+ (0, _prosopo_util_crypto.validateAddress)(user, false, 42);
117
+ const clientRecord = await tasks.db.getClientRecord(dapp);
118
+ if (!clientRecord) return next(new _prosopo_common.ProsopoApiError("API.SITE_KEY_NOT_REGISTERED", {
119
+ context: {
120
+ code: 400,
121
+ siteKey: dapp
122
+ },
123
+ i18n: req.i18n,
124
+ logger: req.logger
125
+ }));
126
+ if (!challenge) {
127
+ const unverifiedResponse = {
128
+ status: req.i18n.t("API.USER_NOT_VERIFIED"),
129
+ [_prosopo_types.ApiParams.verified]: false
130
+ };
131
+ return res.json(unverifiedResponse);
132
+ }
133
+ const dappPair = env.keyring.addFromAddress(dapp);
134
+ const signatureError = dappSignatureError(dappSignature, timestamp.toString(), dappPair, req);
135
+ if (signatureError) return next(signatureError);
136
+ if (require_apiToggleMaintenanceModeEndpoint.isSiteKeyInMaintenanceMode(dapp)) {
137
+ req.logger.info(() => ({
138
+ msg: "Site key in maintenance mode - returning verified",
139
+ data: { siteKey: dapp }
140
+ }));
141
+ const maintenanceResponse = require_maintenanceModeResponses.buildMaintenanceVerificationResponse(req.i18n.t);
142
+ return res.json(maintenanceResponse);
143
+ }
144
+ const captchaManager = manager(tasks);
145
+ const { verified, score, sessionId } = await captchaManager.serverVerifyInteractiveCaptchaSolution(dapp, challenge, clientRecord.settings.verifiedTimeout, env, ip, userAccessRulesStorage, email, clientRecord.settings.spamEmailDomainCheckEnabled, clientRecord.settings.spamFilter, clientRecord.settings.trafficFilter, clientRecord.settings.storeMetadata, clientSessionId);
146
+ const verificationResponse = captchaManager.getVerificationResponse(verified, clientRecord, req.i18n.t, score, void 0, sessionId);
147
+ return res.json(verificationResponse);
148
+ } catch (err) {
149
+ req.logger.error(() => ({
150
+ msg: `Error in ${handlerName}`,
151
+ err,
152
+ data: { body: require_requestBodySummary.summariseRequestBody(req) }
153
+ }));
154
+ return next(new _prosopo_common.ProsopoApiError("API.BAD_REQUEST", {
155
+ context: {
156
+ code: 500,
157
+ error: err
158
+ },
159
+ i18n: req.i18n,
160
+ logger: req.logger
161
+ }));
162
+ }
163
+ };
164
+ /**
64
165
  * Returns a router connected to the database which can interact with the Proposo protocol
65
166
  *
66
167
  * @return {Router} - A middleware router that can interact with the Prosopo protocol
@@ -166,6 +267,14 @@ function prosopoVerifyRouter(env) {
166
267
  const keyPair = env.keyring.addFromAddress(dapp);
167
268
  const signatureError = dappSignatureError(dappSignature, timestamp.toString(), keyPair, req);
168
269
  if (signatureError) return next(signatureError);
270
+ if (require_apiToggleMaintenanceModeEndpoint.isSiteKeyInMaintenanceMode(dapp)) {
271
+ req.logger.info(() => ({
272
+ msg: "Site key in maintenance mode - returning verified",
273
+ data: { siteKey: dapp }
274
+ }));
275
+ const maintenanceResponse = require_maintenanceModeResponses.buildMaintenanceVerificationResponse(req.i18n.t);
276
+ return res.json(maintenanceResponse);
277
+ }
169
278
  const response = await tasks.imgCaptchaManager.verifyImageCaptchaSolution(user, dapp, commitmentId, env, maxVerifiedTime, ip, clientRecord.settings.disallowWebView, userAccessRulesStorage, email, clientRecord.settings.spamEmailDomainCheckEnabled, clientRecord.settings.spamFilter, clientRecord.settings.trafficFilter, clientRecord.settings.storeMetadata, clientSessionId);
170
279
  req.logger.debug(() => ({ data: { response } }));
171
280
  const verificationResponse = tasks.imgCaptchaManager.getVerificationResponse(response[_prosopo_types.ApiParams.verified], clientRecord, req.i18n.t, response[_prosopo_types.ApiParams.score], response[_prosopo_types.ApiParams.commitmentId], response[_prosopo_types.ApiParams.status], response[_prosopo_types.ApiParams.sessionId]);
@@ -260,6 +369,14 @@ function prosopoVerifyRouter(env) {
260
369
  const dappPair = env.keyring.addFromAddress(dapp);
261
370
  const signatureError = dappSignatureError(dappSignature, timestamp.toString(), dappPair, req);
262
371
  if (signatureError) return next(signatureError);
372
+ if (require_apiToggleMaintenanceModeEndpoint.isSiteKeyInMaintenanceMode(dapp)) {
373
+ req.logger.info(() => ({
374
+ msg: "Site key in maintenance mode - returning verified",
375
+ data: { siteKey: dapp }
376
+ }));
377
+ const maintenanceResponse = require_maintenanceModeResponses.buildMaintenanceVerificationResponse(req.i18n.t);
378
+ return res.json(maintenanceResponse);
379
+ }
263
380
  const { verified, score, reason, sessionId } = await tasks.powCaptchaManager.serverVerifyPowCaptchaSolution(dapp, challenge, clientRecord.settings.verifiedTimeout, env, ip, userAccessRulesStorage, email, clientRecord.settings.spamEmailDomainCheckEnabled, clientRecord.settings.spamFilter, clientRecord.settings.trafficFilter, clientRecord.settings.storeMetadata, clientSessionId);
264
381
  const verificationResponse = tasks.powCaptchaManager.getVerificationResponse(verified, clientRecord, req.i18n.t, score, reason, sessionId);
265
382
  return res.json(verificationResponse);
@@ -279,98 +396,30 @@ function prosopoVerifyRouter(env) {
279
396
  }));
280
397
  }
281
398
  });
282
- /**
283
- * Verifies a dapp's puzzle captcha solution as being approved or not
284
- *
285
- * @param {string} token - Token containing dapp, blockNumber and challenge
286
- * @param {string} dappSignature - Signed token
287
- * @param {number} verifiedTimeout - The maximum time in milliseconds to be valid
288
- */
289
- router.post(_prosopo_types.ClientApiPaths.VerifyPuzzleCaptchaSolution, async (req, res, next) => {
290
- if (require_apiToggleMaintenanceModeEndpoint.getMaintenanceMode()) {
291
- req.logger.info(() => ({ msg: "Maintenance mode active - returning verified for puzzle captcha verification" }));
292
- const verificationResponse = require_maintenanceModeResponses.buildMaintenanceVerificationResponse(req.i18n.t);
293
- return res.json(verificationResponse);
294
- }
295
- let parsed;
296
- try {
297
- parsed = _prosopo_types.ServerPuzzleCaptchaVerifyRequestBody.parse(req.body);
298
- } catch (err) {
299
- return next(new _prosopo_common.ProsopoApiError("CAPTCHA.PARSE_ERROR", {
300
- context: {
301
- code: 400,
302
- error: err,
303
- body: require_requestBodySummary.summariseRequestBody(req)
304
- },
305
- i18n: req.i18n,
306
- logger: req.logger
307
- }));
308
- }
309
- try {
310
- const { token, dappSignature, ip, email, clientSessionId } = parsed;
311
- const decoded = decodeTokenOr400(token, req.i18n, req.logger, next);
312
- if (decoded === null) return;
313
- const { dapp, user, timestamp, challenge, providerUrl } = decoded;
314
- const testVerdict = require_testSiteKey.resolveTestSiteKeyVerdict(dapp, req.logger);
315
- if (testVerdict !== null) {
316
- const verificationResponse = {
317
- status: "ok",
318
- verified: testVerdict
319
- };
320
- return res.json(verificationResponse);
321
- }
322
- const forwarded = await require_forwardVerify.forwardVerifyIfNotIssuer({
323
- env,
324
- logger: req.logger,
325
- path: _prosopo_types.ClientApiPaths.VerifyPuzzleCaptchaSolution,
326
- providerUrl,
327
- dapp,
328
- user,
329
- body: parsed,
330
- alreadyForwarded: req.headers[_prosopo_api.VERIFY_FORWARDED_HEADER] !== void 0
331
- });
332
- if (forwarded) return res.json(forwarded);
333
- const tasks = new require_tasks.Tasks(env, req.logger);
334
- (0, _prosopo_util_crypto.validateAddress)(dapp, false, 42);
335
- (0, _prosopo_util_crypto.validateAddress)(user, false, 42);
336
- const clientRecord = await tasks.db.getClientRecord(dapp);
337
- if (!clientRecord) return next(new _prosopo_common.ProsopoApiError("API.SITE_KEY_NOT_REGISTERED", {
338
- context: {
339
- code: 400,
340
- siteKey: dapp
341
- },
342
- i18n: req.i18n,
343
- logger: req.logger
344
- }));
345
- if (!challenge) {
346
- const unverifiedResponse = {
347
- status: req.i18n.t("API.USER_NOT_VERIFIED"),
348
- [_prosopo_types.ApiParams.verified]: false
349
- };
350
- return res.json(unverifiedResponse);
351
- }
352
- const dappPair = env.keyring.addFromAddress(dapp);
353
- const signatureError = dappSignatureError(dappSignature, timestamp.toString(), dappPair, req);
354
- if (signatureError) return next(signatureError);
355
- const { verified, score, sessionId } = await tasks.puzzleCaptchaManager.serverVerifyPuzzleCaptchaSolution(dapp, challenge, clientRecord.settings.verifiedTimeout, env, ip, userAccessRulesStorage, email, clientRecord.settings.spamEmailDomainCheckEnabled, clientRecord.settings.spamFilter, clientRecord.settings.trafficFilter, clientRecord.settings.storeMetadata, clientSessionId);
356
- const verificationResponse = tasks.puzzleCaptchaManager.getVerificationResponse(verified, clientRecord, req.i18n.t, score, void 0, sessionId);
357
- return res.json(verificationResponse);
358
- } catch (err) {
359
- req.logger.error(() => ({
360
- msg: "Error in verifyPuzzleCaptchaSolution",
361
- err,
362
- data: { body: require_requestBodySummary.summariseRequestBody(req) }
363
- }));
364
- return next(new _prosopo_common.ProsopoApiError("API.BAD_REQUEST", {
365
- context: {
366
- code: 500,
367
- error: err
368
- },
369
- i18n: req.i18n,
370
- logger: req.logger
371
- }));
372
- }
373
- });
399
+ router.post(_prosopo_types.ClientApiPaths.VerifyPuzzleCaptchaSolution, interactiveVerifyHandler({
400
+ env,
401
+ userAccessRulesStorage,
402
+ path: _prosopo_types.ClientApiPaths.VerifyPuzzleCaptchaSolution,
403
+ label: "puzzle",
404
+ handlerName: "verifyPuzzleCaptchaSolution",
405
+ manager: (tasks) => tasks.puzzleCaptchaManager
406
+ }));
407
+ router.post(_prosopo_types.ClientApiPaths.VerifyAudioCaptchaSolution, interactiveVerifyHandler({
408
+ env,
409
+ userAccessRulesStorage,
410
+ path: _prosopo_types.ClientApiPaths.VerifyAudioCaptchaSolution,
411
+ label: "audio",
412
+ handlerName: "verifyAudioCaptchaSolution",
413
+ manager: (tasks) => tasks.audioCaptchaManager
414
+ }));
415
+ router.post(_prosopo_types.ClientApiPaths.VerifyIconOrderCaptchaSolution, interactiveVerifyHandler({
416
+ env,
417
+ userAccessRulesStorage,
418
+ path: _prosopo_types.ClientApiPaths.VerifyIconOrderCaptchaSolution,
419
+ label: "icon-order",
420
+ handlerName: "verifyIconOrderCaptchaSolution",
421
+ manager: (tasks) => tasks.iconOrderCaptchaManager
422
+ }));
374
423
  /**
375
424
  * Verify a Web Bot Auth authenticated session token. Enforces IP binding:
376
425
  * the operator MUST forward `ip` in the request body, and it must equal
@@ -434,6 +483,14 @@ function prosopoVerifyRouter(env) {
434
483
  const keyPair = env.keyring.addFromAddress(dapp);
435
484
  const signatureError = dappSignatureError(dappSignature, timestamp.toString(), keyPair, req);
436
485
  if (signatureError) return next(signatureError);
486
+ if (require_apiToggleMaintenanceModeEndpoint.isSiteKeyInMaintenanceMode(dapp)) {
487
+ req.logger.info(() => ({
488
+ msg: "Site key in maintenance mode - returning verified",
489
+ data: { siteKey: dapp }
490
+ }));
491
+ const maintenanceResponse = require_maintenanceModeResponses.buildMaintenanceVerificationResponse(req.i18n.t);
492
+ return res.json(maintenanceResponse);
493
+ }
437
494
  if (!sessionId) return res.json({
438
495
  status: "API.USER_NOT_VERIFIED_NO_SOLUTION",
439
496
  verified: false
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_compositeIpAddress = require("./compositeIpAddress.cjs");
3
- const require_blacklistRequestInspector = require("./api/blacklistRequestInspector.cjs");
4
3
  const require_ipComparison = require("./services/ipComparison.cjs");
5
4
  const require_util = require("./util.cjs");
5
+ const require_blacklistRequestInspector = require("./api/blacklistRequestInspector.cjs");
6
6
  const require_tasks = require("./tasks/tasks.cjs");
7
7
  const require_updateSpamEmailDomains = require("./tasks/spam/updateSpamEmailDomains.cjs");
8
8
  const require_block = require("./api/block.cjs");
@@ -0,0 +1,72 @@
1
+ let _prosopo_audio_assets = require("@prosopo/audio-assets");
2
+ var settingsKey = (settings) => [
3
+ settings.digitCount,
4
+ settings.noiseSnrDb,
5
+ settings.babbleGain,
6
+ settings.babbleVoices,
7
+ settings.reverbMix,
8
+ settings.gapMs
9
+ ].join(":");
10
+ var createAudioChallengeBuffer = (options = {}) => {
11
+ const capacity = options.capacity ?? 8;
12
+ const refillIntervalMs = options.refillIntervalMs ?? 500;
13
+ const refillBatch = options.refillBatch ?? 2;
14
+ const maxVariants = options.maxVariants ?? 8;
15
+ const variants = /* @__PURE__ */ new Map();
16
+ let starved = 0;
17
+ const touch = (key, settings) => {
18
+ const existing = variants.get(key);
19
+ if (existing) {
20
+ variants.delete(key);
21
+ variants.set(key, existing);
22
+ return existing;
23
+ }
24
+ const created = {
25
+ settings,
26
+ ready: []
27
+ };
28
+ variants.set(key, created);
29
+ while (variants.size > maxVariants) {
30
+ const oldest = variants.keys().next().value;
31
+ if (oldest === void 0) break;
32
+ variants.delete(oldest);
33
+ }
34
+ return created;
35
+ };
36
+ const topUp = (limit) => {
37
+ for (const variant of variants.values()) for (let i = 0; i < limit && variant.ready.length < capacity; i++) variant.ready.push((0, _prosopo_audio_assets.renderAudioChallenge)(variant.settings));
38
+ };
39
+ const prime = options.primeSettings ?? _prosopo_audio_assets.DEFAULT_RENDER_SETTINGS;
40
+ touch(settingsKey(prime), prime);
41
+ topUp(capacity);
42
+ const timer = setInterval(() => topUp(refillBatch), refillIntervalMs);
43
+ timer.unref?.();
44
+ return {
45
+ take(settings) {
46
+ const challenge = touch(settingsKey(settings), settings).ready.pop();
47
+ if (!challenge) {
48
+ starved++;
49
+ return (0, _prosopo_audio_assets.renderAudioChallenge)(settings);
50
+ }
51
+ return challenge;
52
+ },
53
+ depth: () => {
54
+ let total = 0;
55
+ for (const variant of variants.values()) total += variant.ready.length;
56
+ return total;
57
+ },
58
+ starvations: () => starved,
59
+ stop: () => clearInterval(timer)
60
+ };
61
+ };
62
+ var globalBuffer = null;
63
+ var initAudioChallengeBuffer = (options = {}) => {
64
+ globalBuffer?.stop();
65
+ globalBuffer = createAudioChallengeBuffer(options);
66
+ return globalBuffer;
67
+ };
68
+ var getAudioChallengeBuffer = () => globalBuffer;
69
+ //#endregion
70
+ exports.createAudioChallengeBuffer = createAudioChallengeBuffer;
71
+ exports.getAudioChallengeBuffer = getAudioChallengeBuffer;
72
+ exports.initAudioChallengeBuffer = initAudioChallengeBuffer;
@@ -0,0 +1,32 @@
1
+ const require_audioBuffer = require("./audioBuffer.cjs");
2
+ let _prosopo_audio_assets = require("@prosopo/audio-assets");
3
+ //#region src/tasks/audio/audioRenderer.ts
4
+ /** Layers partial overrides onto the asset defaults; later sources win. */
5
+ var resolveAudioRenderSettings = (...overrides) => {
6
+ let resolved = { ..._prosopo_audio_assets.DEFAULT_RENDER_SETTINGS };
7
+ for (const override of overrides) resolved = {
8
+ digitCount: override?.digitCount ?? resolved.digitCount,
9
+ noiseSnrDb: override?.noiseSnrDb ?? resolved.noiseSnrDb,
10
+ babbleGain: override?.babbleGain ?? resolved.babbleGain,
11
+ babbleVoices: override?.babbleVoices ?? resolved.babbleVoices,
12
+ reverbMix: override?.reverbMix ?? resolved.reverbMix,
13
+ gapMs: override?.gapMs ?? resolved.gapMs
14
+ };
15
+ return resolved;
16
+ };
17
+ /**
18
+ * Takes one challenge from the process-wide buffer, created on first use so a
19
+ * provider that never serves audio pays nothing for it.
20
+ */
21
+ var renderAudioClip = (settings) => {
22
+ const challenge = (require_audioBuffer.getAudioChallengeBuffer() ?? require_audioBuffer.initAudioChallengeBuffer()).take(settings);
23
+ return {
24
+ clip: (0, _prosopo_audio_assets.toDataUri)(challenge.wav),
25
+ characterCount: challenge.answer.length,
26
+ answer: challenge.answer,
27
+ durationMs: challenge.durationMs
28
+ };
29
+ };
30
+ //#endregion
31
+ exports.renderAudioClip = renderAudioClip;
32
+ exports.resolveAudioRenderSettings = resolveAudioRenderSettings;
@@ -0,0 +1,23 @@
1
+ let _prosopo_types = require("@prosopo/types");
2
+ //#region src/tasks/audioAlternative.ts
3
+ var AUDIO_ALTERNATIVE_SESSION_TYPES = /* @__PURE__ */ new Set([
4
+ _prosopo_types.CaptchaType.image,
5
+ _prosopo_types.CaptchaType.puzzle,
6
+ _prosopo_types.CaptchaType.iconOrder
7
+ ]);
8
+ /** Whether a session of this type is a visual challenge that can offer audio. */
9
+ var isAudioAlternativeSessionType = (captchaType) => captchaType !== void 0 && AUDIO_ALTERNATIVE_SESSION_TYPES.has(captchaType);
10
+ /**
11
+ * The site owner has to turn the alternative on, and Prosopo has to have
12
+ * switched on the audio feature flag for the site.
13
+ */
14
+ var isAudioAlternativeEnabled = (settings) => settings?.audioAccessibilityEnabled === true && (0, _prosopo_types.isCaptchaTypeFeatureEnabled)(_prosopo_types.CaptchaType.audio, settings.captchaTypeFeatureFlags);
15
+ /** Whether a challenge of this type shows "use audio instead". */
16
+ var offersAudioAlternative = (captchaType, audioAlternativeEnabled) => audioAlternativeEnabled && isAudioAlternativeSessionType(captchaType);
17
+ /** Whether an audio challenge may be issued against a session of another type. */
18
+ var isAudioAlternativeAllowed = (requestedCaptchaType, sessionCaptchaType, settings) => requestedCaptchaType === _prosopo_types.CaptchaType.audio && offersAudioAlternative(sessionCaptchaType, isAudioAlternativeEnabled(settings));
19
+ //#endregion
20
+ exports.isAudioAlternativeAllowed = isAudioAlternativeAllowed;
21
+ exports.isAudioAlternativeEnabled = isAudioAlternativeEnabled;
22
+ exports.isAudioAlternativeSessionType = isAudioAlternativeSessionType;
23
+ exports.offersAudioAlternative = offersAudioAlternative;
@@ -0,0 +1,65 @@
1
+ const require_audioRenderer = require("../audio/audioRenderer.cjs");
2
+ const require_interactiveCaptchaManager = require("../interactiveCaptcha/interactiveCaptchaManager.cjs");
3
+ const require_audioTasksUtils = require("./audioTasksUtils.cjs");
4
+ let _prosopo_types = require("@prosopo/types");
5
+ //#region src/tasks/audioCaptcha/audioTasks.ts
6
+ var AudioCaptchaManager = class extends require_interactiveCaptchaManager.InteractiveCaptchaManager {
7
+ constructor(..._args) {
8
+ super(..._args);
9
+ this.captchaType = _prosopo_types.CaptchaType.audio;
10
+ this.logLabel = "audio";
11
+ }
12
+ getRecordByChallenge(challenge) {
13
+ return this.db.getAudioCaptchaRecordByChallenge(challenge);
14
+ }
15
+ updateRecord(challenge, updates) {
16
+ return this.db.updateAudioCaptchaRecord(challenge, updates);
17
+ }
18
+ updateSubmissionResult(challenge, result, userSignature, coords) {
19
+ return this.db.updateAudioCaptchaRecordResult(challenge, result, false, true, userSignature, coords);
20
+ }
21
+ /** Atomic, so concurrent submissions cannot each be graded. */
22
+ claimSubmission(record) {
23
+ return this.db.claimAudioCaptchaSubmission(record.challenge);
24
+ }
25
+ markRecordChecked(challenge) {
26
+ return this.db.markAudioCaptchaRecordChecked(challenge);
27
+ }
28
+ decisionMachineEventFields(record) {
29
+ return {
30
+ audioEvents: record.audioEvents,
31
+ audioReplays: record.replays
32
+ };
33
+ }
34
+ /**
35
+ * The renderer picks the digits, so the answer only exists once the clip
36
+ * does; the caller must store `answer` before responding.
37
+ */
38
+ getAudioCaptchaChallenge(userAccount, dappAccount, settings) {
39
+ return {
40
+ ...this.mintChallenge(userAccount, dappAccount),
41
+ ...require_audioRenderer.renderAudioClip(settings)
42
+ };
43
+ }
44
+ async verifyAudioCaptchaSolution(challenge, providerChallengeSignature, submittedAnswer, replays, audioEvents, timeout, userTimestampSignature, ipAddress, behavioralData, salt, simdReadings, clientMetaData) {
45
+ return this.submitInteractiveCaptchaSolution({
46
+ challenge,
47
+ providerChallengeSignature,
48
+ timeout,
49
+ userTimestampSignature,
50
+ ipAddress,
51
+ behavioralData,
52
+ salt,
53
+ simdReadings,
54
+ clientMetaData,
55
+ isCorrect: (record) => require_audioTasksUtils.validateAudioSolution(submittedAnswer, record.answer),
56
+ persistInteraction: () => this.db.updateAudioCaptchaRecord(challenge, {
57
+ audioEvents,
58
+ replays,
59
+ submittedAnswer: require_audioTasksUtils.normaliseAudioAnswer(submittedAnswer)
60
+ })
61
+ });
62
+ }
63
+ };
64
+ //#endregion
65
+ exports.AudioCaptchaManager = AudioCaptchaManager;
@@ -0,0 +1,19 @@
1
+ //#region src/tasks/audioCaptcha/audioTasksUtils.ts
2
+ /**
3
+ * Keeps only the digits, in order: "1 2 3", "1-2-3" and screen-reader inserted
4
+ * separators all grade the same, and no different digit sequence can pass.
5
+ */
6
+ var normaliseAudioAnswer = (raw) => raw.replace(/\D/g, "");
7
+ /**
8
+ * Exact match after normalisation. No edit-distance slack: one substitution
9
+ * widens the accepted set far more than it helps a listener, and a wrong
10
+ * answer only costs a fresh challenge.
11
+ */
12
+ var validateAudioSolution = (submitted, expected) => {
13
+ const normalised = normaliseAudioAnswer(submitted);
14
+ if (normalised.length === 0 || expected.length === 0) return false;
15
+ return normalised === expected;
16
+ };
17
+ //#endregion
18
+ exports.normaliseAudioAnswer = normaliseAudioAnswer;
19
+ exports.validateAudioSolution = validateAudioSolution;
@@ -1,5 +1,6 @@
1
1
  const require_compositeIpAddress = require("../compositeIpAddress.cjs");
2
2
  const require_blacklistRequestInspector = require("../api/blacklistRequestInspector.cjs");
3
+ const require_audioAlternative = require("./audioAlternative.cjs");
3
4
  const require_bundlePool = require("./detection/bundlePool.cjs");
4
5
  const require_decoderPool = require("./detection/decoderPool.cjs");
5
6
  const require_checkTrafficFilter = require("./spam/checkTrafficFilter.cjs");
@@ -225,7 +226,7 @@ var CaptchaManager = class CaptchaManager {
225
226
  sessionId
226
227
  }
227
228
  }));
228
- if (!(0, _prosopo_types.isCaptchaTypeFeatureEnabled)(requestedCaptchaType, clientSettings.settings?.captchaTypeFeatureFlags)) {
229
+ if (!(requestedCaptchaType === _prosopo_types.CaptchaType.audio ? require_audioAlternative.isAudioAlternativeEnabled(clientSettings.settings) : (0, _prosopo_types.isCaptchaTypeFeatureEnabled)(requestedCaptchaType, clientSettings.settings?.captchaTypeFeatureFlags))) {
229
230
  this.logger.warn(() => ({
230
231
  msg: "Captcha type is switched off for this site",
231
232
  data: {
@@ -332,7 +333,7 @@ var CaptchaManager = class CaptchaManager {
332
333
  type: requestedCaptchaType
333
334
  };
334
335
  }
335
- if (sessionRecord.captchaType !== requestedCaptchaType) {
336
+ if (sessionRecord.captchaType !== requestedCaptchaType && !require_audioAlternative.isAudioAlternativeAllowed(requestedCaptchaType, sessionRecord.captchaType, clientSettings.settings)) {
336
337
  this.logger.warn(() => ({
337
338
  msg: "Session captcha type does not match requested type",
338
339
  data: {
@@ -357,6 +358,17 @@ var CaptchaManager = class CaptchaManager {
357
358
  ipInfo: sessionRecord.ipInfo
358
359
  };
359
360
  }
361
+ if (requestedCaptchaType === _prosopo_types.CaptchaType.audio) {
362
+ this.logger.warn(() => ({
363
+ msg: "Sessionless audio captcha request rejected",
364
+ data: { account: clientSettings.account }
365
+ }));
366
+ return {
367
+ valid: false,
368
+ reason: _prosopo_types.ResultReason.INCORRECT_CAPTCHA_TYPE,
369
+ type: requestedCaptchaType
370
+ };
371
+ }
360
372
  if (userAccessPolicy?.captchaType !== void 0 && userAccessPolicy.captchaType !== requestedCaptchaType) {
361
373
  this.logger.warn(() => ({
362
374
  msg: "Invalid captcha type for user access policy (sessionless)",