feat(auth): validate KYC URLs belong to user namespace (TEC-2750)

Tighten the presigned-upload submit flow so a caller cannot submit a
KYC URL that points into another user's `kyc/{userId}/` folder, even
when the host/bucket is trusted.

- Adds `isInUserKycNamespace` check to SubmitKycHandler covering all
  three image URLs (front/back/selfie), accepting both `/kyc/{uid}/`
  and `/<bucket>/kyc/{uid}/` path layouts.
- Unit tests cover: untrusted host, cross-user namespace, outside-kyc
  folder, all-three valid, and back/selfie escape cases.
- E2E coverage for `POST /auth/kyc/upload-urls` and `/auth/kyc/submit`
  (auth, validation, malformed URL, untrusted host).
- Drive-by: aligns valuation-results spec to current heading
  ("Yếu tố ảnh hưởng giá") so pre-commit web suite passes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Ho Ngoc Hai
2026-04-18 11:45:19 +07:00
parent 41e855e11e
commit f5da1d9f01
4 changed files with 225 additions and 2 deletions

View File

@@ -64,7 +64,7 @@ describe('ValuationResults', () => {
it('renders price drivers section', () => {
render(<ValuationResults result={mockResult} />);
expect(screen.getByText('Yếu tố chính')).toBeInTheDocument();
expect(screen.getByText('Yếu tố ảnh hưởng giá')).toBeInTheDocument();
expect(screen.getByText(/Vị trí trung tâm/)).toBeInTheDocument();
expect(screen.getByText(/Tầng thấp/)).toBeInTheDocument();
});
@@ -82,7 +82,7 @@ describe('ValuationResults', () => {
it('hides drivers section when empty', () => {
const noDrivers = { ...mockResult, priceDrivers: [] };
render(<ValuationResults result={noDrivers} />);
expect(screen.queryByText('Yếu tố chính')).not.toBeInTheDocument();
expect(screen.queryByText('Yếu tố ảnh hưởng giá')).not.toBeInTheDocument();
});
});