Skip to content

[FEAT] Provider Identity Document Upload & Watermarking Pipeline #377

Description

@jotel-dev

[FEAT] Provider Identity Document Upload & Watermarking Pipeline

telegram link : t.me/nullifiersystem


1. Summary & Core Promise

Velo's provider onboarding workflow in apps/api/src/routes/provider.ts allows liquidity providers to register and upload identity documents for verification. Currently, uploaded documents are stored in raw format without content validation, signature verification, or watermarking, posing security risks if administrative storage accounts are audited or inspected.

This feature implements a Provider Identity Document Upload & Watermarking Pipeline. It adds server-side image format signature validation (JPEG, PNG, WebP up to 5 MB), dynamic cryptographic watermarking ("FOR VELO VERIFICATION ONLY"), encrypted storage in apps/api/src/lib/provider-verification-store.ts, PostgreSQL transaction locking (SELECT FOR UPDATE), and restricted admin document retrieval endpoints.


2. Background & Architectural Risks

  • Malicious Payload Injection: Allowing arbitrary document file uploads without inspecting magic number byte signatures exposes backend storage to remote code execution or file inclusion vulnerabilities.
  • Identity Document Leakage: Storing un-watermarked identity documents allows compromised administrative channels to leak sensitive provider identity cards.
  • Race Condition Upload Overwrites: Concurrent uploads for the same provider profile could overwrite pending document reviews without database locking.

3. Database Layer Specifications

Migration SQL (014_add_provider_document_watermarks.sql)

CREATE TYPE document_review_status AS ENUM ('PENDING', 'APPROVED', 'REJECTED');

CREATE TABLE provider_verification_documents (
    document_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    provider_id VARCHAR(64) NOT NULL REFERENCES provider_profiles(id) ON DELETE CASCADE,
    file_name VARCHAR(255) NOT NULL,
    mime_type VARCHAR(50) NOT NULL,
    file_size_bytes INT NOT NULL,
    watermarked_hash VARCHAR(64) NOT NULL,
    storage_path VARCHAR(512) NOT NULL,
    status document_review_status NOT NULL DEFAULT 'PENDING',
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_provider_docs ON provider_verification_documents(provider_id);

Pessimistic Data Locking (SELECT FOR UPDATE)

BEGIN;

-- Lock provider profile record to prevent concurrent upload collisions
SELECT id, verification_status 
FROM provider_profiles 
WHERE id = $1 
FOR UPDATE;

-- Update provider verification status to PENDING
UPDATE provider_profiles SET verification_status = 'PENDING' WHERE id = $1;

COMMIT;

4. Backend Route & Service Layer Specifications

Route: POST /api/v1/provider/verification-document

  1. Validation: Validates file size (<= 5MB) and inspects magic number bytes (FF D8 FF for JPEG, 89 50 4E 47 for PNG, 52 49 46 46 for WebP). Rejects invalid extensions/signatures.
  2. Locking: DB transaction acquires SELECT FOR UPDATE on provider_profiles.
  3. Dynamic Watermarking: Applies semi-transparent diagonal text "FOR VELO VERIFICATION ONLY" and timestamps image buffer before saving.
  4. Synchronous DB Commit: Stores document metadata in provider_verification_documents and sets provider status to PENDING.
  5. Response: Returns HTTP 201 Created with document tracking metadata.

Error Payload Shapes

  • HTTP 400 Bad Request (Invalid file format/signature):
    {
      "error": {
        "code": "INVALID_FILE_SIGNATURE",
        "message": "Uploaded file magic number does not match supported image formats (JPEG, PNG, WebP).",
        "requestId": "req-doc-101"
      }
    }
  • HTTP 413 Payload Too Large (File size > 5 MB):
    {
      "error": {
        "code": "FILE_TOO_LARGE",
        "message": "Verification document exceeds maximum allowable limit of 5 MB.",
        "requestId": "req-doc-102"
      }
    }

5. Background Processors / Workers

Document Cleanup Worker (apps/api/src/lib/workers/documentCleanupWorker.ts)

  • Schedule: Runs daily.
  • Task: Identifies rejected verification documents older than 90 days in provider_verification_documents and purges underlying disk/object storage files safely.

6. Frontend / UI Component Specifications

Component: mobile/frontend/src/components/ProviderDocumentUpload.tsx

  • File Selection Blur/Change Validation: Inspects selected file size and extension on change. Shows inline error "File size must be under 5 MB and in JPEG, PNG, or WebP format".
  • Uploading State: Displays progress bar "Uploading & Applying Security Watermark...".
  • Uploaded State: Displays checkmark badge "Document Uploaded - Awaiting Admin Review".
  • Error Recovery State: Displays error alert "Upload Failed: Unsupported Image File" with button "Choose Another File".

7. Rigor & Test Plan

  1. Unit Tests (apps/api/src/routes/__tests__/provider-document.test.ts):
    • Upload valid JPEG file. Assert 201 Created and verify watermark image buffer header.
    • Upload executable script masked as .png. Assert magic number checker returns 400 Bad Request.
  2. Concurrency Test (tests/concurrency/provider_document_stress.test.ts):
    • Concurrently upload 10 documents for the same provider profile (Promise.all()).
    • Expectation: DB locking prevents state corruption; provider status consistently set to PENDING.
  3. Frontend Test (ProviderDocumentUpload.test.tsx):
    • Test client-side file validation and progress bar rendering.

8. Relevant Files Inventory

New Files to Create

  • apps/api/src/db/migrations/014_add_provider_document_watermarks.sql
  • apps/api/src/lib/provider-watermark.ts
  • apps/api/src/routes/__tests__/provider-document.test.ts
  • tests/concurrency/provider_document_stress.test.ts
  • mobile/frontend/src/components/ProviderDocumentUpload.tsx

Existing Files to Modify

  • apps/api/src/app.ts
  • apps/api/src/routes/provider.ts
  • apps/api/src/routes/admin.ts
  • apps/api/src/lib/provider-verification-store.ts
  • packages/shared/src/index.ts

9. Acceptance Criteria

  • DB migration creates provider_verification_documents table.
  • Magic number checker rejects invalid file signatures with 400 Bad Request.
  • Watermarking pipeline stamps "FOR VELO VERIFICATION ONLY" on uploaded images.
  • Private documents readable only via authenticated admin route (GET /api/v1/admin/providers/:providerId/verifications/:documentId).
  • UI component provides file format validation and upload feedback.

10. Contributor / Architectural Notes

  • ⚠️ Order: Apply SQL migration -> Deploy backend watermark utility & route -> Update frontend component.
  • ⚠️ Security Warning: NEVER trust client-side file MIME extensions; ALWAYS verify binary magic numbers on the backend.

Metadata

Metadata

Assignees

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions