@prosopo/provider 3.3.0 → 3.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +545 -0
  2. package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js +7 -4
  3. package/dist/api/blacklistRequestInspector.js +11 -9
  4. package/dist/api/captcha.js +121 -33
  5. package/dist/api/domainMiddleware.js +8 -8
  6. package/dist/api/headerCheckMiddleware.js +4 -0
  7. package/dist/api/ignoreMiddleware.js +4 -1
  8. package/dist/api/ja4Middleware.js +5 -23
  9. package/dist/api/public.js +26 -3
  10. package/dist/api/verify.js +4 -2
  11. package/dist/cjs/api/admin/apiRemoveDetectorKeyEndpoint.cjs +6 -3
  12. package/dist/cjs/api/blacklistRequestInspector.cjs +11 -9
  13. package/dist/cjs/api/captcha.cjs +121 -33
  14. package/dist/cjs/api/domainMiddleware.cjs +8 -8
  15. package/dist/cjs/api/headerCheckMiddleware.cjs +4 -0
  16. package/dist/cjs/api/ignoreMiddleware.cjs +3 -0
  17. package/dist/cjs/api/ja4Middleware.cjs +4 -22
  18. package/dist/cjs/api/public.cjs +26 -3
  19. package/dist/cjs/api/verify.cjs +4 -2
  20. package/dist/cjs/compositeIpAddress.cjs +53 -0
  21. package/dist/cjs/index.cjs +7 -0
  22. package/dist/cjs/pairs.cjs +27 -0
  23. package/dist/cjs/services/ipComparison.cjs +123 -0
  24. package/dist/cjs/services/ipInfo.cjs +87 -0
  25. package/dist/cjs/tasks/captchaManager.cjs +49 -2
  26. package/dist/cjs/tasks/client/clientTasks.cjs +33 -12
  27. package/dist/cjs/tasks/detection/decodePayload.cjs +712 -278
  28. package/dist/cjs/tasks/detection/getBotScore.cjs +14 -3
  29. package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +128 -24
  30. package/dist/cjs/tasks/frictionless/frictionlessTasksUtils.cjs +17 -0
  31. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +62 -20
  32. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +43 -15
  33. package/dist/cjs/util.cjs +248 -16
  34. package/dist/cjs/utils/hashUserAgent.cjs +10 -0
  35. package/dist/compositeIpAddress.js +53 -0
  36. package/dist/index.js +8 -1
  37. package/dist/pairs.js +27 -0
  38. package/dist/services/ipComparison.js +123 -0
  39. package/dist/services/ipInfo.js +87 -0
  40. package/dist/tasks/captchaManager.js +49 -2
  41. package/dist/tasks/client/clientTasks.js +33 -12
  42. package/dist/tasks/detection/decodePayload.js +712 -278
  43. package/dist/tasks/detection/getBotScore.js +15 -4
  44. package/dist/tasks/frictionless/frictionlessTasks.js +128 -24
  45. package/dist/tasks/frictionless/frictionlessTasksUtils.js +18 -1
  46. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +64 -22
  47. package/dist/tasks/powCaptcha/powTasks.js +44 -16
  48. package/dist/util.js +249 -17
  49. package/dist/utils/hashUserAgent.js +10 -0
  50. package/package.json +26 -23
  51. package/vite.test.config.ts +3 -2
  52. package/vite.threads.test.config.ts +33 -0
@@ -6,8 +6,11 @@ const datasets = require("@prosopo/datasets");
6
6
  const types = require("@prosopo/types");
7
7
  const util = require("@prosopo/util");
8
8
  const express = require("express");
9
+ const compositeIpAddress = require("../compositeIpAddress.cjs");
9
10
  const frictionlessTasks = require("../tasks/frictionless/frictionlessTasks.cjs");
11
+ const frictionlessTasksUtils = require("../tasks/frictionless/frictionlessTasksUtils.cjs");
10
12
  const tasks = require("../tasks/tasks.cjs");
13
+ const hashUserAgent = require("../utils/hashUserAgent.cjs");
11
14
  const blacklistRequestInspector = require("./blacklistRequestInspector.cjs");
12
15
  const validateAddress = require("./validateAddress.cjs");
13
16
  const DEFAULT_FRICTIONLESS_THRESHOLD = 0.5;
@@ -65,11 +68,13 @@ function prosopoRouter(env) {
65
68
  dapp,
66
69
  userScope
67
70
  ))[0];
68
- const { valid, reason, frictionlessTokenId } = await tasks$1.imgCaptchaManager.isValidRequest(
71
+ const { valid, reason, frictionlessTokenId, solvedImagesCount } = await tasks$1.imgCaptchaManager.isValidRequest(
69
72
  clientRecord,
70
73
  types.CaptchaType.image,
74
+ env,
71
75
  sessionId,
72
- userAccessPolicy
76
+ userAccessPolicy,
77
+ req.ip
73
78
  );
74
79
  if (!valid) {
75
80
  return next(
@@ -86,7 +91,7 @@ function prosopoRouter(env) {
86
91
  }
87
92
  const captchaConfig = {
88
93
  solved: {
89
- count: userAccessPolicy?.solvedImagesCount || env.config.captchas.solved.count
94
+ count: solvedImagesCount || userAccessPolicy?.solvedImagesCount || env.config.captchas.solved.count
90
95
  },
91
96
  unsolved: {
92
97
  count: userAccessPolicy?.unsolvedImagesCount || env.config.captchas.unsolved.count
@@ -117,12 +122,23 @@ function prosopoRouter(env) {
117
122
  }
118
123
  }
119
124
  };
125
+ req.logger.info(() => ({
126
+ msg: "Image captcha challenge issued",
127
+ data: {
128
+ captchaType: types.CaptchaType.image,
129
+ requestHash: taskData.requestHash,
130
+ solvedImagesCount: captchaConfig.solved.count,
131
+ user,
132
+ dapp,
133
+ sessionId
134
+ }
135
+ }));
120
136
  return res.json(captchaResponse);
121
137
  } catch (err) {
122
138
  req.logger.error(() => ({
123
139
  err,
124
140
  data: req.params,
125
- msg: "Error in PoW captcha solution submission"
141
+ msg: "Error in image captcha challenge request"
126
142
  }));
127
143
  return next(
128
144
  new common.ProsopoApiError("API.BAD_REQUEST", {
@@ -177,7 +193,7 @@ function prosopoRouter(env) {
177
193
  parsed[types.ApiParams.signature].user.timestamp,
178
194
  Number.parseInt(parsed[types.ApiParams.timestamp]),
179
195
  parsed[types.ApiParams.signature].provider.requestHash,
180
- util.getIPAddress(req.ip || "").bigInt(),
196
+ util.getIPAddress(req.ip || ""),
181
197
  util.flatten(req.headers),
182
198
  req.ja4
183
199
  );
@@ -192,7 +208,7 @@ function prosopoRouter(env) {
192
208
  req.logger.error(() => ({
193
209
  err,
194
210
  body: req.body,
195
- msg: "Error in PoW captcha solution submission"
211
+ msg: "Error in image captcha solution submission"
196
212
  }));
197
213
  return next(
198
214
  new common.ProsopoApiError("API.BAD_REQUEST", {
@@ -248,11 +264,13 @@ function prosopoRouter(env) {
248
264
  dapp,
249
265
  userScope
250
266
  ))[0];
251
- const { valid, reason, frictionlessTokenId } = await tasks$1.powCaptchaManager.isValidRequest(
267
+ const { valid, reason, frictionlessTokenId, powDifficulty } = await tasks$1.powCaptchaManager.isValidRequest(
252
268
  clientSettings,
253
269
  types.CaptchaType.pow,
270
+ env,
254
271
  sessionId,
255
- userAccessPolicy
272
+ userAccessPolicy,
273
+ req.ip
256
274
  );
257
275
  if (!valid) {
258
276
  return next(
@@ -282,11 +300,12 @@ function prosopoRouter(env) {
282
300
  })
283
301
  );
284
302
  }
303
+ const difficulty = powDifficulty || userAccessPolicy?.powDifficulty || clientSettings?.settings?.powDifficulty;
285
304
  const challenge = await tasks$1.powCaptchaManager.getPowCaptchaChallenge(
286
305
  user,
287
306
  dapp,
288
307
  origin,
289
- userAccessPolicy?.powDifficulty || clientSettings?.settings?.powDifficulty
308
+ difficulty
290
309
  );
291
310
  await tasks$1.db.storePowCaptchaRecord(
292
311
  challenge.challenge,
@@ -297,7 +316,7 @@ function prosopoRouter(env) {
297
316
  },
298
317
  challenge.difficulty,
299
318
  challenge.providerSignature,
300
- util.getIPAddress(req.ip || "").bigInt(),
319
+ compositeIpAddress.getCompositeIpAddress(req.ip || ""),
301
320
  util.flatten(req.headers),
302
321
  req.ja4,
303
322
  frictionlessTokenId
@@ -313,12 +332,23 @@ function prosopoRouter(env) {
313
332
  }
314
333
  }
315
334
  };
335
+ req.logger.info(() => ({
336
+ msg: "PoW captcha challenge issued",
337
+ data: {
338
+ captchaType: types.CaptchaType.pow,
339
+ challenge: challenge.challenge,
340
+ difficulty: challenge.difficulty,
341
+ user,
342
+ dapp,
343
+ session: sessionId
344
+ }
345
+ }));
316
346
  return res.json(getPowCaptchaResponse);
317
347
  } catch (err) {
318
348
  req.logger.error(() => ({
319
349
  err,
320
350
  body: req.body,
321
- msg: "Error in PoW captcha solution submission"
351
+ msg: "Error in PoW captcha challenge request"
322
352
  }));
323
353
  return next(
324
354
  new common.ProsopoApiError("API.BAD_REQUEST", {
@@ -350,15 +380,7 @@ function prosopoRouter(env) {
350
380
  })
351
381
  );
352
382
  }
353
- const {
354
- challenge,
355
- difficulty,
356
- signature,
357
- nonce,
358
- verifiedTimeout,
359
- dapp,
360
- user
361
- } = parsed;
383
+ const { challenge, signature, nonce, verifiedTimeout, dapp, user } = parsed;
362
384
  validateAddress.validateSiteKey(dapp);
363
385
  validateAddress.validateAddr(user);
364
386
  try {
@@ -374,7 +396,6 @@ function prosopoRouter(env) {
374
396
  }
375
397
  const verified = await tasks$1.powCaptchaManager.verifyPowCaptchaSolution(
376
398
  challenge,
377
- difficulty,
378
399
  signature.provider.challenge,
379
400
  nonce,
380
401
  verifiedTimeout,
@@ -416,17 +437,39 @@ function prosopoRouter(env) {
416
437
  token: existingToken,
417
438
  msg: "Token has already been used"
418
439
  }));
419
- return res.json(
420
- await tasks$1.frictionlessManager.sendImageCaptcha(
421
- existingToken._id
422
- )
440
+ return next(
441
+ new common.ProsopoApiError("API.BAD_REQUEST", {
442
+ context: {
443
+ code: 400,
444
+ siteKey: dapp,
445
+ user
446
+ },
447
+ i18n: req.i18n,
448
+ logger: req.logger
449
+ })
423
450
  );
424
451
  }
425
452
  const lScore = tasks$1.frictionlessManager.checkLangRules(
426
453
  req.headers["accept-language"] || ""
427
454
  );
428
- const { baseBotScore, timestamp } = await tasks$1.frictionlessManager.decryptPayload(token);
429
- const botScore = baseBotScore + lScore;
455
+ const {
456
+ baseBotScore,
457
+ timestamp,
458
+ providerSelectEntropy,
459
+ userId,
460
+ userAgent
461
+ } = await tasks$1.frictionlessManager.decryptPayload(token);
462
+ req.logger.debug(() => ({
463
+ msg: "Decrypted payload",
464
+ data: {
465
+ baseBotScore,
466
+ timestamp,
467
+ providerSelectEntropy,
468
+ userId,
469
+ userAgent
470
+ }
471
+ }));
472
+ let botScore = baseBotScore + lScore;
430
473
  const clientRecord = await tasks$1.db.getClientRecord(dapp);
431
474
  if (!clientRecord) {
432
475
  return next(
@@ -439,7 +482,8 @@ function prosopoRouter(env) {
439
482
  }
440
483
  const { valid, reason } = await tasks$1.frictionlessManager.isValidRequest(
441
484
  clientRecord,
442
- types.CaptchaType.frictionless
485
+ types.CaptchaType.frictionless,
486
+ env
443
487
  );
444
488
  if (!valid) {
445
489
  return next(
@@ -462,7 +506,9 @@ function prosopoRouter(env) {
462
506
  scoreComponents: {
463
507
  baseScore: baseBotScore,
464
508
  ...lScore && { lScore }
465
- }
509
+ },
510
+ providerSelectEntropy,
511
+ ipAddress: compositeIpAddress.getCompositeIpAddress(req.ip || "")
466
512
  });
467
513
  const userScope = blacklistRequestInspector.getRequestUserScope(
468
514
  util.flatten(req.headers),
@@ -475,6 +521,28 @@ function prosopoRouter(env) {
475
521
  dapp,
476
522
  userScope
477
523
  ))[0];
524
+ const headersUserAgent = req.headers["user-agent"];
525
+ const hashedHeadersUserAgent = headersUserAgent ? hashUserAgent.hashUserAgent(headersUserAgent) : "";
526
+ const headersProsopoUser = req.headers["prosopo-user"];
527
+ if (hashedHeadersUserAgent !== userAgent || headersProsopoUser !== userId) {
528
+ req.logger.info(() => ({
529
+ msg: "User agent or user id does not match",
530
+ data: {
531
+ headersUserAgent,
532
+ hashedHeadersUserAgent,
533
+ userAgent,
534
+ // This is the hashed user agent from the token
535
+ headersProsopoUser,
536
+ userId
537
+ }
538
+ }));
539
+ return res.json(
540
+ await tasks$1.frictionlessManager.sendImageCaptcha(
541
+ tokenId,
542
+ frictionlessTasksUtils.timestampDecayFunction(timestamp)
543
+ )
544
+ );
545
+ }
478
546
  if (userAccessPolicy) {
479
547
  await tasks$1.frictionlessManager.scoreIncreaseAccessPolicy(
480
548
  userAccessPolicy,
@@ -484,7 +552,10 @@ function prosopoRouter(env) {
484
552
  );
485
553
  if (userAccessPolicy.captchaType === types.CaptchaType.image) {
486
554
  return res.json(
487
- await tasks$1.frictionlessManager.sendImageCaptcha(tokenId)
555
+ await tasks$1.frictionlessManager.sendImageCaptcha(
556
+ tokenId,
557
+ userAccessPolicy.solvedImagesCount
558
+ )
488
559
  );
489
560
  }
490
561
  if (userAccessPolicy.captchaType === types.CaptchaType.pow) {
@@ -501,12 +572,26 @@ function prosopoRouter(env) {
501
572
  tokenId
502
573
  );
503
574
  return res.json(
504
- await tasks$1.frictionlessManager.sendImageCaptcha(tokenId)
575
+ await tasks$1.frictionlessManager.sendImageCaptcha(
576
+ tokenId,
577
+ frictionlessTasksUtils.timestampDecayFunction(timestamp)
578
+ )
579
+ );
580
+ }
581
+ const hostVerified = await tasks$1.frictionlessManager.hostVerified(
582
+ providerSelectEntropy
583
+ );
584
+ if (!hostVerified.verified) {
585
+ botScore = await tasks$1.frictionlessManager.scoreIncreaseUnverifiedHost(
586
+ hostVerified.domain,
587
+ baseBotScore,
588
+ botScore,
589
+ tokenId
505
590
  );
506
591
  }
507
592
  if (Number(botScore) > botThreshold) {
508
593
  req.logger.info(() => ({
509
- message: "Bot score is greater than threshold",
594
+ msg: "Bot score is greater than threshold",
510
595
  data: {
511
596
  botScore,
512
597
  botThreshold,
@@ -514,7 +599,10 @@ function prosopoRouter(env) {
514
599
  }
515
600
  }));
516
601
  return res.json(
517
- await tasks$1.frictionlessManager.sendImageCaptcha(tokenId)
602
+ await tasks$1.frictionlessManager.sendImageCaptcha(
603
+ tokenId,
604
+ env.config.captchas.solved.count
605
+ )
518
606
  );
519
607
  }
520
608
  return res.json(
@@ -10,26 +10,26 @@ const domainMiddleware = (env) => {
10
10
  const tasks$1 = new tasks.Tasks(env);
11
11
  return async (req, res, next) => {
12
12
  try {
13
- const dapp = req.headers["prosopo-site-key"];
14
- if (!dapp)
13
+ const siteKey = req.headers["prosopo-site-key"];
14
+ if (!siteKey)
15
15
  throw siteKeyNotRegisteredError(
16
16
  req.i18n,
17
17
  "No sitekey provided",
18
18
  req.logger
19
19
  );
20
20
  try {
21
- utilCrypto.validateAddress(dapp, false, 42);
21
+ utilCrypto.validateAddress(siteKey, false, 42);
22
22
  } catch (err) {
23
- throw invalidSiteKeyError(req.i18n, dapp, req.logger);
23
+ throw invalidSiteKeyError(req.i18n, siteKey, req.logger);
24
24
  }
25
- const clientSettings = await tasks$1.db.getClientRecord(dapp);
25
+ const clientSettings = await tasks$1.db.getClientRecord(siteKey);
26
26
  if (!clientSettings)
27
- throw siteKeyNotRegisteredError(req.i18n, dapp, req.logger);
27
+ throw siteKeyNotRegisteredError(req.i18n, siteKey, req.logger);
28
28
  const allowedDomains = clientSettings.settings?.domains;
29
29
  if (!allowedDomains)
30
30
  throw siteKeyInvalidDomainError(
31
31
  req.i18n,
32
- dapp,
32
+ siteKey,
33
33
  req.hostname,
34
34
  req.logger
35
35
  );
@@ -37,7 +37,7 @@ const domainMiddleware = (env) => {
37
37
  if (!origin)
38
38
  throw unauthorizedOriginError(req.i18n, void 0, req.logger);
39
39
  for (const domain of allowedDomains) {
40
- if (tasks$1.clientTaskManager.isSubdomainOrExactMatch(origin, domain)) {
40
+ if (tasks$1.clientTaskManager.domainPatternMatcher(origin, domain)) {
41
41
  next();
42
42
  return;
43
43
  }
@@ -19,6 +19,10 @@ const headerCheckMiddleware = (env) => {
19
19
  validateAddress.validateAddr(user, void 0, req.logger);
20
20
  req.user = user;
21
21
  req.siteKey = siteKey;
22
+ req.logger = req.logger.with({
23
+ user,
24
+ siteKey
25
+ });
22
26
  next();
23
27
  } catch (err) {
24
28
  return apiExpressRouter.handleErrors(err, req, res, next);
@@ -3,6 +3,9 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const types = require("@prosopo/types");
4
4
  function ignoreMiddleware() {
5
5
  return (req, res, next) => {
6
+ if (req.originalUrl.indexOf(types.PublicApiPaths.Healthz) !== -1) {
7
+ return next();
8
+ }
6
9
  if (req.originalUrl.indexOf(types.ApiPrefix) === -1) {
7
10
  res.statusCode = 404;
8
11
  res.send("Not Found");
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const node_crypto = require("node:crypto");
4
3
  const node_stream = require("node:stream");
5
4
  const apiExpressRouter = require("@prosopo/api-express-router");
6
5
  const common = require("@prosopo/common");
@@ -17,7 +16,6 @@ const getJA4 = async (headers, logger) => {
17
16
  try {
18
17
  const xTlsClientHello = (headers["x-tls-clienthello"] || "").toString();
19
18
  const xTlsVersion = (headers["x-tls-version"] || "").toString().toLowerCase();
20
- const xTlsServerName = (headers["x-tls-server-name"] || "").toString();
21
19
  const clientHelloBuffer = Buffer.from(xTlsClientHello, "base64");
22
20
  logger.debug(() => ({
23
21
  msg: "ClientHello First Bytes:",
@@ -33,32 +31,13 @@ const getJA4 = async (headers, logger) => {
33
31
  msg: "Headers TLS Version:",
34
32
  data: { xTlsVersion }
35
33
  }));
36
- const tlsVersion = xTlsVersion.replace(/(tls)|\./g, "");
37
34
  const readableStream = new node_stream.Readable({
38
35
  read() {
39
36
  this.push(clientHelloBuffer);
40
37
  }
41
38
  });
42
39
  const clientHello = await readTlsClientHello.readTlsClientHello(readableStream);
43
- const { alpnProtocols } = clientHello;
44
- const [_tlsVersion, cipherSuites, extensions] = clientHello.fingerprintData;
45
- const transport = "t";
46
- const sniIndicator = xTlsServerName ? "d" : "i";
47
- const validCipherSuites = cipherSuites.filter(
48
- (cs) => (cs & 3855) !== 2570
49
- );
50
- const cipherCount = validCipherSuites.length;
51
- const validExtensions = extensions.filter(
52
- (ext) => (ext & 3855) !== 2570
53
- );
54
- const extensionCount = validExtensions.length;
55
- const alpn = alpnProtocols?.length ? alpnProtocols[0] : "";
56
- const alpnLabel = alpn ? `${alpn[0]}${alpn[alpn.length - 1]}` : "00";
57
- const sortedCiphers = validCipherSuites.map((cs) => cs.toString(16).padStart(4, "0")).sort().join(",");
58
- const cipherHash = node_crypto.createHash("sha256").update(sortedCiphers).digest("hex").slice(0, 12);
59
- const decimalString = extensions.sort((a, b) => a - b).map((ext) => ext.toString(10)).join("-");
60
- const extensionHash = node_crypto.createHash("sha256").update(decimalString).digest("hex").slice(0, 12);
61
- const ja4PlusFingerprint = `${transport}${tlsVersion}${sniIndicator}${cipherCount}${extensionCount}${alpnLabel}_${cipherHash}_${extensionHash}`;
40
+ const ja4PlusFingerprint = readTlsClientHello.calculateJa4FromHelloData(clientHello);
62
41
  return { ja4PlusFingerprint };
63
42
  } catch (e) {
64
43
  logger.error(() => ({
@@ -74,6 +53,9 @@ const ja4Middleware = (env) => {
74
53
  req.logger.debug(() => ({ data: { url: req.url } }));
75
54
  const ja4 = await getJA4(req.headers, req.logger);
76
55
  req.ja4 = ja4.ja4PlusFingerprint || "";
56
+ req.logger = req.logger.with({
57
+ ja4: req.ja4
58
+ });
77
59
  next();
78
60
  } catch (err) {
79
61
  return apiExpressRouter.handleErrors(err, req, res, next);
@@ -5,16 +5,39 @@ const common = require("@prosopo/common");
5
5
  const types = require("@prosopo/types");
6
6
  const util = require("@prosopo/util");
7
7
  const express = require("express");
8
- function publicRouter() {
8
+ function publicRouter(env) {
9
9
  const router = express.Router();
10
10
  router.get(types.PublicApiPaths.Healthz, (req, res) => {
11
11
  res.status(200).send("OK");
12
12
  });
13
13
  router.get(types.PublicApiPaths.GetProviderDetails, async (req, res, next) => {
14
14
  try {
15
- return res.json({ version: util.version, ...{ message: "Provider online" } });
15
+ const db = env.getDb();
16
+ const redisConnection = db.getRedisConnection();
17
+ const redisAccessRulesConnection = db.getRedisAccessRulesConnection();
18
+ const response = {
19
+ version: util.version,
20
+ message: "Provider online",
21
+ redis: [
22
+ {
23
+ actor: "General",
24
+ isReady: redisConnection.isReady(),
25
+ awaitingTimeSeconds: Math.ceil(
26
+ redisConnection.getAwaitingTimeMs() / 1e3
27
+ )
28
+ },
29
+ {
30
+ actor: "UAP",
31
+ isReady: redisAccessRulesConnection.isReady(),
32
+ awaitingTimeSeconds: Math.ceil(
33
+ redisAccessRulesConnection.getAwaitingTimeMs() / 1e3
34
+ )
35
+ }
36
+ ]
37
+ };
38
+ return res.json(response);
16
39
  } catch (err) {
17
- req.logger.error(() => ({
40
+ env.logger.error(() => ({
18
41
  err,
19
42
  data: { reqParams: req.params },
20
43
  msg: "Error getting provider details"
@@ -24,7 +24,7 @@ function prosopoVerifyRouter(env) {
24
24
  })
25
25
  );
26
26
  }
27
- const { dappSignature, token, ip } = parsed;
27
+ const { dappSignature, token, ip, maxVerifiedTime } = parsed;
28
28
  try {
29
29
  const { user, dapp, timestamp, commitmentId } = types.decodeProcaptchaOutput(token);
30
30
  utilCrypto.validateAddress(dapp, false, 42);
@@ -45,7 +45,8 @@ function prosopoVerifyRouter(env) {
45
45
  user,
46
46
  dapp,
47
47
  commitmentId,
48
- parsed.maxVerifiedTime,
48
+ env,
49
+ maxVerifiedTime,
49
50
  ip
50
51
  );
51
52
  req.logger.debug(() => ({ data: { response } }));
@@ -113,6 +114,7 @@ function prosopoVerifyRouter(env) {
113
114
  dapp,
114
115
  challenge,
115
116
  verifiedTimeout,
117
+ env,
116
118
  ip
117
119
  );
118
120
  const verificationResponse = tasks$1.powCaptchaManager.getVerificationResponse(
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const typesDatabase = require("@prosopo/types-database");
4
+ const util = require("@prosopo/util");
5
+ const ipAddress = require("ip-address");
6
+ const V6_SHIFT = 64n;
7
+ const v6_LOWER_MASK = (1n << V6_SHIFT) - 1n;
8
+ const getCompositeIpAddress = (ip) => {
9
+ let ipAddress2;
10
+ try {
11
+ ipAddress2 = "string" === typeof ip ? util.getIPAddress(ip) : ip;
12
+ } catch (e) {
13
+ return {
14
+ lower: 0n,
15
+ type: typesDatabase.IpAddressType.v4
16
+ };
17
+ }
18
+ return getCompositeFromIpAddress(ipAddress2);
19
+ };
20
+ const getCompositeFromIpAddress = (ipAddress$1) => {
21
+ const numericIp = ipAddress$1.bigInt();
22
+ if (ipAddress$1 instanceof ipAddress.Address4) {
23
+ return {
24
+ lower: numericIp,
25
+ type: typesDatabase.IpAddressType.v4
26
+ };
27
+ }
28
+ ipAddress$1;
29
+ return {
30
+ lower: numericIp & v6_LOWER_MASK,
31
+ upper: numericIp >> V6_SHIFT,
32
+ type: typesDatabase.IpAddressType.v6
33
+ };
34
+ };
35
+ const getIpAddressFromComposite = (compositeIpAddress) => {
36
+ switch (compositeIpAddress.type) {
37
+ case typesDatabase.IpAddressType.v4:
38
+ return ipAddress.Address4.fromBigInt(getBigInt(compositeIpAddress.lower));
39
+ case typesDatabase.IpAddressType.v6:
40
+ return ipAddress.Address6.fromBigInt(
41
+ getBigInt(compositeIpAddress.upper) << V6_SHIFT | getBigInt(compositeIpAddress.lower) & v6_LOWER_MASK
42
+ );
43
+ default:
44
+ never();
45
+ return ipAddress.Address4.fromBigInt(0n);
46
+ }
47
+ };
48
+ const getBigInt = (number) => BigInt(number || 0n);
49
+ const never = () => {
50
+ throw new Error("Unhandled type");
51
+ };
52
+ exports.getCompositeIpAddress = getCompositeIpAddress;
53
+ exports.getIpAddressFromComposite = getIpAddressFromComposite;
@@ -14,9 +14,13 @@ const headerCheckMiddleware = require("./api/headerCheckMiddleware.cjs");
14
14
  const createApiAdminRoutesProvider = require("./api/admin/createApiAdminRoutesProvider.cjs");
15
15
  const ignoreMiddleware = require("./api/ignoreMiddleware.cjs");
16
16
  const robotsMiddleware = require("./api/robotsMiddleware.cjs");
17
+ const compositeIpAddress = require("./compositeIpAddress.cjs");
18
+ const ipComparison = require("./services/ipComparison.cjs");
17
19
  const tasks = require("./tasks/tasks.cjs");
18
20
  exports.checkIfTaskIsRunning = util.checkIfTaskIsRunning;
21
+ exports.deepValidateIpAddress = util.deepValidateIpAddress;
19
22
  exports.encodeStringAddress = util.encodeStringAddress;
23
+ exports.evaluateIpValidationRules = util.evaluateIpValidationRules;
20
24
  exports.getIPAddress = util.getIPAddress;
21
25
  exports.getIPAddressFromBigInt = util.getIPAddressFromBigInt;
22
26
  exports.shuffleArray = util.shuffleArray;
@@ -35,4 +39,7 @@ exports.headerCheckMiddleware = headerCheckMiddleware.headerCheckMiddleware;
35
39
  exports.createApiAdminRoutesProvider = createApiAdminRoutesProvider.createApiAdminRoutesProvider;
36
40
  exports.ignoreMiddleware = ignoreMiddleware.ignoreMiddleware;
37
41
  exports.robotsMiddleware = robotsMiddleware.robotsMiddleware;
42
+ exports.getCompositeIpAddress = compositeIpAddress.getCompositeIpAddress;
43
+ exports.getIpAddressFromComposite = compositeIpAddress.getIpAddressFromComposite;
44
+ exports.compareIPs = ipComparison.compareIPs;
38
45
  exports.Tasks = tasks.Tasks;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const util = require("@prosopo/util");
4
+ const constructPairList = (list) => {
5
+ if (list.length % 2 !== 0) {
6
+ throw new Error("Invalid pairs length");
7
+ }
8
+ const pairList = [];
9
+ for (let i = 0; i < list.length; i += 2) {
10
+ pairList.push([util.at(list, i), util.at(list, i + 1)]);
11
+ }
12
+ return pairList;
13
+ };
14
+ const containsIdenticalPairs = (pairsLists) => {
15
+ const set = /* @__PURE__ */ new Set();
16
+ for (const pairList of pairsLists) {
17
+ for (const pair of pairList) {
18
+ const x = util.at(pair, 0);
19
+ const y = util.at(pair, 1);
20
+ const coordString = `${x},${y}`;
21
+ set.add(coordString);
22
+ }
23
+ }
24
+ return set.size !== pairsLists.flat().flat().length / 2;
25
+ };
26
+ exports.constructPairList = constructPairList;
27
+ exports.containsIdenticalPairs = containsIdenticalPairs;