# Kiểm Tra Bảo Mật Module Thanh Toán GoodGo Platform - Danh Sách File ## Tổng Quan Danh sách file toàn diện cho đợt kiểm tra bảo mật các thực thể Order & Escrow trong module thanh toán. Vị trí: `/Users/velikho/Desktop/WORKING/goodgo-platform-ai/apps/api/src/modules/payments/` --- ## 1. TẦNG DOMAIN - CÁC THỰC THỂ ### Các Thực Thể Cốt Lõi | File | Mô tả | |------|-------| | `domain/entities/order.entity.ts` | **THỰC THỂ ORDER** - Quản lý vòng đời đơn hàng với máy trạng thái (CREATED→PAYMENT_PENDING→PAYMENT_CONFIRMED→ESCROW_HELD→SHIPPED→DELIVERED→ESCROW_RELEASED→COMPLETED). Xác thực các chuyển trạng thái. Phát sự kiện: OrderCreatedEvent, OrderPaidEvent, OrderCancelledEvent. Các trường quan trọng: buyerId, sellerId, listingId, amount (Money VO), platformFee, sellerPayout. | | `domain/entities/escrow.entity.ts` | **THỰC THỂ ESCROW** - Quản lý vòng đời escrow (PENDING→HELD→RELEASED/DISPUTED/REFUNDED). Lưu trữ số tiền escrow, phí và netPayout đã tính. Phát: EscrowHeldEvent, EscrowReleasedEvent, EscrowDisputedEvent. Xác thực chuyển trạng thái. | | `domain/entities/payment.entity.ts` | **THỰC THỂ PAYMENT** - Quản lý giao dịch thanh toán (PENDING→PROCESSING→COMPLETED/FAILED/REFUNDED). Lưu trữ userId, provider (VNPAY/MOMO/ZALOPAY), type, amount, callbackData, idempotencyKey. Phát: PaymentCreatedEvent, PaymentCompletedEvent, PaymentFailedEvent, PaymentRefundedEvent. | ### Các Value Object | File | Mô tả | |------|-------| | `domain/value-objects/money.vo.ts` | **VALUE OBJECT MONEY** - Bọc các số tiền dưới dạng bigint theo VND. Xác thực: amount > 0, giới hạn tối đa 999_999_999_999. Dùng cho tất cả các số tiền tài chính. | | `domain/value-objects/platform-fee.vo.ts` | **VALUE OBJECT PHÍ NỀN TẢNG** - Tính phí nền tảng 5%. Các phương thức: `fromOrderAmount()` (tự động tính 5%), `create()` (số tiền tường minh). Xác thực fee >= 0. | --- ## 2. TẦNG DOMAIN - REPOSITORY (Giao Diện) | File | Mô tả | |------|-------| | `domain/repositories/order.repository.ts` | **GIAO DIỆN ORDER REPOSITORY** - Định nghĩa các phương thức CRUD + truy vấn: findById, findByIdempotencyKey, findByBuyerId, findBySellerId, save, update. Bảo vệ idempotency. | | `domain/repositories/escrow.repository.ts` | **GIAO DIỆN ESCROW REPOSITORY** - Định nghĩa: findById, findByOrderId, save, update. Quan hệ một escrow trên một order. | | `domain/repositories/payment.repository.ts` | **GIAO DIỆN PAYMENT REPOSITORY** - Định nghĩa: findById, findByProviderTxId, findByIdempotencyKey, findByUserId, save, update, **updateIfStatus** (cập nhật có điều kiện nguyên tử để xử lý race condition). | --- ## 3. TẦNG DOMAIN - SỰ KIỆN | File | Mô tả | |------|-------| | `domain/events/order-created.event.ts` | Phát khi tạo order - chứa orderId, buyerId, sellerId, listingId, amount | | `domain/events/order-paid.event.ts` | Phát khi thanh toán được xác nhận - chứa orderId, buyerId, amount | | `domain/events/order-cancelled.event.ts` | Phát khi order bị hủy - chứa orderId, buyerId, sellerId | | `domain/events/escrow-held.event.ts` | Phát khi escrow được giữ - chứa escrowId, orderId, amount | | `domain/events/escrow-released.event.ts` | Phát khi escrow được giải phóng - chứa escrowId, orderId, netPayout | | `domain/events/escrow-disputed.event.ts` | Phát khi escrow bị tranh chấp - chứa escrowId, orderId, reason | | `domain/events/payment-created.event.ts` | Phát khi tạo thanh toán - chứa paymentId, userId, provider, amount | | `domain/events/payment-completed.event.ts` | Phát khi thanh toán hoàn tất - chứa paymentId, userId, provider | | `domain/events/payment-failed.event.ts` | Phát khi thanh toán thất bại - chứa paymentId, userId, provider | | `domain/events/payment-refunded.event.ts` | Phát khi thanh toán được hoàn tiền - chứa paymentId, userId, provider, amount | --- ## 4. TẦNG CƠ SỞ HẠ TẦNG - REPOSITORY (Triển Khai) | File | Mô tả | |------|-------| | `infrastructure/repositories/prisma-order.repository.ts` | **TRIỂN KHAI ORDER REPOSITORY** - Triển khai Prisma ORM. Lưu trữ: id, buyerId, sellerId, listingId, status, amountVND, platformFeeVND, sellerPayoutVND, idempotencyKey, metadata. Xử lý lưu trữ order. | | `infrastructure/repositories/prisma-escrow.repository.ts` | **TRIỂN KHAI ESCROW REPOSITORY** - Triển khai Prisma ORM. Lưu trữ: id, orderId, amountVND, feeVND, status, heldAt, releasedAt, disputeReason, disputedAt. Xử lý lưu trữ escrow. | | `infrastructure/repositories/prisma-payment.repository.ts` | **TRIỂN KHAI PAYMENT REPOSITORY** - Prisma ORM. Lưu trữ: id, userId, transactionId, provider, type, amountVND, status, providerTxId, callbackData, idempotencyKey. **QUAN TRỌNG: `updateIfStatus()` sử dụng mệnh đề WHERE có điều kiện để ngăn race condition nguyên tử** (Dòng 84-109). | --- ## 5. TẦNG CƠ SỞ HẠ TẦNG - DỊCH VỤ CỔNG THANH TOÁN ### Giao Diện Cổng Thanh Toán | File | Mô tả | |------|-------| | `infrastructure/services/payment-gateway.interface.ts` | **GIAO DIỆN GATEWAY** - Định nghĩa hợp đồng IPaymentGateway: createPaymentUrl(), verifyCallback(), refund(). CallbackVerifyResult bao gồm: isValid, orderId, providerTxId, isSuccess, rawData. Nhạy cảm về bảo mật. | ### Dịch Vụ VNPay | File | Mô tả | |------|-------| | `infrastructure/services/vnpay.service.ts` | **CỔNG THANH TOÁN VNPAY** - Triển khai IPaymentGateway. **XÁC MINH CALLBACK (Dòng 72-105)**: Trích xuất secure hash, loại bỏ khỏi dữ liệu, sắp xếp các tham số, tạo HMAC-SHA512, dùng crypto.timingSafeEqual() để so sánh thời gian cố định. Số tiền nhân 100 cho VND cents. Trả về isValid, orderId (vnp_TxnRef), providerTxId (vnp_TransactionNo), isSuccess (responseCode === '00'). Hỗ trợ hoàn tiền. | ### Dịch Vụ MoMo | File | Mô tả | |------|-------| | `infrastructure/services/momo.service.ts` | **CỔNG THANH TOÁN MOMO** - Triển khai IPaymentGateway. **XÁC MINH CALLBACK (Dòng 102-147)**: Trích xuất chữ ký từ dữ liệu, xây dựng lại chữ ký thô với accessKey, amount, extraData, IPN/redirect URLs, orderId, v.v. Dùng HMAC-SHA256, so sánh thời gian cố định qua crypto.timingSafeEqual(). Kiểm tra thành công: resultCode === '0'. Hỗ trợ hoàn tiền. Amount dưới dạng Number (không phải bigint trong API). | ### Dịch Vụ ZaloPay | File | Mô tả | |------|-------| | `infrastructure/services/zalopay.service.ts` | **CỔNG THANH TOÁN ZALOPAY** - Triển khai IPaymentGateway. **XÁC MINH CALLBACK (Dòng 98-144)**: Dữ liệu được truyền dưới dạng chuỗi JSON trong trường 'data'. MAC được xác minh qua HMAC-SHA256 với key2. Phân tích dữ liệu JSON để trích xuất app_trans_id và zp_trans_id. **LƯU Ý BẢO MẬT**: Xử lý lỗi phân tích JSON một cách duyên dáng. Dùng so sánh thời gian cố định. Hỗ trợ hoàn tiền (key1). | ### Factory Cổng Thanh Toán | File | Mô tả | |------|-------| | `infrastructure/services/payment-gateway.factory.ts` | **GATEWAY FACTORY** - Trả về instance gateway phù hợp (VNPay/MoMo/ZaloPay) dựa trên enum provider. | --- ## 6. TẦNG ỨNG DỤNG - COMMAND ### Các Order Command | File | Mô tả | |------|-------| | `application/commands/create-order/create-order.command.ts` | **CREATE ORDER COMMAND** - Đầu vào: buyerId, sellerId, listingId, amountVND, idempotencyKey. Đối tượng payload. | | `application/commands/create-order/create-order.handler.ts` | **CREATE ORDER HANDLER** - Kiểm tra idempotency qua findByIdempotencyKey. Xác thực amount (Money VO). Tính phí nền tảng (5%) và seller payout. Tạo OrderEntity + EscrowEntity (trạng thái PENDING). Lưu cả hai. Phát sự kiện. | | `application/commands/cancel-order/cancel-order.command.ts` | **CANCEL ORDER COMMAND** - Đầu vào: orderId, userId, reason. | | `application/commands/cancel-order/cancel-order.handler.ts` | **CANCEL ORDER HANDLER** - Xác minh người dùng sở hữu order, xác thực chuyển trạng thái qua entity.markCancelled(), lưu, phát sự kiện. | ### Các Escrow Command | File | Mô tả | |------|-------| | `application/commands/hold-escrow/hold-escrow.command.ts` | **HOLD ESCROW COMMAND** - Đầu vào: orderId. Chỉ dành cho Admin. | | `application/commands/hold-escrow/hold-escrow.handler.ts` | **HOLD ESCROW HANDLER (Dòng 23-67)** - Lấy order + escrow theo orderId. Gọi escrow.hold() để chuyển trạng thái. Cập nhật cả hai thực thể. Phát EscrowHeldEvent. **LƯU Ý BẢO MẬT**: Không có Redis lock - tiềm ẩn race condition nếu có nhiều yêu cầu đồng thời. | | `application/commands/release-escrow/release-escrow.command.ts` | **RELEASE ESCROW COMMAND** - Đầu vào: orderId. Chỉ dành cho Admin. | | `application/commands/release-escrow/release-escrow.handler.ts` | **RELEASE ESCROW HANDLER (Dòng 24-45)** - Lấy order + escrow theo orderId. Gọi escrow.release() để chuyển trạng thái. Cập nhật cả hai thực thể. Phát EscrowReleasedEvent với netPayout. **LƯU Ý BẢO MẬT**: Không có Redis lock - tiềm ẩn race condition. | ### Các Payment Command | File | Mô tả | |------|-------| | `application/commands/create-payment/create-payment.command.ts` | **CREATE PAYMENT COMMAND** - Đầu vào: userId, provider, type, amountVND, description, returnUrl, ipAddress, transactionId, idempotencyKey. | | `application/commands/create-payment/create-payment.handler.ts` | **CREATE PAYMENT HANDLER** - Kiểm tra idempotency. Xác thực amount (Money VO). Lấy payment gateway. Gọi createPaymentUrl(). Tạo PaymentEntity (trạng thái PENDING). Lưu. Phát PaymentCreatedEvent. Trả về paymentUrl để frontend chuyển hướng. | | `application/commands/refund-payment/refund-payment.command.ts` | **REFUND PAYMENT COMMAND** - Đầu vào: paymentId, reason, userId. Lệnh dành cho Admin. | | `application/commands/refund-payment/refund-payment.handler.ts` | **REFUND PAYMENT HANDLER** - Xác minh thanh toán tồn tại, gọi gateway.refund() với các tham số đặc thù nhà cung cấp, cập nhật trạng thái thanh toán thành REFUNDED, phát PaymentRefundedEvent. | ### Handler Callback (QUAN TRỌNG) | File | Mô tả | |------|-------| | `application/commands/handle-callback/handle-callback.command.ts` | **HANDLE CALLBACK COMMAND** - Đầu vào: provider (enum PaymentProvider), callbackData (Record). | | `application/commands/handle-callback/handle-callback.handler.ts` | **HANDLE CALLBACK HANDLER (Dòng 32-110)** - **FILE BẢO MẬT QUAN TRỌNG**. Lấy gateway, gọi verifyCallback() (xác thực chữ ký). Nếu không hợp lệ: ném ValidationException. Nếu hợp lệ: **Dùng `paymentRepo.updateIfStatus()` với WHERE có điều kiện ['PENDING', 'PROCESSING']** (Dòng 48-55) - cập nhật nguyên tử để ngăn xử lý trùng lặp. Nếu cập nhật trả về null: kiểm tra xem thanh toán có tồn tại không (đã xử lý - phản hồi idempotent). Nếu thành công: gọi payment.emitCompleted(), ngược lại payment.emitFailed(). Phát sự kiện. **BẢO VỆ RACE CONDITION MẠNH qua cập nhật có điều kiện**. | --- ## 7. TẦNG ỨNG DỤNG - QUERY | File | Mô tả | |------|-------| | `application/queries/get-order-status/get-order-status.query.ts` | Query: Đầu vào orderId, userId (để phân quyền). | | `application/queries/get-order-status/get-order-status.handler.ts` | Lấy order, xác minh quyền sở hữu (buyer/seller), trả về trạng thái + chi tiết. | | `application/queries/get-payment-status/get-payment-status.query.ts` | Query: Đầu vào paymentId, userId. | | `application/queries/get-payment-status/get-payment-status.handler.ts` | Lấy thanh toán, xác minh quyền sở hữu, trả về trạng thái + chi tiết. | | `application/queries/list-transactions/list-transactions.query.ts` | Query: Đầu vào userId, status (tùy chọn), limit, offset. | | `application/queries/list-transactions/list-transactions.handler.ts` | Liệt kê các thanh toán của người dùng với phân trang, lọc theo status nếu được cung cấp. | --- ## 8. TẦNG TRÌNH BÀY - CONTROLLER | File | Mô tả | |------|-------| | `presentation/controllers/orders.controller.ts` | **ORDERS CONTROLLER** - Các route: POST / (tạo order), GET /:id (trạng thái), POST /:id/cancel (hủy), POST /:id/escrow/hold (admin), POST /:id/escrow/release (admin). Xác thực: JwtAuthGuard, RolesGuard cho các thao tác admin. Chuyển đổi DTO thành command. | | `presentation/controllers/payments.controller.ts` | **PAYMENTS CONTROLLER** - Các route: POST / (tạo thanh toán), POST /callback/:provider (webhook - **Throttle + EndpointRateLimit**), GET /:id (trạng thái), GET (danh sách), POST /:id/refund (admin hoàn tiền). **QUAN TRỌNG: Endpoint callback có giới hạn tốc độ (Throttle + EndpointRateLimitGuard)** - ngăn chặn lũ lụt callback. | --- ## 9. TẦNG TRÌNH BÀY - DTO | File | Mô tả | |------|-------| | `presentation/dto/create-order.dto.ts` | DTO: sellerId, listingId, amountVND (string), idempotencyKey (tùy chọn). | | `presentation/dto/cancel-order.dto.ts` | DTO: reason (string). | | `presentation/dto/create-payment.dto.ts` | DTO: provider (enum), type (enum), amountVND (string), description, returnUrl, transactionId (tùy chọn), idempotencyKey (tùy chọn). | | `presentation/dto/refund-payment.dto.ts` | DTO: reason (string). | | `presentation/dto/list-transactions.dto.ts` | DTO: status (tùy chọn), limit, offset. | --- ## 10. MODULE & CÁC FILE KIỂM THỬ | File | Mô tả | |------|-------| | `payments.module.ts` | **CÀI ĐẶT MODULE** - Đăng ký các repository, service, handler, controller. | | `index.ts` (cấp module) | Xuất API công khai. | | `infrastructure/repositories/index.ts` | Xuất các triển khai repository. | | `infrastructure/services/index.ts` | Xuất các dịch vụ gateway. | | `application/index.ts` | Xuất các handler command/query. | | `domain/repositories/index.ts` | Xuất các giao diện repository. | | `domain/entities/index.ts` | Xuất các thực thể. | | `domain/value-objects/index.ts` | Xuất các VO. | | `domain/events/index.ts` | Xuất các sự kiện domain. | | `presentation/controllers/index.ts` | Xuất các controller. | | `presentation/dto/index.ts` | Xuất các DTO. | ### Các File Kiểm Thử | File | Mô tả | |------|-------| | `domain/__tests__/order.entity.spec.ts` | Kiểm thử đơn vị thực thể Order - máy trạng thái, các chuyển trạng thái | | `domain/__tests__/escrow.entity.spec.ts` | Kiểm thử đơn vị thực thể Escrow - hold, release, dispute, refund | | `domain/__tests__/payment.entity.spec.ts` | Kiểm thử đơn vị thực thể Payment | | `domain/__tests__/money.vo.spec.ts` | Kiểm thử xác thực Money VO | | `domain/__tests__/platform-fee.vo.spec.ts` | Kiểm thử tính toán phí nền tảng | | `domain/__tests__/payment-events.spec.ts` | Kiểm thử phát sự kiện domain | | `application/__tests__/create-order.handler.spec.ts` | Kiểm thử handler tạo order | | `application/__tests__/create-payment.handler.spec.ts` | Kiểm thử handler tạo thanh toán | | `application/__tests__/handle-callback.handler.spec.ts` | Kiểm thử xử lý callback | | `application/__tests__/handle-callback-edge-cases.handler.spec.ts` | Kiểm thử các trường hợp biên callback (race condition, idempotency) | | `application/__tests__/get-payment-status.handler.spec.ts` | Kiểm thử query trạng thái thanh toán | | `application/__tests__/refund-payment.handler.spec.ts` | Kiểm thử lệnh hoàn tiền | | `application/__tests__/list-transactions.handler.spec.ts` | Kiểm thử query danh sách giao dịch | | `infrastructure/__tests__/vnpay.service.spec.ts` | Kiểm thử gateway VNPay - xác minh chữ ký | | `infrastructure/__tests__/momo.service.spec.ts` | Kiểm thử gateway MoMo - xác minh HMAC-SHA256 | | `infrastructure/__tests__/zalopay.service.spec.ts` | Kiểm thử gateway ZaloPay - phân tích JSON + xác minh MAC | | `infrastructure/__tests__/payment-gateway.factory.spec.ts` | Kiểm thử mẫu factory | --- ## TÓM TẮT KẾT QUẢ BẢO MẬT ### ✅ CÁC BIỆN PHÁP BẢO MẬT MẠNH 1. **Xác Minh Chữ Ký Callback**: Cả 3 nhà cung cấp (VNPay, MoMo, ZaloPay) đều xác minh chữ ký HMAC sử dụng `crypto.timingSafeEqual()` để so sánh thời gian cố định 2. **Ngăn Chặn Race Condition Nguyên Tử**: `paymentRepo.updateIfStatus()` sử dụng mệnh đề WHERE có điều kiện để cập nhật nguyên tử chỉ khi ở trạng thái PENDING/PROCESSING 3. **Bảo Vệ Idempotency**: Order + Payment kiểm tra idempotencyKey để ngăn chặn các thao tác trùng lặp 4. **Giới Hạn Tốc Độ**: Endpoint callback có decorator Throttle + EndpointRateLimit 5. **Phân Quyền**: Tất cả endpoint yêu cầu JwtAuthGuard; các thao tác admin yêu cầu RolesGuard 6. **Xác Thực Số Tiền**: Money VO xác thực: 0 < amount ≤ 999_999_999_999 VND 7. **Xác Thực Máy Trạng Thái**: Order + Escrow thực thi các chuyển trạng thái hợp lệ ### ⚠️ VẤN ĐỀ BẢO MẬT (CẦN KIỂM TRA) 1. **Race Condition Hold/Release Escrow**: Không có Redis lock trên các handler hold-escrow/release-escrow - các yêu cầu đồng thời có thể gây ra sự không nhất quán trạng thái 2. **Không Có Cơ Chế Khóa Phân Tán**: Các thao tác escrow không được bảo vệ trước các yêu cầu đồng thời từ các máy chủ khác nhau 3. **Idempotency Xử Lý Callback**: Mặc dù paymentRepo.updateIfStatus() ngăn xử lý hai lần, kiểm tra idempotency không xác minh tính nhất quán của chữ ký callback 4. **Bí Mật Nhà Cung Cấp Thanh Toán**: Các khóa được tải từ ConfigService - xác minh mã hóa biến môi trường khi lưu trữ 5. **Phân Quyền Hoàn Tiền**: Chỉ kiểm tra vai trò ADMIN - không có xác thực logic nghiệp vụ (ví dụ: thời hạn hoàn tiền, số tiền hoàn tiền tối đa) 6. **Race Update Order/Escrow**: Mặc dù hold là nguyên tử đối với thanh toán, cập nhật order + escrow trong handler được thực hiện tuần tự (2 lần gọi DB), không nguyên tử --- ## CÁC FILE KHÔNG TÌM THẤY / NGOÀI PHẠM VI - ❌ **Sử Dụng Redis Lock**: Không tìm thấy Redis lock trong module thanh toán. MỐI LO NGẠI: Quan trọng cho escrow hold/release. - ❌ **Tiện Ích Thanh Toán Dùng Chung**: Không có module tiện ích thanh toán bên ngoài nào được tham chiếu - ❌ **Mã Hóa Dữ Liệu Thanh Toán**: Không có mã hóa cấp trường cho dữ liệu thanh toán nhạy cảm (mặc dù dịch vụ field-encryption tồn tại trong module shared)