Fixed captcha for prod

This commit is contained in:
SepehrYahyaee
2026-05-31 16:15:55 +03:30
parent 02a69f3db2
commit e90c6a5c50
2 changed files with 14 additions and 32 deletions

View File

@@ -12,49 +12,40 @@ import { HashService } from "src/utils/hash/hash.service";
@Injectable() @Injectable()
export class CaptchaChallengeService { export class CaptchaChallengeService {
private readonly isDev: boolean;
constructor( constructor(
private readonly captchaService: CaptchaService, private readonly captchaService: CaptchaService,
private readonly hashService: HashService, private readonly hashService: HashService,
private readonly captchaChallengeDbService: CaptchaChallengeDbService, private readonly captchaChallengeDbService: CaptchaChallengeDbService,
private readonly configService: ConfigService, private readonly configService: ConfigService,
) {} ) {
this.isDev = this.configService.get<string>("NODE_ENV") === "development";
}
async issue(): Promise<CaptchaResponseDto> { async issue(): Promise<CaptchaResponseDto> {
const generated = this.captchaService.generate(); const generated = this.captchaService.generate();
const captchaId = randomUUID(); const captchaId = randomUUID();
if (this.configService.get<string>("NODE_ENV") === "development") { // Always hash and persist the answer — the env check was the root bug
const answerHash = await this.hashService.hash( const answerHash = await this.hashService.hash(
this.captchaService.normalizeAnswer(generated.text), this.captchaService.normalizeAnswer(generated.text),
); );
const result = {
await this.captchaChallengeDbService.create({
captchaId, captchaId,
answerHash: answerHash,
this.configService.get<string>("NODE_ENV") === "development"
? answerHash
: "",
image: generated.image, image: generated.image,
expiresAt: generated.expiresAt, expiresAt: generated.expiresAt,
expireAt: new Date(generated.expiresAt), expireAt: new Date(generated.expiresAt),
usedAt: null, usedAt: null,
}; });
}
const result = {
captchaId,
image: generated.image,
expiresAt: generated.expiresAt,
expireAt: new Date(generated.expiresAt),
usedAt: null,
};
await this.captchaChallengeDbService.create(result);
return { return {
captchaId, captchaId,
text: generated.text /* TODO: REMOVE THIS FOR PROD*/,
image: generated.image, image: generated.image,
expiresAt: generated.expiresAt, expiresAt: generated.expiresAt,
...(this.isDev && { text: generated.text }),
}; };
} }

View File

@@ -3,15 +3,13 @@ import { ConfigService } from "@nestjs/config";
import * as svgCaptcha from "svg-captcha"; import * as svgCaptcha from "svg-captcha";
export interface GeneratedCaptcha { export interface GeneratedCaptcha {
text?: string; text: string;
image: string; image: string;
expiresAt: number; expiresAt: number;
} }
@Injectable() @Injectable()
export class CaptchaService { export class CaptchaService {
constructor(private readonly configService: ConfigService) {}
generate(): GeneratedCaptcha { generate(): GeneratedCaptcha {
const captcha = svgCaptcha.create({ const captcha = svgCaptcha.create({
size: 5, size: 5,
@@ -24,13 +22,6 @@ export class CaptchaService {
fontSize: 52, fontSize: 52,
}); });
if (this.configService.get<string>("NODE_ENV") === "production") {
return {
image: `data:image/svg+xml;base64,${Buffer.from(captcha.data, "utf8").toString("base64")}`,
expiresAt: this.buildExpireAt(),
};
}
return { return {
text: captcha.text, text: captcha.text,
image: `data:image/svg+xml;base64,${Buffer.from(captcha.data, "utf8").toString("base64")}`, image: `data:image/svg+xml;base64,${Buffer.from(captcha.data, "utf8").toString("base64")}`,