Skip to content

Commit 33b4c78

Browse files
committed
improve captcha validation and error logging in AuthService
1 parent 62ba866 commit 33b4c78

File tree

3 files changed

+45
-47
lines changed

3 files changed

+45
-47
lines changed

packages/apps/job-launcher/server/src/common/utils/hcaptcha.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import axios from 'axios';
2+
import { formatAxiosError } from './http';
23

34
export async function verifyToken(
45
url: string,
@@ -17,11 +18,18 @@ export async function verifyToken(
1718
queryParams.remoteip = ip;
1819
}
1920

20-
const { data } = await axios.post(
21-
`${url}/siteverify`,
22-
{},
23-
{ params: queryParams },
24-
);
21+
try {
22+
const { data } = await axios.post(
23+
`${url}/siteverify`,
24+
{},
25+
{ params: queryParams },
26+
);
2527

26-
return data;
28+
return data;
29+
} catch (error) {
30+
return {
31+
success: false,
32+
error: formatAxiosError(error),
33+
};
34+
}
2735
}

packages/apps/job-launcher/server/src/common/utils/slack.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import axios from 'axios';
22

33
import logger from '../../logger';
4+
import { formatAxiosError } from './http';
45

56
const slackLogger = logger.child({ context: 'sendSlackNotification' });
67

@@ -21,7 +22,10 @@ export async function sendSlackNotification(
2122
slackLogger.debug('Slack notification sent', payload);
2223
return true;
2324
} catch (error) {
24-
slackLogger.error('Error sending Slack notification', error);
25+
slackLogger.error(
26+
'Error sending Slack notification',
27+
formatAxiosError(error),
28+
);
2529
return false;
2630
}
2731
}

packages/apps/job-launcher/server/src/modules/auth/auth.service.ts

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable @typescript-eslint/no-non-null-assertion */
2-
import { Injectable } from '@nestjs/common';
2+
import { Injectable, Logger } from '@nestjs/common';
33
import { JwtService } from '@nestjs/jwt';
44

55
import { ErrorAuth, ErrorUser } from '../../common/constants/errors';
@@ -39,6 +39,8 @@ import { ApiKeyRepository } from './apikey.repository';
3939

4040
@Injectable()
4141
export class AuthService {
42+
private readonly logger = new Logger(AuthService.name);
43+
4244
constructor(
4345
private readonly jwtService: JwtService,
4446
private readonly userService: UserService,
@@ -80,19 +82,7 @@ export class AuthService {
8082
}
8183

8284
public async signup(data: UserCreateDto, ip?: string): Promise<UserEntity> {
83-
if (
84-
!(
85-
await verifyToken(
86-
this.authConfigService.hcaptchaProtectionUrl,
87-
this.authConfigService.hCaptchaSiteKey,
88-
this.authConfigService.hCaptchaSecret,
89-
data.hCaptchaToken,
90-
ip,
91-
)
92-
).success
93-
) {
94-
throw new ForbiddenError(ErrorAuth.InvalidCaptchaToken);
95-
}
85+
await this.ensureCaptchaValid(data.hCaptchaToken, ip);
9686
const storedUser = await this.userRepository.findByEmail(data.email);
9787
if (storedUser) {
9888
throw new ConflictError(ErrorUser.DuplicatedEmail);
@@ -185,19 +175,7 @@ export class AuthService {
185175
data: ForgotPasswordDto,
186176
ip?: string,
187177
): Promise<void> {
188-
if (
189-
!(
190-
await verifyToken(
191-
this.authConfigService.hcaptchaProtectionUrl,
192-
this.authConfigService.hCaptchaSiteKey,
193-
this.authConfigService.hCaptchaSecret,
194-
data.hCaptchaToken,
195-
ip,
196-
)
197-
).success
198-
) {
199-
throw new ForbiddenError(ErrorAuth.InvalidCaptchaToken);
200-
}
178+
await this.ensureCaptchaValid(data.hCaptchaToken, ip);
201179
const userEntity = await this.userRepository.findByEmail(data.email);
202180

203181
if (!userEntity) {
@@ -245,19 +223,7 @@ export class AuthService {
245223
data: RestorePasswordDto,
246224
ip?: string,
247225
): Promise<void> {
248-
if (
249-
!(
250-
await verifyToken(
251-
this.authConfigService.hcaptchaProtectionUrl,
252-
this.authConfigService.hCaptchaSiteKey,
253-
this.authConfigService.hCaptchaSecret,
254-
data.hCaptchaToken,
255-
ip,
256-
)
257-
).success
258-
) {
259-
throw new ForbiddenError(ErrorAuth.InvalidCaptchaToken);
260-
}
226+
await this.ensureCaptchaValid(data.hCaptchaToken, ip);
261227

262228
const tokenEntity = await this.tokenRepository.findOneByUuidAndType(
263229
data.token,
@@ -426,4 +392,24 @@ export class AuthService {
426392

427393
return null;
428394
}
395+
396+
private async ensureCaptchaValid(token: string, ip?: string): Promise<void> {
397+
const verification = await verifyToken(
398+
this.authConfigService.hcaptchaProtectionUrl,
399+
this.authConfigService.hCaptchaSiteKey,
400+
this.authConfigService.hCaptchaSecret,
401+
token,
402+
ip,
403+
);
404+
405+
if (verification.success) {
406+
return;
407+
}
408+
409+
this.logger.error(ErrorAuth.InvalidCaptchaToken, {
410+
error: verification.error,
411+
});
412+
413+
throw new ForbiddenError(ErrorAuth.InvalidCaptchaToken);
414+
}
429415
}

0 commit comments

Comments
 (0)