@prosopo/provider 3.1.3 → 3.2.1
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/CHANGELOG.md +54 -0
- package/dist/api/admin/apiAdminRoutesProvider.js +26 -21
- package/dist/api/admin/apiRegisterSiteKeyEndpoint.js +21 -20
- package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js +27 -27
- package/dist/api/admin/apiUpdateDetectorKeyEndpoint.js +33 -33
- package/dist/api/admin/createApiAdminRoutesProvider.js +8 -5
- package/dist/api/blacklistRequestInspector.js +116 -98
- package/dist/api/block.js +13 -8
- package/dist/api/captcha.js +519 -356
- package/dist/api/domainMiddleware.js +75 -68
- package/dist/api/headerCheckMiddleware.js +26 -25
- package/dist/api/ignoreMiddleware.js +12 -10
- package/dist/api/ja4Middleware.js +75 -80
- package/dist/api/public.js +26 -23
- package/dist/api/robotsMiddleware.js +11 -9
- package/dist/api/validateAddress.js +20 -18
- package/dist/api/verify.js +133 -95
- package/dist/cjs/api/blacklistRequestInspector.cjs +4 -6
- package/dist/cjs/api/captcha.cjs +45 -36
- package/dist/cjs/api/ja4Middleware.cjs +4 -1
- package/dist/cjs/tasks/captchaManager.cjs +24 -10
- package/dist/cjs/tasks/frictionless/frictionlessTasks.cjs +0 -3
- package/dist/cjs/tasks/powCaptcha/powTasksUtils.cjs +1 -1
- package/dist/index.js +38 -15
- package/dist/rules/lang.js +14 -14
- package/dist/schedulers/captchaScheduler.js +28 -23
- package/dist/schedulers/getClientList.js +29 -24
- package/dist/tasks/captchaManager.js +109 -85
- package/dist/tasks/client/clientTasks.js +265 -204
- package/dist/tasks/dataset/datasetTasks.js +27 -16
- package/dist/tasks/dataset/datasetTasksUtils.js +31 -31
- package/dist/tasks/detection/decodePayload.js +378 -208
- package/dist/tasks/detection/getBotScore.js +12 -10
- package/dist/tasks/frictionless/frictionlessTasks.js +117 -119
- package/dist/tasks/frictionless/frictionlessTasksUtils.js +10 -5
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.js +360 -271
- package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.js +23 -16
- package/dist/tasks/index.js +4 -2
- package/dist/tasks/powCaptcha/powTasks.js +157 -97
- package/dist/tasks/powCaptcha/powTasksUtils.js +24 -20
- package/dist/tasks/tasks.js +53 -29
- package/dist/util.js +98 -88
- package/package.json +31 -27
- package/vite.cjs.config.ts +4 -1
- package/vite.esm.config.ts +20 -0
- package/vite.test.config.ts +15 -3
- package/dist/api/admin/apiAdminRoutesProvider.d.ts +0 -9
- package/dist/api/admin/apiAdminRoutesProvider.d.ts.map +0 -1
- package/dist/api/admin/apiAdminRoutesProvider.js.map +0 -1
- package/dist/api/admin/apiRegisterSiteKeyEndpoint.d.ts +0 -14
- package/dist/api/admin/apiRegisterSiteKeyEndpoint.d.ts.map +0 -1
- package/dist/api/admin/apiRegisterSiteKeyEndpoint.js.map +0 -1
- package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts +0 -14
- package/dist/api/admin/apiRemoveDetectorKeyEndpoint.d.ts.map +0 -1
- package/dist/api/admin/apiRemoveDetectorKeyEndpoint.js.map +0 -1
- package/dist/api/admin/apiUpdateDetectorKeyEndpoint.d.ts +0 -14
- package/dist/api/admin/apiUpdateDetectorKeyEndpoint.d.ts.map +0 -1
- package/dist/api/admin/apiUpdateDetectorKeyEndpoint.js.map +0 -1
- package/dist/api/admin/createApiAdminRoutesProvider.d.ts +0 -4
- package/dist/api/admin/createApiAdminRoutesProvider.d.ts.map +0 -1
- package/dist/api/admin/createApiAdminRoutesProvider.js.map +0 -1
- package/dist/api/blacklistRequestInspector.d.ts +0 -44
- package/dist/api/blacklistRequestInspector.d.ts.map +0 -1
- package/dist/api/blacklistRequestInspector.js.map +0 -1
- package/dist/api/block.d.ts +0 -3
- package/dist/api/block.d.ts.map +0 -1
- package/dist/api/block.js.map +0 -1
- package/dist/api/captcha.d.ts +0 -4
- package/dist/api/captcha.d.ts.map +0 -1
- package/dist/api/captcha.js.map +0 -1
- package/dist/api/domainMiddleware.d.ts +0 -4
- package/dist/api/domainMiddleware.d.ts.map +0 -1
- package/dist/api/domainMiddleware.js.map +0 -1
- package/dist/api/headerCheckMiddleware.d.ts +0 -4
- package/dist/api/headerCheckMiddleware.d.ts.map +0 -1
- package/dist/api/headerCheckMiddleware.js.map +0 -1
- package/dist/api/ignoreMiddleware.d.ts +0 -3
- package/dist/api/ignoreMiddleware.d.ts.map +0 -1
- package/dist/api/ignoreMiddleware.js.map +0 -1
- package/dist/api/ja4Middleware.d.ts +0 -10
- package/dist/api/ja4Middleware.d.ts.map +0 -1
- package/dist/api/ja4Middleware.js.map +0 -1
- package/dist/api/public.d.ts +0 -3
- package/dist/api/public.d.ts.map +0 -1
- package/dist/api/public.js.map +0 -1
- package/dist/api/robotsMiddleware.d.ts +0 -3
- package/dist/api/robotsMiddleware.d.ts.map +0 -1
- package/dist/api/robotsMiddleware.js.map +0 -1
- package/dist/api/validateAddress.d.ts +0 -5
- package/dist/api/validateAddress.d.ts.map +0 -1
- package/dist/api/validateAddress.js.map +0 -1
- package/dist/api/verify.d.ts +0 -4
- package/dist/api/verify.d.ts.map +0 -1
- package/dist/api/verify.js.map +0 -1
- package/dist/index.d.ts +0 -15
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/rules/lang.d.ts +0 -3
- package/dist/rules/lang.d.ts.map +0 -1
- package/dist/rules/lang.js.map +0 -1
- package/dist/schedulers/captchaScheduler.d.ts +0 -4
- package/dist/schedulers/captchaScheduler.d.ts.map +0 -1
- package/dist/schedulers/captchaScheduler.js.map +0 -1
- package/dist/schedulers/getClientList.d.ts +0 -4
- package/dist/schedulers/getClientList.d.ts.map +0 -1
- package/dist/schedulers/getClientList.js.map +0 -1
- package/dist/tasks/captchaManager.d.ts +0 -48
- package/dist/tasks/captchaManager.d.ts.map +0 -1
- package/dist/tasks/captchaManager.js.map +0 -1
- package/dist/tasks/client/clientTasks.d.ts +0 -21
- package/dist/tasks/client/clientTasks.d.ts.map +0 -1
- package/dist/tasks/client/clientTasks.js.map +0 -1
- package/dist/tasks/dataset/datasetTasks.d.ts +0 -13
- package/dist/tasks/dataset/datasetTasks.d.ts.map +0 -1
- package/dist/tasks/dataset/datasetTasks.js.map +0 -1
- package/dist/tasks/dataset/datasetTasksUtils.d.ts +0 -3
- package/dist/tasks/dataset/datasetTasksUtils.d.ts.map +0 -1
- package/dist/tasks/dataset/datasetTasksUtils.js.map +0 -1
- package/dist/tasks/detection/decodePayload.d.ts +0 -5
- package/dist/tasks/detection/decodePayload.d.ts.map +0 -1
- package/dist/tasks/detection/decodePayload.js.map +0 -1
- package/dist/tasks/detection/getBotScore.d.ts +0 -5
- package/dist/tasks/detection/getBotScore.d.ts.map +0 -1
- package/dist/tasks/detection/getBotScore.js.map +0 -1
- package/dist/tasks/frictionless/frictionlessTasks.d.ts +0 -23
- package/dist/tasks/frictionless/frictionlessTasks.d.ts.map +0 -1
- package/dist/tasks/frictionless/frictionlessTasks.js.map +0 -1
- package/dist/tasks/frictionless/frictionlessTasksUtils.d.ts +0 -5
- package/dist/tasks/frictionless/frictionlessTasksUtils.d.ts.map +0 -1
- package/dist/tasks/frictionless/frictionlessTasksUtils.js.map +0 -1
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts +0 -29
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.d.ts.map +0 -1
- package/dist/tasks/imgCaptcha/imgCaptchaTasks.js.map +0 -1
- package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.d.ts +0 -7
- package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.d.ts.map +0 -1
- package/dist/tasks/imgCaptcha/imgCaptchaTasksUtils.js.map +0 -1
- package/dist/tasks/index.d.ts +0 -2
- package/dist/tasks/index.d.ts.map +0 -1
- package/dist/tasks/index.js.map +0 -1
- package/dist/tasks/powCaptcha/powTasks.d.ts +0 -16
- package/dist/tasks/powCaptcha/powTasks.d.ts.map +0 -1
- package/dist/tasks/powCaptcha/powTasks.js.map +0 -1
- package/dist/tasks/powCaptcha/powTasksUtils.d.ts +0 -3
- package/dist/tasks/powCaptcha/powTasksUtils.d.ts.map +0 -1
- package/dist/tasks/powCaptcha/powTasksUtils.js.map +0 -1
- package/dist/tasks/tasks.d.ts +0 -25
- package/dist/tasks/tasks.d.ts.map +0 -1
- package/dist/tasks/tasks.js.map +0 -1
- package/dist/tests/index.d.ts +0 -2
- package/dist/tests/index.d.ts.map +0 -1
- package/dist/tests/index.js +0 -2
- package/dist/tests/index.js.map +0 -1
- package/dist/tests/integration/imgCaptcha.integration.test.d.ts +0 -2
- package/dist/tests/integration/imgCaptcha.integration.test.d.ts.map +0 -1
- package/dist/tests/integration/imgCaptcha.integration.test.js +0 -261
- package/dist/tests/integration/imgCaptcha.integration.test.js.map +0 -1
- package/dist/tests/integration/mocks/solvedTestCaptchas.d.ts +0 -32
- package/dist/tests/integration/mocks/solvedTestCaptchas.d.ts.map +0 -1
- package/dist/tests/integration/mocks/solvedTestCaptchas.js +0 -1046
- package/dist/tests/integration/mocks/solvedTestCaptchas.js.map +0 -1
- package/dist/tests/integration/powCaptcha.integration.test.d.ts +0 -2
- package/dist/tests/integration/powCaptcha.integration.test.d.ts.map +0 -1
- package/dist/tests/integration/powCaptcha.integration.test.js +0 -299
- package/dist/tests/integration/powCaptcha.integration.test.js.map +0 -1
- package/dist/tests/integration/registerSitekey.d.ts +0 -3
- package/dist/tests/integration/registerSitekey.d.ts.map +0 -1
- package/dist/tests/integration/registerSitekey.js +0 -39
- package/dist/tests/integration/registerSitekey.js.map +0 -1
- package/dist/tests/unit/api/ignoreMiddleware.unit.test.d.ts +0 -2
- package/dist/tests/unit/api/ignoreMiddleware.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/api/ignoreMiddleware.unit.test.js +0 -43
- package/dist/tests/unit/api/ignoreMiddleware.unit.test.js.map +0 -1
- package/dist/tests/unit/api/ja4Middleware.unit.test.d.ts +0 -2
- package/dist/tests/unit/api/ja4Middleware.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/api/ja4Middleware.unit.test.js +0 -71
- package/dist/tests/unit/api/ja4Middleware.unit.test.js.map +0 -1
- package/dist/tests/unit/schedulers/captchaScheduler.unit.test.d.ts +0 -2
- package/dist/tests/unit/schedulers/captchaScheduler.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/schedulers/captchaScheduler.unit.test.js +0 -75
- package/dist/tests/unit/schedulers/captchaScheduler.unit.test.js.map +0 -1
- package/dist/tests/unit/tasks/captchaManager.unit.test.d.ts +0 -2
- package/dist/tests/unit/tasks/captchaManager.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/tasks/captchaManager.unit.test.js +0 -236
- package/dist/tests/unit/tasks/captchaManager.unit.test.js.map +0 -1
- package/dist/tests/unit/tasks/client/clientTasks.unit.test.d.ts +0 -2
- package/dist/tests/unit/tasks/client/clientTasks.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/tasks/client/clientTasks.unit.test.js +0 -277
- package/dist/tests/unit/tasks/client/clientTasks.unit.test.js.map +0 -1
- package/dist/tests/unit/tasks/dataset/datasetTasks.unit.test.d.ts +0 -2
- package/dist/tests/unit/tasks/dataset/datasetTasks.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/tasks/dataset/datasetTasks.unit.test.js +0 -93
- package/dist/tests/unit/tasks/dataset/datasetTasks.unit.test.js.map +0 -1
- package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.d.ts +0 -2
- package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.js +0 -75
- package/dist/tests/unit/tasks/dataset/datasetTasksUtils.unit.test.js.map +0 -1
- package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.d.ts +0 -2
- package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.js +0 -68
- package/dist/tests/unit/tasks/frictionless/frictionlessTasks.unit.test.js.map +0 -1
- package/dist/tests/unit/tasks/frictionless/frictionlessTasksUtils.unit.test.d.ts +0 -2
- package/dist/tests/unit/tasks/frictionless/frictionlessTasksUtils.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/tasks/frictionless/frictionlessTasksUtils.unit.test.js +0 -37
- package/dist/tests/unit/tasks/frictionless/frictionlessTasksUtils.unit.test.js.map +0 -1
- package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.d.ts +0 -2
- package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.js +0 -402
- package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasks.unit.test.js.map +0 -1
- package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.d.ts +0 -2
- package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js +0 -46
- package/dist/tests/unit/tasks/imgCaptcha/imgCaptchaTasksUtils.unit.test.js.map +0 -1
- package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.d.ts +0 -2
- package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js +0 -228
- package/dist/tests/unit/tasks/powCaptcha/powTasks.unit.test.js.map +0 -1
- package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.d.ts +0 -2
- package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.js +0 -68
- package/dist/tests/unit/tasks/powCaptcha/powTasksUtils.unit.test.js.map +0 -1
- package/dist/tests/unit/util.unit.test.d.ts +0 -2
- package/dist/tests/unit/util.unit.test.d.ts.map +0 -1
- package/dist/tests/unit/util.unit.test.js +0 -148
- package/dist/tests/unit/util.unit.test.js.map +0 -1
- package/dist/util.d.ts +0 -13
- package/dist/util.d.ts.map +0 -1
- package/dist/util.js.map +0 -1
|
@@ -2,81 +2,88 @@ import { handleErrors } from "@prosopo/api-express-router";
|
|
|
2
2
|
import { ProsopoApiError } from "@prosopo/common";
|
|
3
3
|
import { validateAddress } from "@prosopo/util-crypto";
|
|
4
4
|
import { ZodError } from "zod";
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
5
|
+
import "../tasks/index.js";
|
|
6
|
+
import { Tasks } from "../tasks/tasks.js";
|
|
7
|
+
const domainMiddleware = (env) => {
|
|
8
|
+
const tasks = new Tasks(env);
|
|
9
|
+
return async (req, res, next) => {
|
|
10
|
+
try {
|
|
11
|
+
const dapp = req.headers["prosopo-site-key"];
|
|
12
|
+
if (!dapp)
|
|
13
|
+
throw siteKeyNotRegisteredError(
|
|
14
|
+
req.i18n,
|
|
15
|
+
"No sitekey provided",
|
|
16
|
+
req.logger
|
|
17
|
+
);
|
|
18
|
+
try {
|
|
19
|
+
validateAddress(dapp, false, 42);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
throw invalidSiteKeyError(req.i18n, dapp, req.logger);
|
|
22
|
+
}
|
|
23
|
+
const clientSettings = await tasks.db.getClientRecord(dapp);
|
|
24
|
+
if (!clientSettings)
|
|
25
|
+
throw siteKeyNotRegisteredError(req.i18n, dapp, req.logger);
|
|
26
|
+
const allowedDomains = clientSettings.settings?.domains;
|
|
27
|
+
if (!allowedDomains)
|
|
28
|
+
throw siteKeyInvalidDomainError(
|
|
29
|
+
req.i18n,
|
|
30
|
+
dapp,
|
|
31
|
+
req.hostname,
|
|
32
|
+
req.logger
|
|
33
|
+
);
|
|
34
|
+
const origin = req.headers.origin;
|
|
35
|
+
if (!origin)
|
|
36
|
+
throw unauthorizedOriginError(req.i18n, void 0, req.logger);
|
|
37
|
+
for (const domain of allowedDomains) {
|
|
38
|
+
if (tasks.clientTaskManager.isSubdomainOrExactMatch(origin, domain)) {
|
|
39
|
+
next();
|
|
40
|
+
return;
|
|
35
41
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
};
|
|
42
|
+
}
|
|
43
|
+
throw unauthorizedOriginError(req.i18n, origin, req.logger);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
if (err instanceof ProsopoApiError || err instanceof ZodError || err instanceof SyntaxError) {
|
|
46
|
+
handleErrors(err, req, res, next);
|
|
47
|
+
} else {
|
|
48
|
+
res.status(401).json({ error: "Unauthorized", message: err });
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
48
53
|
};
|
|
49
54
|
const siteKeyNotRegisteredError = (i18n, dapp, logger) => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
return new ProsopoApiError("API.SITE_KEY_NOT_REGISTERED", {
|
|
56
|
+
context: { code: 400, siteKey: dapp },
|
|
57
|
+
i18n,
|
|
58
|
+
logger
|
|
59
|
+
});
|
|
55
60
|
};
|
|
56
61
|
const invalidSiteKeyError = (i18n, siteKey, logger) => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
return new ProsopoApiError("API.INVALID_SITE_KEY", {
|
|
63
|
+
context: { code: 400, siteKey },
|
|
64
|
+
i18n,
|
|
65
|
+
logger
|
|
66
|
+
});
|
|
62
67
|
};
|
|
63
68
|
const unauthorizedOriginError = (i18n, origin, logger) => {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
return new ProsopoApiError("API.UNAUTHORIZED_ORIGIN_URL", {
|
|
70
|
+
context: { code: 400, origin },
|
|
71
|
+
i18n,
|
|
72
|
+
logger
|
|
73
|
+
});
|
|
69
74
|
};
|
|
70
75
|
const siteKeyInvalidDomainError = (i18n, dapp, domain, logger) => {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
return new ProsopoApiError("API.UNAUTHORIZED_ORIGIN_URL", {
|
|
77
|
+
context: {
|
|
78
|
+
code: 400,
|
|
79
|
+
message: "No domains are allowed for this site key. Please fix in the Procaptcha Portal",
|
|
80
|
+
siteKey: dapp,
|
|
81
|
+
domain
|
|
82
|
+
},
|
|
83
|
+
i18n,
|
|
84
|
+
logger
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
export {
|
|
88
|
+
domainMiddleware
|
|
81
89
|
};
|
|
82
|
-
//# sourceMappingURL=domainMiddleware.js.map
|
|
@@ -1,28 +1,29 @@
|
|
|
1
1
|
import { handleErrors } from "@prosopo/api-express-router";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
2
|
+
import { validateSiteKey, validateAddr } from "./validateAddress.js";
|
|
3
|
+
const headerCheckMiddleware = (env) => {
|
|
4
|
+
return async (req, res, next) => {
|
|
5
|
+
try {
|
|
6
|
+
const user = req.headers["prosopo-user"];
|
|
7
|
+
const siteKey = req.headers["prosopo-site-key"];
|
|
8
|
+
if (!user) {
|
|
9
|
+
unauthorised(res);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (!siteKey) {
|
|
13
|
+
unauthorised(res);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
validateSiteKey(siteKey, req.logger);
|
|
17
|
+
validateAddr(user, void 0, req.logger);
|
|
18
|
+
req.user = user;
|
|
19
|
+
req.siteKey = siteKey;
|
|
20
|
+
next();
|
|
21
|
+
} catch (err) {
|
|
22
|
+
return handleErrors(err, req, res, next);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
26
25
|
};
|
|
27
26
|
const unauthorised = (res) => res.status(401).json({ error: "Unauthorized", message: "Unauthorized" });
|
|
28
|
-
|
|
27
|
+
export {
|
|
28
|
+
headerCheckMiddleware
|
|
29
|
+
};
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { ApiPrefix } from "@prosopo/types";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
function ignoreMiddleware() {
|
|
3
|
+
return (req, res, next) => {
|
|
4
|
+
if (req.originalUrl.indexOf(ApiPrefix) === -1) {
|
|
5
|
+
res.statusCode = 404;
|
|
6
|
+
res.send("Not Found");
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
next();
|
|
10
|
+
};
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
export {
|
|
13
|
+
ignoreMiddleware
|
|
14
|
+
};
|
|
@@ -2,89 +2,84 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { Readable } from "node:stream";
|
|
3
3
|
import { handleErrors } from "@prosopo/api-express-router";
|
|
4
4
|
import { getLogger } from "@prosopo/common";
|
|
5
|
+
import { randomAsHex } from "@prosopo/util-crypto";
|
|
5
6
|
import { readTlsClientHello } from "read-tls-client-hello";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const DEFAULT_JA4 = "ja4";
|
|
8
|
+
const getJA4 = async (headers, logger) => {
|
|
9
|
+
logger = logger || getLogger("info", import.meta.url);
|
|
10
|
+
if (process.env.NODE_ENV === "development") {
|
|
11
|
+
return {
|
|
12
|
+
ja4PlusFingerprint: `${DEFAULT_JA4}${randomAsHex().slice(28, 32)}`
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const xTlsClientHello = (headers["x-tls-clienthello"] || "").toString();
|
|
17
|
+
const xTlsVersion = (headers["x-tls-version"] || "").toString().toLowerCase();
|
|
18
|
+
const xTlsServerName = (headers["x-tls-server-name"] || "").toString();
|
|
19
|
+
const clientHelloBuffer = Buffer.from(xTlsClientHello, "base64");
|
|
20
|
+
logger.debug(() => ({
|
|
21
|
+
msg: "ClientHello First Bytes:",
|
|
22
|
+
data: { hex: clientHelloBuffer.subarray(0, 5).toString("hex") }
|
|
23
|
+
}));
|
|
24
|
+
if (clientHelloBuffer[5] !== 1) {
|
|
25
|
+
logger.debug(() => ({
|
|
26
|
+
msg: "Invalid ClientHello message: First byte is not 0x01"
|
|
27
|
+
}));
|
|
28
|
+
return { ja4PlusFingerprint: DEFAULT_JA4 };
|
|
11
29
|
}
|
|
30
|
+
logger.debug(() => ({
|
|
31
|
+
msg: "Headers TLS Version:",
|
|
32
|
+
data: { xTlsVersion }
|
|
33
|
+
}));
|
|
34
|
+
const tlsVersion = xTlsVersion.replace(/(tls)|\./g, "");
|
|
35
|
+
const readableStream = new Readable({
|
|
36
|
+
read() {
|
|
37
|
+
this.push(clientHelloBuffer);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
const clientHello = await readTlsClientHello(readableStream);
|
|
41
|
+
const { alpnProtocols } = clientHello;
|
|
42
|
+
const [_tlsVersion, cipherSuites, extensions] = clientHello.fingerprintData;
|
|
43
|
+
const transport = "t";
|
|
44
|
+
const sniIndicator = xTlsServerName ? "d" : "i";
|
|
45
|
+
const validCipherSuites = cipherSuites.filter(
|
|
46
|
+
(cs) => (cs & 3855) !== 2570
|
|
47
|
+
);
|
|
48
|
+
const cipherCount = validCipherSuites.length;
|
|
49
|
+
const validExtensions = extensions.filter(
|
|
50
|
+
(ext) => (ext & 3855) !== 2570
|
|
51
|
+
);
|
|
52
|
+
const extensionCount = validExtensions.length;
|
|
53
|
+
const alpn = alpnProtocols?.length ? alpnProtocols[0] : "";
|
|
54
|
+
const alpnLabel = alpn ? `${alpn[0]}${alpn[alpn.length - 1]}` : "00";
|
|
55
|
+
const sortedCiphers = validCipherSuites.map((cs) => cs.toString(16).padStart(4, "0")).sort().join(",");
|
|
56
|
+
const cipherHash = createHash("sha256").update(sortedCiphers).digest("hex").slice(0, 12);
|
|
57
|
+
const decimalString = extensions.sort((a, b) => a - b).map((ext) => ext.toString(10)).join("-");
|
|
58
|
+
const extensionHash = createHash("sha256").update(decimalString).digest("hex").slice(0, 12);
|
|
59
|
+
const ja4PlusFingerprint = `${transport}${tlsVersion}${sniIndicator}${cipherCount}${extensionCount}${alpnLabel}_${cipherHash}_${extensionHash}`;
|
|
60
|
+
return { ja4PlusFingerprint };
|
|
61
|
+
} catch (e) {
|
|
62
|
+
logger.error(() => ({
|
|
63
|
+
msg: "Error generating JA4+ fingerprint:",
|
|
64
|
+
err: e instanceof Error ? e : new Error(String(e))
|
|
65
|
+
}));
|
|
66
|
+
return { ja4PlusFingerprint: DEFAULT_JA4 };
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const ja4Middleware = (env) => {
|
|
70
|
+
return async (req, res, next) => {
|
|
12
71
|
try {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
logger.debug(() => ({
|
|
20
|
-
msg: "ClientHello First Bytes:",
|
|
21
|
-
data: { hex: clientHelloBuffer.subarray(0, 5).toString("hex") },
|
|
22
|
-
}));
|
|
23
|
-
if (clientHelloBuffer[5] !== 0x01) {
|
|
24
|
-
logger.debug(() => ({
|
|
25
|
-
msg: "Invalid ClientHello message: First byte is not 0x01",
|
|
26
|
-
}));
|
|
27
|
-
return { ja4PlusFingerprint: DEFAULT_JA4 };
|
|
28
|
-
}
|
|
29
|
-
logger.debug(() => ({
|
|
30
|
-
msg: "Headers TLS Version:",
|
|
31
|
-
data: { xTlsVersion },
|
|
32
|
-
}));
|
|
33
|
-
const tlsVersion = xTlsVersion.replace(/(tls)|\./g, "");
|
|
34
|
-
const readableStream = new Readable({
|
|
35
|
-
read() {
|
|
36
|
-
this.push(clientHelloBuffer);
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
const clientHello = await readTlsClientHello(readableStream);
|
|
40
|
-
const { alpnProtocols } = clientHello;
|
|
41
|
-
const [_tlsVersion, cipherSuites, extensions] = clientHello.fingerprintData;
|
|
42
|
-
const transport = "t";
|
|
43
|
-
const sniIndicator = xTlsServerName ? "d" : "i";
|
|
44
|
-
const validCipherSuites = cipherSuites.filter((cs) => (cs & 0x0f0f) !== 0x0a0a);
|
|
45
|
-
const cipherCount = validCipherSuites.length;
|
|
46
|
-
const validExtensions = extensions.filter((ext) => (ext & 0x0f0f) !== 0x0a0a);
|
|
47
|
-
const extensionCount = validExtensions.length;
|
|
48
|
-
const alpn = alpnProtocols?.length ? alpnProtocols[0] : "";
|
|
49
|
-
const alpnLabel = alpn ? `${alpn[0]}${alpn[alpn.length - 1]}` : "00";
|
|
50
|
-
const sortedCiphers = validCipherSuites
|
|
51
|
-
.map((cs) => cs.toString(16).padStart(4, "0"))
|
|
52
|
-
.sort()
|
|
53
|
-
.join(",");
|
|
54
|
-
const cipherHash = createHash("sha256")
|
|
55
|
-
.update(sortedCiphers)
|
|
56
|
-
.digest("hex")
|
|
57
|
-
.slice(0, 12);
|
|
58
|
-
const decimalString = extensions
|
|
59
|
-
.sort((a, b) => a - b)
|
|
60
|
-
.map((ext) => ext.toString(10))
|
|
61
|
-
.join("-");
|
|
62
|
-
const extensionHash = createHash("sha256")
|
|
63
|
-
.update(decimalString)
|
|
64
|
-
.digest("hex")
|
|
65
|
-
.slice(0, 12);
|
|
66
|
-
const ja4PlusFingerprint = `${transport}${tlsVersion}${sniIndicator}${cipherCount}${extensionCount}${alpnLabel}_${cipherHash}_${extensionHash}`;
|
|
67
|
-
return { ja4PlusFingerprint };
|
|
68
|
-
}
|
|
69
|
-
catch (e) {
|
|
70
|
-
logger.error(() => ({
|
|
71
|
-
msg: "Error generating JA4+ fingerprint:",
|
|
72
|
-
err: e instanceof Error ? e : new Error(String(e)),
|
|
73
|
-
}));
|
|
74
|
-
return { ja4PlusFingerprint: DEFAULT_JA4 };
|
|
72
|
+
req.logger.debug(() => ({ data: { url: req.url } }));
|
|
73
|
+
const ja4 = await getJA4(req.headers, req.logger);
|
|
74
|
+
req.ja4 = ja4.ja4PlusFingerprint || "";
|
|
75
|
+
next();
|
|
76
|
+
} catch (err) {
|
|
77
|
+
return handleErrors(err, req, res, next);
|
|
75
78
|
}
|
|
79
|
+
};
|
|
76
80
|
};
|
|
77
|
-
export
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const ja4 = await getJA4(req.headers, req.logger);
|
|
82
|
-
req.ja4 = ja4.ja4PlusFingerprint || "";
|
|
83
|
-
next();
|
|
84
|
-
}
|
|
85
|
-
catch (err) {
|
|
86
|
-
return handleErrors(err, req, res, next);
|
|
87
|
-
}
|
|
88
|
-
};
|
|
81
|
+
export {
|
|
82
|
+
DEFAULT_JA4,
|
|
83
|
+
getJA4,
|
|
84
|
+
ja4Middleware
|
|
89
85
|
};
|
|
90
|
-
//# sourceMappingURL=ja4Middleware.js.map
|
package/dist/api/public.js
CHANGED
|
@@ -3,27 +3,30 @@ import { ProsopoApiError } from "@prosopo/common";
|
|
|
3
3
|
import { PublicApiPaths } from "@prosopo/types";
|
|
4
4
|
import { version } from "@prosopo/util";
|
|
5
5
|
import express from "express";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
|
|
6
|
+
function publicRouter() {
|
|
7
|
+
const router = express.Router();
|
|
8
|
+
router.get(PublicApiPaths.Healthz, (req, res) => {
|
|
9
|
+
res.status(200).send("OK");
|
|
10
|
+
});
|
|
11
|
+
router.get(PublicApiPaths.GetProviderDetails, async (req, res, next) => {
|
|
12
|
+
try {
|
|
13
|
+
return res.json({ version, ...{ message: "Provider online" } });
|
|
14
|
+
} catch (err) {
|
|
15
|
+
req.logger.error(() => ({
|
|
16
|
+
err,
|
|
17
|
+
data: { reqParams: req.params },
|
|
18
|
+
msg: "Error getting provider details"
|
|
19
|
+
}));
|
|
20
|
+
return next(
|
|
21
|
+
new ProsopoApiError("API.BAD_REQUEST", {
|
|
22
|
+
context: { code: 500 }
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
router.use(handleErrors);
|
|
28
|
+
return router;
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
+
export {
|
|
31
|
+
publicRouter
|
|
32
|
+
};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
function robotsMiddleware() {
|
|
2
|
+
return (_req, res, next) => {
|
|
3
|
+
res.setHeader("Strict-Transport-Security", "max-age=31536000;");
|
|
4
|
+
res.setHeader("X-XSS-Protection", "1; mode=block");
|
|
5
|
+
res.setHeader("X-Frame-Options", "DENY");
|
|
6
|
+
res.setHeader("X-Robots-Tag", "none");
|
|
7
|
+
next();
|
|
8
|
+
};
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
export {
|
|
11
|
+
robotsMiddleware
|
|
12
|
+
};
|
|
@@ -1,23 +1,25 @@
|
|
|
1
1
|
import { ProsopoApiError } from "@prosopo/common";
|
|
2
2
|
import { validateAddress } from "@prosopo/util-crypto";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const validateSiteKey = (siteKey, logger) => {
|
|
4
|
+
return validateAddr(siteKey, "API.INVALID_SITE_KEY", logger);
|
|
5
5
|
};
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
catch (err) {
|
|
17
|
-
throw new ProsopoApiError(translationKey, {
|
|
18
|
-
context: { code: 400, siteKey: address },
|
|
19
|
-
logger,
|
|
20
|
-
});
|
|
6
|
+
const validateAddr = (address, translationKey = "CONTRACT.INVALID_ADDRESS", logger) => {
|
|
7
|
+
try {
|
|
8
|
+
const valid = validateAddress(address, false, 42);
|
|
9
|
+
if (!valid) {
|
|
10
|
+
throw new ProsopoApiError(translationKey, {
|
|
11
|
+
context: { code: 400, siteKey: address },
|
|
12
|
+
logger
|
|
13
|
+
});
|
|
21
14
|
}
|
|
15
|
+
} catch (err) {
|
|
16
|
+
throw new ProsopoApiError(translationKey, {
|
|
17
|
+
context: { code: 400, siteKey: address },
|
|
18
|
+
logger
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export {
|
|
23
|
+
validateAddr,
|
|
24
|
+
validateSiteKey
|
|
22
25
|
};
|
|
23
|
-
//# sourceMappingURL=validateAddress.js.map
|