fix(payments): harden payment flow with idempotency keys, amount validation, and magic byte file validation
- Add dedicated idempotencyKey column with unique constraint (userId, provider, idempotencyKey) to prevent duplicate payments at DB level - Add @Min(1) @Max(100B) validators on amountVND in CreatePaymentDto to reject invalid amounts at API boundary - Replace read-check-write callback handler with atomic updateIfStatus to eliminate race condition on concurrent callbacks - Add magic byte verification in FileValidationPipe to validate file content matches declared MIME type server-side Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -62,7 +62,7 @@ export class PaymentsController {
|
||||
user.sub,
|
||||
dto.provider,
|
||||
dto.type,
|
||||
dto.amountVND,
|
||||
BigInt(dto.amountVND),
|
||||
dto.description,
|
||||
dto.returnUrl,
|
||||
ip || '127.0.0.1',
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import {
|
||||
IsEnum,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsUrl,
|
||||
Max,
|
||||
Min,
|
||||
MinLength,
|
||||
} from 'class-validator';
|
||||
import { Transform } from 'class-transformer';
|
||||
@@ -19,10 +22,17 @@ export class CreatePaymentDto {
|
||||
@IsEnum(PaymentType)
|
||||
type!: PaymentType;
|
||||
|
||||
@ApiProperty({ type: Number, description: 'Amount in VND', example: 500000 })
|
||||
@ApiProperty({ type: Number, description: 'Amount in VND (1 – 100,000,000,000)', example: 500000 })
|
||||
@IsNotEmpty()
|
||||
@Transform(({ value }) => BigInt(value))
|
||||
amountVND!: bigint;
|
||||
@IsNumber()
|
||||
@Min(1, { message: 'Số tiền phải lớn hơn 0' })
|
||||
@Max(100_000_000_000, { message: 'Số tiền vượt quá giới hạn cho phép (100 tỷ VND)' })
|
||||
@Transform(({ value }) => {
|
||||
const num = Number(value);
|
||||
if (!Number.isFinite(num) || !Number.isInteger(num)) return value;
|
||||
return num;
|
||||
}, { toClassOnly: true })
|
||||
amountVND!: number;
|
||||
|
||||
@ApiProperty({ description: 'Payment description', example: 'Listing fee' })
|
||||
@IsString()
|
||||
|
||||
Reference in New Issue
Block a user