@prosopo/provider 3.12.3 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +214 -0
  2. package/dist/api/admin/apiAdminRoutesProvider.js +13 -18
  3. package/dist/api/admin/apiToggleMaintenanceModeEndpoint.js +40 -0
  4. package/dist/api/blacklistRequestInspector.js +4 -4
  5. package/dist/api/captcha/getFrictionlessCaptchaChallenge.js +338 -0
  6. package/dist/api/captcha/getImageCaptchaChallenge.js +150 -0
  7. package/dist/api/captcha/getPoWCaptchaChallenge.js +156 -0
  8. package/dist/api/captcha/submitImageCaptchaSolution.js +87 -0
  9. package/dist/api/captcha/submitPoWCaptchaSolution.js +77 -0
  10. package/dist/api/captcha.js +18 -606
  11. package/dist/api/verify.js +24 -1
  12. package/dist/cjs/api/admin/apiAdminRoutesProvider.cjs +13 -18
  13. package/dist/cjs/api/admin/apiRegisterSiteKeyEndpoint.cjs +2 -1
  14. package/dist/cjs/api/admin/apiRemoveDetectorKeyEndpoint.cjs +3 -2
  15. package/dist/cjs/api/admin/apiToggleMaintenanceModeEndpoint.cjs +41 -0
  16. package/dist/cjs/api/blacklistRequestInspector.cjs +3 -3
  17. package/dist/cjs/api/captcha/getFrictionlessCaptchaChallenge.cjs +337 -0
  18. package/dist/cjs/api/captcha/getImageCaptchaChallenge.cjs +149 -0
  19. package/dist/cjs/api/captcha/getPoWCaptchaChallenge.cjs +155 -0
  20. package/dist/cjs/api/captcha/submitImageCaptchaSolution.cjs +86 -0
  21. package/dist/cjs/api/captcha/submitPoWCaptchaSolution.cjs +76 -0
  22. package/dist/cjs/api/captcha.cjs +17 -605
  23. package/dist/cjs/api/ja4Middleware.cjs +2 -1
  24. package/dist/cjs/api/verify.cjs +24 -1
  25. package/dist/cjs/index.cjs +2 -0
  26. package/dist/cjs/schedulers/setClientEntropy.cjs +36 -0
  27. package/dist/cjs/tasks/captchaManager.cjs +7 -22
  28. package/dist/cjs/tasks/client/clientTasks.cjs +18 -36
  29. package/dist/cjs/tasks/detection/decodePayload.cjs +385 -714
  30. package/dist/cjs/tasks/detection/getBotScore.cjs +15 -2
  31. package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +136 -30
  32. package/dist/cjs/tasks/imgCaptcha/imgCaptchaTasks.cjs +25 -13
  33. package/dist/cjs/tasks/powCaptcha/powTasks.cjs +8 -8
  34. package/dist/cjs/tasks/tasks.cjs +1 -0
  35. package/dist/cjs/util.cjs +14 -1
  36. package/dist/cjs/utils/hashUserIp.cjs +9 -0
  37. package/dist/index.js +2 -0
  38. package/dist/schedulers/setClientEntropy.js +36 -0
  39. package/dist/tasks/captchaManager.js +5 -21
  40. package/dist/tasks/client/clientTasks.js +19 -37
  41. package/dist/tasks/detection/decodePayload.js +385 -714
  42. package/dist/tasks/detection/getBotScore.js +17 -4
  43. package/dist/tasks/frictionless/frictionlessTasks.js +137 -31
  44. package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +25 -13
  45. package/dist/tasks/powCaptcha/powTasks.js +8 -8
  46. package/dist/tasks/tasks.js +1 -0
  47. package/dist/util.js +14 -1
  48. package/dist/utils/hashUserIp.js +9 -0
  49. package/package.json +24 -25
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ const common = require("@prosopo/common");
3
+ const types = require("@prosopo/types");
4
+ const util = require("@prosopo/util");
5
+ const compositeIpAddress = require("../../compositeIpAddress.cjs");
6
+ require("../../tasks/index.cjs");
7
+ const blacklistRequestInspector = require("../blacklistRequestInspector.cjs");
8
+ const validateAddress = require("../validateAddress.cjs");
9
+ const tasks = require("../../tasks/tasks.cjs");
10
+ const getPoWCaptchaChallenge = (env, userAccessRulesStorage) => async (req, res, next) => {
11
+ let parsed;
12
+ const tasks$1 = new tasks.Tasks(env);
13
+ tasks$1.setLogger(req.logger);
14
+ try {
15
+ parsed = types.GetPowCaptchaChallengeRequestBody.parse(req.body);
16
+ } catch (err) {
17
+ return next(
18
+ new common.ProsopoApiError("CAPTCHA.PARSE_ERROR", {
19
+ context: { code: 400, error: err },
20
+ i18n: req.i18n,
21
+ logger: req.logger
22
+ })
23
+ );
24
+ }
25
+ const { user, dapp, sessionId } = parsed;
26
+ validateAddress.validateSiteKey(dapp);
27
+ validateAddress.validateAddr(user);
28
+ try {
29
+ const clientSettings = await tasks$1.db.getClientRecord(dapp);
30
+ if (!clientSettings) {
31
+ return next(
32
+ new common.ProsopoApiError("API.SITE_KEY_NOT_REGISTERED", {
33
+ context: { code: 400, siteKey: dapp },
34
+ i18n: req.i18n,
35
+ logger: req.logger
36
+ })
37
+ );
38
+ }
39
+ const userScope = blacklistRequestInspector.getRequestUserScope(
40
+ util.flatten(req.headers),
41
+ req.ja4,
42
+ req.ip,
43
+ user
44
+ );
45
+ const userAccessPolicy = (await tasks$1.powCaptchaManager.getPrioritisedAccessPolicies(
46
+ userAccessRulesStorage,
47
+ dapp,
48
+ userScope
49
+ ))[0];
50
+ const {
51
+ valid,
52
+ reason,
53
+ sessionId: validSessionId,
54
+ powDifficulty
55
+ } = await tasks$1.powCaptchaManager.isValidRequest(
56
+ clientSettings,
57
+ types.CaptchaType.pow,
58
+ env,
59
+ sessionId,
60
+ userAccessPolicy,
61
+ req.ip
62
+ );
63
+ if (!valid) {
64
+ return next(
65
+ new common.ProsopoApiError(reason || "API.BAD_REQUEST", {
66
+ context: {
67
+ code: 400,
68
+ siteKey: dapp,
69
+ user
70
+ },
71
+ i18n: req.i18n,
72
+ logger: req.logger
73
+ })
74
+ );
75
+ }
76
+ const origin = req.headers.origin;
77
+ if (!origin) {
78
+ return next(
79
+ new common.ProsopoApiError("API.BAD_REQUEST", {
80
+ context: {
81
+ error: "Origin header not found",
82
+ code: 400,
83
+ siteKey: dapp,
84
+ user
85
+ },
86
+ i18n: req.i18n,
87
+ logger: req.logger
88
+ })
89
+ );
90
+ }
91
+ const difficulty = powDifficulty || userAccessPolicy?.powDifficulty || clientSettings?.settings?.powDifficulty;
92
+ const challenge = await tasks$1.powCaptchaManager.getPowCaptchaChallenge(
93
+ user,
94
+ dapp,
95
+ origin,
96
+ difficulty
97
+ );
98
+ await tasks$1.db.storePowCaptchaRecord(
99
+ challenge.challenge,
100
+ {
101
+ requestedAtTimestamp: challenge.requestedAtTimestamp,
102
+ userAccount: user,
103
+ dappAccount: dapp
104
+ },
105
+ challenge.difficulty,
106
+ challenge.providerSignature,
107
+ compositeIpAddress.getCompositeIpAddress(req.ip || ""),
108
+ util.flatten(req.headers),
109
+ req.ja4,
110
+ validSessionId
111
+ );
112
+ const getPowCaptchaResponse = {
113
+ [types.ApiParams.status]: "ok",
114
+ [types.ApiParams.challenge]: challenge.challenge,
115
+ [types.ApiParams.difficulty]: challenge.difficulty,
116
+ [types.ApiParams.timestamp]: challenge.requestedAtTimestamp.toString(),
117
+ [types.ApiParams.signature]: {
118
+ [types.ApiParams.provider]: {
119
+ [types.ApiParams.challenge]: challenge.providerSignature
120
+ }
121
+ }
122
+ };
123
+ req.logger.info(() => ({
124
+ msg: "PoW captcha challenge issued",
125
+ data: {
126
+ captchaType: types.CaptchaType.pow,
127
+ challenge: challenge.challenge,
128
+ difficulty: challenge.difficulty,
129
+ user,
130
+ dapp,
131
+ session: sessionId
132
+ }
133
+ }));
134
+ return res.json(getPowCaptchaResponse);
135
+ } catch (err) {
136
+ req.logger.error(() => ({
137
+ err,
138
+ body: req.body,
139
+ msg: "Error in PoW captcha challenge request"
140
+ }));
141
+ return next(
142
+ new common.ProsopoApiError("API.BAD_REQUEST", {
143
+ context: {
144
+ code: 500,
145
+ siteKey: req.body.dapp,
146
+ user: req.body.user,
147
+ error: err
148
+ },
149
+ i18n: req.i18n,
150
+ logger: req.logger
151
+ })
152
+ );
153
+ }
154
+ };
155
+ module.exports = getPoWCaptchaChallenge;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ const common = require("@prosopo/common");
3
+ const types = require("@prosopo/types");
4
+ const util = require("@prosopo/util");
5
+ require("../../tasks/index.cjs");
6
+ const apiToggleMaintenanceModeEndpoint = require("../admin/apiToggleMaintenanceModeEndpoint.cjs");
7
+ const validateAddress = require("../validateAddress.cjs");
8
+ const tasks = require("../../tasks/tasks.cjs");
9
+ const submitImageCaptchaSolution = (env, userAccessRulesStorage) => async (req, res, next) => {
10
+ const tasks$1 = new tasks.Tasks(env, req.logger);
11
+ if (apiToggleMaintenanceModeEndpoint.getMaintenanceMode()) {
12
+ req.logger.info(() => ({
13
+ msg: "Maintenance mode active - returning verified for image captcha"
14
+ }));
15
+ const result = {
16
+ status: "ok",
17
+ captchas: [],
18
+ verified: true
19
+ };
20
+ return res.json(result);
21
+ }
22
+ let parsed;
23
+ try {
24
+ parsed = types.CaptchaSolutionBody.parse(req.body);
25
+ } catch (err) {
26
+ return next(
27
+ new common.ProsopoApiError("CAPTCHA.PARSE_ERROR", {
28
+ context: { code: 400, error: err, body: req.body },
29
+ i18n: req.i18n,
30
+ logger: req.logger
31
+ })
32
+ );
33
+ }
34
+ const { user, dapp } = parsed;
35
+ validateAddress.validateSiteKey(dapp);
36
+ validateAddress.validateAddr(user);
37
+ try {
38
+ const clientRecord = await tasks$1.db.getClientRecord(parsed.dapp);
39
+ if (!clientRecord) {
40
+ return next(
41
+ new common.ProsopoApiError("API.SITE_KEY_NOT_REGISTERED", {
42
+ context: { code: 400, siteKey: dapp },
43
+ i18n: req.i18n,
44
+ logger: req.logger
45
+ })
46
+ );
47
+ }
48
+ const result = await tasks$1.imgCaptchaManager.dappUserSolution(
49
+ user,
50
+ dapp,
51
+ parsed[types.ApiParams.requestHash],
52
+ parsed[types.ApiParams.captchas],
53
+ parsed[types.ApiParams.signature].user.timestamp,
54
+ Number.parseInt(parsed[types.ApiParams.timestamp]),
55
+ parsed[types.ApiParams.signature].provider.requestHash,
56
+ util.getIPAddress(req.ip || ""),
57
+ util.flatten(req.headers),
58
+ req.ja4
59
+ );
60
+ const returnValue = {
61
+ status: req.i18n.t(
62
+ result.verified ? "API.CAPTCHA_PASSED" : "API.CAPTCHA_FAILED"
63
+ ),
64
+ ...result
65
+ };
66
+ return res.json(returnValue);
67
+ } catch (err) {
68
+ req.logger.error(() => ({
69
+ err,
70
+ body: req.body,
71
+ msg: "Error in image captcha solution submission"
72
+ }));
73
+ return next(
74
+ new common.ProsopoApiError("API.BAD_REQUEST", {
75
+ context: {
76
+ code: 500,
77
+ siteKey: req.body.dapp,
78
+ error: err
79
+ },
80
+ i18n: req.i18n,
81
+ logger: req.logger
82
+ })
83
+ );
84
+ }
85
+ };
86
+ module.exports = submitImageCaptchaSolution;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ const common = require("@prosopo/common");
3
+ const types = require("@prosopo/types");
4
+ const util = require("@prosopo/util");
5
+ const tasks = require("../../tasks/tasks.cjs");
6
+ const apiToggleMaintenanceModeEndpoint = require("../admin/apiToggleMaintenanceModeEndpoint.cjs");
7
+ const validateAddress = require("../validateAddress.cjs");
8
+ const submitPoWCaptchaSolution = (env) => async (req, res, next) => {
9
+ let parsed;
10
+ const tasks$1 = new tasks.Tasks(env, req.logger);
11
+ if (apiToggleMaintenanceModeEndpoint.getMaintenanceMode()) {
12
+ req.logger.info(() => ({
13
+ msg: "Maintenance mode active - returning verified"
14
+ }));
15
+ const response = {
16
+ status: "ok",
17
+ verified: true
18
+ };
19
+ return res.json(response);
20
+ }
21
+ try {
22
+ parsed = types.SubmitPowCaptchaSolutionBody.parse(req.body);
23
+ } catch (err) {
24
+ return next(
25
+ new common.ProsopoApiError("CAPTCHA.PARSE_ERROR", {
26
+ context: { code: 400, error: err, body: req.body },
27
+ i18n: req.i18n,
28
+ logger: req.logger
29
+ })
30
+ );
31
+ }
32
+ const { challenge, signature, nonce, verifiedTimeout, dapp, user } = parsed;
33
+ validateAddress.validateSiteKey(dapp);
34
+ validateAddress.validateAddr(user);
35
+ try {
36
+ const clientRecord = await tasks$1.db.getClientRecord(dapp);
37
+ if (!clientRecord) {
38
+ return next(
39
+ new common.ProsopoApiError("API.SITE_KEY_NOT_REGISTERED", {
40
+ context: { code: 400, siteKey: dapp },
41
+ i18n: req.i18n,
42
+ logger: req.logger
43
+ })
44
+ );
45
+ }
46
+ const verified = await tasks$1.powCaptchaManager.verifyPowCaptchaSolution(
47
+ challenge,
48
+ signature.provider.challenge,
49
+ nonce,
50
+ verifiedTimeout,
51
+ signature.user.timestamp,
52
+ util.getIPAddress(req.ip || ""),
53
+ util.flatten(req.headers)
54
+ );
55
+ const response = { status: "ok", verified };
56
+ return res.json(response);
57
+ } catch (err) {
58
+ req.logger.error(() => ({
59
+ err,
60
+ body: req.body,
61
+ msg: "Error in PoW captcha solution submission"
62
+ }));
63
+ return next(
64
+ new common.ProsopoApiError("API.BAD_REQUEST", {
65
+ context: {
66
+ code: 500,
67
+ siteKey: req.body.dapp,
68
+ error: err
69
+ },
70
+ i18n: req.i18n,
71
+ logger: req.logger
72
+ })
73
+ );
74
+ }
75
+ };
76
+ module.exports = submitPoWCaptchaSolution;