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