Skip to content

Commit 323cfd3

Browse files
committed
feat: added altcha support to form-api
1 parent d1ecbc5 commit 323cfd3

1 file changed

Lines changed: 58 additions & 0 deletions

File tree

src/form-api/src/controller/submit.controller.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
Param,
77
Body,
88
Logger,
9+
Ip,
910
} from '@nestjs/common';
1011
import {
1112
ApiBadRequestResponse,
@@ -42,12 +43,32 @@ export class CaptchaResponse {
4243
response: string;
4344
}
4445

46+
export class AltchaResponse {
47+
@ApiProperty({ description: 'The verification data', required: false })
48+
verificationData?: string;
49+
@ApiProperty({ description: 'The signature' })
50+
signature: string;
51+
@ApiProperty({ description: 'The time of verification', required: false })
52+
time?: number;
53+
@ApiProperty({ description: 'The challenge', required: false })
54+
challenge?: string;
55+
@ApiProperty({ description: 'The algorithm', required: false })
56+
algorithm?: string;
57+
@ApiProperty({ description: 'The salt', required: false })
58+
salt?: string;
59+
}
60+
4561
export class SubmitRequest {
4662
@ApiProperty({
4763
description: 'The captcha response, if required.',
4864
required: false,
4965
})
5066
captcha?: CaptchaResponse;
67+
@ApiProperty({
68+
description: 'The altcha response, if required.',
69+
required: false,
70+
})
71+
altchaData?: AltchaResponse;
5172
@ApiProperty({ description: 'The form data to submit' })
5273
data: any;
5374
}
@@ -95,6 +116,7 @@ export class SubmitController {
95116
async getCaptcha(
96117
@Param('id') id: string,
97118
@Body() body: SubmitRequest,
119+
@Ip() ip: string,
98120
): Promise<{ success: boolean }> {
99121
const email = process.env[`CFG_${id}_EMAIL`];
100122
if (!email)
@@ -128,6 +150,42 @@ export class SubmitController {
128150
HttpStatus.PAYLOAD_TOO_LARGE,
129151
);
130152

153+
// Altcha validation, if required
154+
const altchaUrl = process.env[`CFG_${id}_ALTCHA_VERIFY_URL`];
155+
if (altchaUrl) {
156+
if (!body.altchaData || !body.altchaData.signature) {
157+
throw new HttpException(
158+
'Malformed or missing altcha response',
159+
HttpStatus.UNAUTHORIZED,
160+
);
161+
}
162+
163+
const altchaDomain = process.env[`CFG_${id}_ALTCHA_DOMAIN`];
164+
165+
try {
166+
const verifyRes = await axios.post(altchaUrl, {
167+
domain: altchaDomain,
168+
verificationData: body.altchaData.verificationData,
169+
signature: body.altchaData.signature,
170+
time: body.altchaData.time,
171+
ip: ip,
172+
});
173+
174+
if (!verifyRes.data || verifyRes.data.valid !== true) {
175+
throw new HttpException(
176+
'Invalid altcha response',
177+
HttpStatus.FORBIDDEN,
178+
);
179+
}
180+
} catch (err: any) {
181+
this.log.error(`Altcha verification failed for ${id}: ${err.message}`);
182+
throw new HttpException(
183+
'Invalid altcha response',
184+
HttpStatus.FORBIDDEN,
185+
);
186+
}
187+
}
188+
131189
// Captcha validation, if required
132190
const secret = process.env[`CFG_${id}_CAPTCHA_SECRET`];
133191
if (secret) {

0 commit comments

Comments
 (0)