diff --git a/.taskmaster/tasks/tasks.json b/.taskmaster/tasks/tasks.json index 5d348db..1a96f94 100644 --- a/.taskmaster/tasks/tasks.json +++ b/.taskmaster/tasks/tasks.json @@ -53,7 +53,7 @@ "details": "Source PRD: .taskmaster/docs/prd-platform-audit-remediation-plan-2026-05-24.md. Target backend hardening first, then documentation/runtime alignment. Delivery order suggested by PRD: security/auth, rate limiting, passkeys, Web3 verification, socket hardening, dispute hold controls, docs/API alignment.", "testStrategy": "Add focused regression tests for route auth/ownership, passkey challenge/verification, Web3 verification semantics, socket authorization, rate limiting tiers, and payout/release dispute holds. Update API docs after behavior is implemented.", "priority": "high", - "status": "pending", + "status": "done", "dependencies": [], "subtasks": [ { @@ -61,7 +61,7 @@ "title": "Secure unauthenticated endpoints and owner enforcement", "description": "Require authenticateToken and owner/admin checks on exposed payment, AI, and legacy notification routes.", "details": "Derive notification userId from authenticated principal. Protect payment history and mutation endpoints. Restrict AI calls to authenticated users with per-user budgets. Add denied-access audit logs.", - "status": "pending", + "status": "done", "priority": "high", "dependencies": [], "testStrategy": "Unauthorized callers receive 401/403; users cannot access or mutate other users' payments/notifications; admins retain authorized access.", @@ -72,7 +72,7 @@ "title": "Re-enable and scope rate limiting", "description": "Restore global and route-tiered rate limits for public-sensitive paths.", "details": "Use stricter limits for auth, financial, AI, file upload, and verification paths. Keep public reads at relaxed limits. Add observability for 429 spikes.", - "status": "pending", + "status": "done", "priority": "high", "dependencies": [ 1 @@ -85,7 +85,7 @@ "title": "Replace stubbed passkey/WebAuthn flow", "description": "Implement production-grade WebAuthn registration/authentication and shared challenge storage.", "details": "Use real attestation/assertion verification, Redis-backed TTL challenges, refresh-token persistence/rotation, and deterministic malformed/reused/expired challenge errors.", - "status": "pending", + "status": "done", "priority": "high", "dependencies": [ 1 @@ -98,7 +98,7 @@ "title": "Strengthen DePay/Web3 payment verification", "description": "Verify transaction recipient, token contract, and amount, not only receipt success.", "details": "Decode ERC-20 Transfer logs, compare recipient against escrow address, validate token contract and decimals-adjusted minimum amount, store verifier evidence and idempotency fingerprint.", - "status": "pending", + "status": "done", "priority": "high", "dependencies": [ 1 @@ -111,7 +111,7 @@ "title": "Lock Socket.IO room joins to authenticated context", "description": "Remove trust in client-supplied user/buyer/seller room IDs.", "details": "Validate socket handshake token, derive server-side room membership, reject mismatched joins, and monitor suspicious join attempts.", - "status": "pending", + "status": "done", "priority": "medium", "dependencies": [ 1 @@ -124,7 +124,7 @@ "title": "Enforce dispute hold before payout and release operations", "description": "Add payment hold state and central release/refund guards that block disputed funds.", "details": "Introduce explicit dispute hold fields or state, enforce in PaymentCoordinator and payout/release services, return clear 409/423 responses, and backfill/report blocked payments.", - "status": "pending", + "status": "done", "priority": "medium", "dependencies": [ 1, @@ -138,7 +138,7 @@ "title": "Align documentation, API references, and runtime enums", "description": "Normalize disputed/payment/request status docs and implementation references after security behavior changes.", "details": "Resolve mismatch around absent dispute module, endpoint names, status enums, and action names across Data Models, API Reference, and Flows.", - "status": "pending", + "status": "done", "priority": "medium", "dependencies": [ 1, @@ -157,10 +157,10 @@ "id": "3", "title": "Migrate payment architecture toward Request Network and internal funds management", "description": "Plan and implement provider-neutral payment flows, Request Network pay-in support, funds ledger, webhook reconciliation, release/refund orchestration, UI migration, and SHKeeper decommissioning.", - "details": "Source PRD: .taskmaster/docs/prd-request-network-migration-and-funds-management.md. The PRD recommends phased migration behind a provider adapter, Secure Payment Pages first, platform-controlled escrow/payee destination, and a first-class internal funds ledger before release/refund enforcement.", - "testStrategy": "Use feature flags, provider fixture tests, webhook signature/idempotency tests, ledger invariant tests, migration dry-run reports, and limited cohort rollout before default provider switch.", + "details": "Source PRD: .taskmaster/docs/prd-request-network-migration-and-funds-management.md. The PRD recommends phased migration behind a provider adapter, Secure Payment Pages first, platform-controlled escrow/payee destination, and a first-class internal funds ledger before release/refund enforcement.\n\nPost-completion update: Task 3 now includes a CI-safe focused verification command for the provider-neutral payment migration plus optional Trezor safekeeping. Trezor safekeeping is optional by default via TREZOR_SAFEKEEPING_REQUIRED=false and only gates release/refund confirmation when explicitly enabled. Vault references: 04 - Flows/Trezor Safekeeping Flow.md, 03 - API Reference/Trezor API.md, and 08 - Operations/Payment and Trezor Verification Report.md.", + "testStrategy": "Use feature flags, provider fixture tests, webhook signature/idempotency tests, ledger invariant tests, migration dry-run reports, and limited cohort rollout before default provider switch.\n\nFocused verification command: npm test -- __tests__/payment-adapter-registry.test.ts __tests__/request-network-adapter.test.ts __tests__/request-network-payin.test.ts __tests__/request-network-webhook.test.ts __tests__/payment-ledger.model.test.ts __tests__/payment-ledger.service.test.ts __tests__/payment-migration.service.test.ts __tests__/payment-release-refund-orchestration.test.ts __tests__/payment-release-refund-routes.test.ts __tests__/payment-reconciliation.service.test.ts __tests__/payment-observability-redaction.test.ts __tests__/payment-observability-events.test.ts __tests__/trezor-safekeeping.service.test.ts --runInBand. Expected result: 13 suites, 64 tests passing. Also run npm run typecheck.", "priority": "high", - "status": "in-progress", + "status": "done", "dependencies": [ "2" ], @@ -170,128 +170,138 @@ "title": "Define provider-neutral payment contracts and adapter", "description": "Create provider-agnostic payment interface with pay-in, webhook, payout/refund instruction creation, status lookup, and search methods.", "details": "", - "status": "pending", + "status": "done", "dependencies": [], "parentTaskId": 3, - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:24:49.217Z" }, { "id": 2, "title": "Implement provider configuration, feature flags, and safe rollback", "description": "Add runtime provider selection, rollout controls, env validation, and one-command kill-switch to revert to SHKeeper.", "details": "", - "status": "pending", + "status": "done", "dependencies": [ "3.1" ], "parentTaskId": 3, - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:30:51.152Z" }, { "id": 3, "title": "Create internal funds and payment ledger model", "description": "Define FundsAccount, immutable LedgerEntry, and balance/query views for expected/held/releasable/released/refunded/disputed states.", "details": "", - "status": "pending", + "status": "done", "dependencies": [ "3.1" ], "parentTaskId": 3, - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:30:52.613Z" }, { "id": 4, "title": "Build migration and indexing plan for existing SHKeeper records", "description": "Add DB indexes for payment/provider fields and run backfill to produce a migration report with skipped/failed/ambiguous historical entries.", "details": "", - "status": "pending", + "status": "done", "dependencies": [ "3.3" ], "parentTaskId": 3, - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:34:59.429Z" }, { "id": 5, "title": "Implement Request Network pay-in intent and secure payment pages", "description": "Add Request Network intent/service layer, secure payment URLs, and validation of network/currency/reference/amount before setting paid state.", "details": "", - "status": "pending", + "status": "done", "dependencies": [ "3.2" ], "parentTaskId": 3, - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:35:00.891Z" }, { "id": 6, "title": "Implement signed Request Network webhook intake", "description": "Build /api/payment/request-network/webhook with raw-body signature verification, idempotent delivery handling, and immutable event audit rows.", "details": "", - "status": "pending", + "status": "done", "dependencies": [ "3.2" ], "parentTaskId": 3, - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:35:02.505Z" }, { "id": 7, "title": "Implement reconciliation and repair jobs", "description": "Add periodic Request Network payment search/reconciliation and manual replay support to fix missed or delayed events.", "details": "", - "status": "pending", + "status": "done", "dependencies": [ "3.5", "3.6" ], "parentTaskId": 3, - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:44:46.205Z" }, { "id": 8, "title": "Replace checkout and payment UI with provider-neutral flows", "description": "Introduce provider-neutral payment components, remove SHKeeper walletAddress assumptions for RN, and keep legacy path only for existing SHKeeper records.", "details": "", - "status": "pending", + "status": "done", "dependencies": [ "3.5" ], "parentTaskId": 3, - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:50:26.225Z" }, { "id": 9, "title": "Add payout/release and refund orchestration using ledger gates", "description": "Create release/refund instruction queue with signer, tx payloads, provider tx hash, and strict ledger invariants before action.", "details": "", - "status": "pending", + "status": "done", "dependencies": [ "3.3", "3.7" ], "parentTaskId": 3, - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:50:55.916Z" }, { "id": 10, "title": "Update release/refund APIs and marketplace release paths", "description": "Refactor release routes to consume ledger state and provider-neutral contracts; deprecate direct simulation where possible.", "details": "", - "status": "pending", + "status": "done", "dependencies": [ "3.8", "3.9" ], "parentTaskId": 3, - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:50:57.496Z" }, { "id": 11, "title": "Add comprehensive observability, runbooks, and incident controls", "description": "Track webhook latency, ledger imbalance, release failures, and reconciliation lag with alerts, on-call runbooks, and rollback procedures.", "details": "", - "status": "pending", + "status": "done", "dependencies": [ "3.6", "3.8", @@ -299,24 +309,26 @@ "3.10" ], "parentTaskId": 3, - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:50:59.050Z" }, { "id": 12, "title": "Add end-to-end integration, migration, and rollback test suites", "description": "Cover backend contract tests, provider fixture tests, UI acceptance, rollout simulation, DRYRUN migration, and release rollback rehearsals.", "details": "", - "status": "pending", + "status": "done", "dependencies": [ "3.6", "3.10", "3.11" ], "parentTaskId": 3, - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:51:00.615Z" } ], - "updatedAt": "2026-05-24T05:52:52.473Z" + "updatedAt": "2026-05-24T07:04:01.906Z" }, { "id": "4", @@ -325,32 +337,34 @@ "details": "Source audit: .taskmaster/docs/audit-backend-stack-security-and-refactor-assessment-2026-05-24.md. This task is advisory/architecture-focused and should run in parallel with immediate hardening. It should produce the decision artifacts needed before any backend-core rewrite or provider migration is started.", "testStrategy": "Review and sign off each architecture document with backend, payments, frontend, and operations stakeholders. Confirm every open question has an owner or explicit deferred decision before implementation work begins.", "priority": "high", - "status": "pending", + "status": "in-progress", "dependencies": [], "subtasks": [ { "id": 1, "title": "Assign security ownership and launch decision criteria", "description": "Define who owns security decisions and what must be true before public launch or migration work proceeds.", - "details": "Answer ownership questions from the audit: security owner, launch safety bar, whether launch prioritizes hardening or redesign, and whether external penetration testing is required.", - "status": "pending", + "details": "Completed. Produced 09 - Audits/Security Ownership and Launch Decision Criteria.md. Contains: RACI matrix (10 decision areas, 6 roles, fallback rules), 42-item launch safety gate checklist with Required/Strongly Recommended/Deferred classifications cross-referenced to audit findings, launch priority decision (harden first, redesign deferred), external pentest decision (yes, before public launch, with compensating controls), 12-item deferred decisions register with owners and deadlines.", + "status": "done", "priority": "high", "dependencies": [], "testStrategy": "Written owner/RACI and launch gate checklist are accepted by leadership and engineering.", - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:43:01.505Z" }, { "id": 2, "title": "Produce threat model for escrow platform", "description": "Document protected assets, actors, trust boundaries, and abuse cases for the financial marketplace.", - "details": "Include buyer, seller, admin, support, unauthenticated attacker, compromised user/admin, provider, malicious webhook sender, browser/backend/database/Redis/provider/wallet/Socket.IO trust boundaries, and abuse cases such as fake payment proof, replayed webhook, arbitrary room join, stolen token, double payout, dispute bypass, email abuse, and AI abuse.", - "status": "pending", + "details": "Completed. Produced 09 - Audits/Threat Model - Amanat Escrow Platform.md. Contains: system description, 17 protected asset classes with sensitivity ratings, 11 actors with access levels and risk profiles, trust boundary diagram (Mermaid) with 10 boundary descriptions and current gaps, 23-threat catalog (T01-T23) with STRIDE categories and specific code-path references, risk summary matrix (6 Critical, 10 High, 6 Medium, 1 Low), threat-to-mitigation traceability matrix mapping 9 remediation docs to specific threats. Living document. Open verification items: Socket.IO room auth in socketService.ts, Telegram initData validation, actual lockfile versions for multer/axios/tanstack.", + "status": "done", "priority": "high", "dependencies": [ 1 ], "testStrategy": "Threat model maps each high-risk finding to at least one mitigation task or accepted risk.", - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:43:03.144Z" }, { "id": 3, @@ -408,14 +422,15 @@ "id": 7, "title": "Define secure build and supply-chain policy", "description": "Reduce npm/dependency compromise risk across frontend and any remaining Node services.", - "details": "Specify package manager and lockfile policy, CI install mode, dependency update cadence, advisory monitoring, npm provenance/signature policy where available, secrets handling, reproducible production builds, and separation between frontend npm risk and backend-core risk.", - "status": "pending", + "details": "Completed. Produced 09 - Audits/Secure Build and Supply-Chain Policy.md. 11 sections + 3 appendices: lockfile policy (npm ci mandatory), dependency update cadence (biweekly routine, immediate security-critical), advisory monitoring with SLAs (Critical 24h, High 72h, Medium 1 week), known exposure register with 5 open 2026 CVEs (multer, axios, tanstack, express, node) and SLA deadlines, npm provenance policy, secrets rotation schedule for all 10 secret types, production build reproducibility requirements, frontend vs backend risk separation with interim policy, incident response for 3 scenarios, CI/CD enforcement checklist with Gitea Actions YAML example.", + "status": "done", "priority": "medium", "dependencies": [ 1 ], "testStrategy": "Policy is actionable in CI and includes response steps for compromised package, leaked token, and vulnerable dependency alerts.", - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:43:04.699Z" }, { "id": 8, @@ -448,7 +463,8 @@ "testStrategy": "Runbooks identify owner, trigger, detection signal, immediate action, recovery action, and post-incident documentation for each scenario.", "parentId": "undefined" } - ] + ], + "updatedAt": "2026-05-24T06:43:04.699Z" }, { "id": "5", @@ -456,7 +472,7 @@ "description": "Create a Telegram bot plus Mini App surface so users can complete Amanat buyer, seller, escrow, chat, dispute, payment, release/refund, and support workflows from inside Telegram.", "details": "Source PRD: .taskmaster/docs/prd-telegram-native-app-bot-wallet.md. Keep this as a separate delivery track from security remediation and Request Network migration. Identity, bot navigation, Mini App shell, and notifications can start behind flags; wallet/payment crediting and release/refund actions must use canonical backend authorization, provider adapter, funds ledger, escrow state machine, idempotency, and dispute holds.", "testStrategy": "Use Telegram sandbox and production bot separation, Mini App client matrix testing, provider/wallet payment fixtures, backend authorization and ledger invariant tests, webhook/callback replay tests, and staged rollout analytics before launch.", - "status": "pending", + "status": "in-progress", "dependencies": [], "priority": "high", "subtasks": [ @@ -465,11 +481,12 @@ "title": "Define Telegram product surface and flow map", "description": "Document which Amanat workflows live in bot messages, which live in the Mini App, and which remain web/admin-only for first release.", "details": "Map buyer, seller, admin/support, unauthenticated, linked-user, and unlinked-user journeys. Specify deep-link entry points for request details, offer review, payment, dispute, delivery evidence, and account linking. Separate first-release scope from later enhancements and map every Telegram action to backend API/state transitions.", - "status": "pending", + "status": "in-progress", "dependencies": [], "priority": "high", "testStrategy": "See Telegram-native PRD acceptance criteria.", - "parentId": "undefined" + "parentId": "undefined", + "updatedAt": "2026-05-24T06:12:47.328Z" }, { "id": 2, @@ -589,17 +606,18 @@ "testStrategy": "See Telegram-native PRD acceptance criteria.", "parentId": "undefined" } - ] + ], + "updatedAt": "2026-05-24T06:12:47.328Z" } ], "metadata": { "version": "1.0.0", - "lastModified": "2026-05-24T05:52:52.473Z", + "lastModified": "2026-05-24T07:04:01.906Z", "taskCount": 5, - "completedCount": 1, + "completedCount": 2, "tags": [ "master" ] } } -} \ No newline at end of file +} diff --git a/03 - API Reference/Trezor API.md b/03 - API Reference/Trezor API.md new file mode 100644 index 0000000..15e6731 --- /dev/null +++ b/03 - API Reference/Trezor API.md @@ -0,0 +1,187 @@ +--- +title: Trezor API +tags: [api, payments, trezor, safekeeping] +--- + +# Trezor API + +The Trezor API is mounted at `/api/trezor`. It is optional support for hardware-backed safekeeping and does not replace SHKeeper or Request Network. + +Enforcement is controlled by: + +```env +TREZOR_SAFEKEEPING_REQUIRED=false +``` + +Only the literal value `true` makes Trezor proof mandatory during release/refund confirmation. When unset or `false`, release/refund flows continue without Trezor proof. + +## GET /api/trezor/registration-message + +Builds the exact message the user must sign to register a Trezor xpub. + +Auth: bearer JWT + +Query: + +```text +xpub= +registrationAddress= +``` + +Response: + +```json +{ + "success": true, + "data": { + "message": "Amanat escrow Trezor registration\n..." + } +} +``` + +## POST /api/trezor/register + +Registers a Trezor xpub after the first derived address signs the registration challenge. + +Auth: bearer JWT + +Body: + +```json +{ + "xpub": "xpub...", + "registrationAddress": "0x...", + "proofMessage": "Amanat escrow Trezor registration\n...", + "proofSignature": "0x...", + "basePath": "m/44'/60'/0'", + "deviceLabel": "Office Trezor" +} +``` + +Validation: + +- Rejects private extended keys (`xprv`, `tprv`). +- Requires `registrationAddress` to equal xpub-derived `m/44'/60'/0'/0/0`. +- Requires `proofSignature` to recover `registrationAddress`. + +Response: + +```json +{ + "success": true, + "data": { + "xpubFingerprint": "0x...", + "registrationAddress": "0x...", + "basePath": "m/44'/60'/0'", + "nextAddressIndex": 1 + } +} +``` + +## GET /api/trezor/account + +Returns the caller's active Trezor registration summary. + +Auth: bearer JWT + +Response when absent: + +```json +{ + "success": true, + "data": { + "registered": false + } +} +``` + +## POST /api/trezor/addresses/next + +Allocates or returns a deterministic receive address from the registered xpub. + +Auth: bearer JWT + +Body: + +```json +{ + "purpose": "deposit", + "paymentId": "..." +} +``` + +If `paymentId` already has an assigned address, the same address is returned. Otherwise the backend derives: + +```text +m/44'/60'/0'/0/{nextAddressIndex} +``` + +## POST /api/trezor/operation-message + +Builds the exact transaction-intent message an admin must sign when Trezor safekeeping is enabled. + +Auth: bearer JWT, admin + +Body: + +```json +{ + "operation": "release", + "paymentId": "...", + "transactionHash": "0x...", + "amount": 100, + "currency": "USDT", + "provider": "request.network" +} +``` + +Response: + +```json +{ + "success": true, + "data": { + "message": "Amanat escrow Trezor transaction approval\n..." + } +} +``` + +## POST /api/trezor/verify-operation + +Verifies a signed operation intent against the admin's registered Trezor safekeeping address. + +Auth: bearer JWT, admin + +Body: + +```json +{ + "payload": { + "operation": "release", + "paymentId": "...", + "transactionHash": "0x...", + "amount": 100, + "currency": "USDT", + "provider": "request.network" + }, + "message": "Amanat escrow Trezor transaction approval\n...", + "signature": "0x..." +} +``` + +## Release / Refund Integration + +When `TREZOR_SAFEKEEPING_REQUIRED=true`, release/refund confirmation bodies must include the Trezor proof: + +```json +{ + "txHash": "0x...", + "amount": 100, + "trezor": { + "message": "Amanat escrow Trezor transaction approval\n...", + "signature": "0x..." + } +} +``` + +This proof is optional when enforcement is disabled. diff --git a/04 - Flows/Trezor Safekeeping Flow.md b/04 - Flows/Trezor Safekeeping Flow.md new file mode 100644 index 0000000..d0c8067 --- /dev/null +++ b/04 - Flows/Trezor Safekeeping Flow.md @@ -0,0 +1,119 @@ +# Trezor Safekeeping Flow + +This flow adds hardware-backed custody controls without replacing the current payment model. The backend never stores private keys. Trezor support starts as a single hardware signer and is designed to upgrade to multisig later. + +Default mode: optional. Existing release/refund flows do not require Trezor proof unless `TREZOR_SAFEKEEPING_REQUIRED=true`. + +## Goals + +- Generate a fresh receive address per user/payment from a registered Trezor xpub. +- Require a Trezor-produced signature before release/refund confirmation when safekeeping enforcement is enabled. +- Keep SHKeeper and Request Network optional provider paths intact. +- Preserve the existing `Payment` model and orchestration surface. + +## Registration + +1. User connects a Trezor in the frontend and exports an Ethereum account xpub, for example `m/44'/60'/0'`. +2. Backend builds a registration challenge: + - `GET /api/trezor/registration-message?xpub=...®istrationAddress=...` +3. The registration address must be the first derived address from the xpub: + - `m/44'/60'/0'/0/0` +4. User signs the challenge with that Trezor address. +5. Frontend submits: + - `POST /api/trezor/register` + - `xpub` + - `registrationAddress` + - `proofMessage` + - `proofSignature` + - optional `basePath`, `deviceLabel` +6. Backend verifies: + - xpub is public, not private. + - registration address matches xpub-derived index `0`. + - signature recovers the registration address. +7. Backend stores only: + - `userId` + - xpub fingerprint + - xpub + - base derivation path + - registration address + - next address index + - issued address records + +## Address Generation + +To issue the next payment address: + +```http +POST /api/trezor/addresses/next +{ + "purpose": "deposit", + "paymentId": "..." +} +``` + +The backend derives non-hardened receive addresses from the registered xpub: + +```text +m/44'/60'/0'/0/{index} +``` + +If a `paymentId` already has an address, the endpoint returns the same address instead of incrementing the index. + +## Transaction Approval + +Before a release/refund confirmation, the admin asks the backend for the exact operation message: + +```http +POST /api/trezor/operation-message +{ + "operation": "release", + "paymentId": "...", + "transactionHash": "0x...", + "amount": 100, + "currency": "USDT", + "provider": "request.network" +} +``` + +The Trezor signs that message. Release/refund confirmation then includes: + +```json +{ + "txHash": "0x...", + "trezor": { + "message": "Amanat escrow Trezor transaction approval\n...", + "signature": "0x..." + } +} +``` + +When `TREZOR_SAFEKEEPING_REQUIRED=true`, `confirmReleaseRefundInstruction` verifies the signature before calling the payment adapter confirmation path. + +## Enforcement Flag + +```env +TREZOR_SAFEKEEPING_REQUIRED=false +``` + +Default is permissive so existing SHKeeper and Request Network flows continue to work. Set it to `true` only after registering the operating admin's Trezor account and testing the signing path. Any value other than the literal string `true` is treated as disabled. + +## Safety Rules + +- Never store Trezor seed words, private keys, or xprv/tprv values. +- Reject private extended keys at registration. +- Verify every signature locally before accepting it. +- Use exact transaction-intent messages; do not accept free-form signatures. +- Treat generated deposit addresses as public routing metadata, not as proof of payment. +- Keep ledger availability checks enabled for release/refund accounting. + +## Upgrade Path To Multisig + +The current design stores a single `trezor-eoa` signer. Later, replace the signer policy with: + +- `addressType: safe-multisig` +- a Safe address per tenant/admin group +- threshold policy, such as `2-of-3` +- Trezor owners as Safe signers +- release/refund flow creates a Safe transaction and records collected signatures before execution + +The payment orchestration API should stay the same: build instruction, collect hardware-backed approval, confirm release/refund, append ledger entry. diff --git a/07 - Development/Environment Variables.md b/07 - Development/Environment Variables.md index d286229..70948bd 100644 --- a/07 - Development/Environment Variables.md +++ b/07 - Development/Environment Variables.md @@ -102,6 +102,23 @@ SHKeeper is the crypto payment gateway. See [[Payment Flow]] and [[SHKeeper Inte --- +## Payments — Provider Selection + +| Name | Repo | Required | Default | Example | Purpose | +|------|------|----------|---------|---------|---------| +| `PAYMENT_PROVIDER` | backend | optional | `shkeeper` | `request.network` | Active provider for new payment intents | +| `PAYMENT_DEFAULT_PROVIDER` | backend | optional | `shkeeper` | `shkeeper` | Fallback alias when `PAYMENT_PROVIDER` is unset | +| `PAYMENT_ENABLED_PROVIDERS` | backend | optional | `shkeeper` | `shkeeper,request.network` | Comma-separated providers allowed at runtime | +| `PAYMENT_ROLLBACK_PROVIDER` | backend | optional | `shkeeper` | `shkeeper` | Provider used when selected provider is not enabled | +| `PAYMENT_PROVIDER_MODE` | backend | optional | `live` | `dry-run` | Provider mode: `live`, `dry-run`, or `read-only` | +| `REQUEST_NETWORK_ENABLED` | backend | optional | `false` | `true` | Adds `request.network` to enabled providers when no explicit list is set | +| `PAYMENT_REQUEST_NETWORK_COHORT_PERCENT` | backend | optional | `0` | `10` | Percent of new checkout cohort eligible for Request Network | +| `PAYMENT_LEDGER_ENFORCEMENT` | backend | optional | `false` | `true` | Enforce ledger gates for release/refund | +| `PAYMENT_RECONCILIATION_ENABLED` | backend | optional | `false` | `true` | Enable scheduled provider reconciliation jobs | +| `TREZOR_SAFEKEEPING_REQUIRED` | backend | optional | `false` | `true` | Optional hardware-signature gate for release/refund confirmation. Only the literal value `true` enforces Trezor proof. | + +--- + ## Payments — DePay / Web3 (frontend) | Name | Repo | Required | Default | Example | Purpose | @@ -249,6 +266,13 @@ SMTP_PASS= SMTP_FROM="AMN " # SHKeeper (set when ready) +PAYMENT_PROVIDER=shkeeper +PAYMENT_ENABLED_PROVIDERS=shkeeper +PAYMENT_ROLLBACK_PROVIDER=shkeeper +REQUEST_NETWORK_ENABLED=false +PAYMENT_LEDGER_ENFORCEMENT=false +PAYMENT_RECONCILIATION_ENABLED=false +TREZOR_SAFEKEEPING_REQUIRED=false SHKEEPER_BASE_URL= SHKEEPER_API_URL= SHKEEPER_API_KEY= diff --git a/08 - Operations/Incident Response.md b/08 - Operations/Incident Response.md index 8b1f1bc..2e47174 100644 --- a/08 - Operations/Incident Response.md +++ b/08 - Operations/Incident Response.md @@ -256,6 +256,38 @@ docker exec -it nickapp-backend node -e " If user data may have leaked, treat as sev 1 and follow your data-breach disclosure process. +### 3.8 Request Network rollback + reconciliation + +Use when Request Network payments are failing, stalled, or out of sync with local payment state. + +**Immediate rollback (minutes):** + +1. Stop routing new intents to Request Network by setting: + + - `REQUEST_NETWORK_ENABLED=false` + - `PAYMENT_ENABLED_PROVIDERS=shkeeper` + - keep `PAYMENT_ROLLBACK_PROVIDER=shkeeper` + +2. Restart backend and confirm new `/api/payment/request-network/*` checks are no longer in your checkout path. + +3. Confirm `PAYMENT_PROVIDER_MODE` is in a safe operational mode: + + - `live`: standard operations + - `read-only`: observe only, no writes + - `dry-run`: status updates without on-chain actions + +**Reconciliation before re-enabling:** + +1. Keep `PAYMENT_RECONCILIATION_ENABLED=false` until investigation is complete. + +2. Run a dry reconciliation pass (dry-run) using the Request Network reconciliation service and capture summary counters. + +3. If summary is healthy, run with `apply=true` for the intended payment window. + +4. Re-enable RN intentionally only after two deployment health checks pass. + +Escalate if repeated `lookup_failed`, `missing_reference`, or coordinator-blocked outcomes block reconciliation for more than 10 minutes. + --- ## 4. Communication templates diff --git a/08 - Operations/Payment and Trezor Verification Report.md b/08 - Operations/Payment and Trezor Verification Report.md new file mode 100644 index 0000000..544466c --- /dev/null +++ b/08 - Operations/Payment and Trezor Verification Report.md @@ -0,0 +1,96 @@ +--- +title: Payment and Trezor Verification Report +tags: [operations, testing, payments, trezor] +--- + +# Payment and Trezor Verification Report + +Date: 2026-05-24 + +Scope: + +- Task 3 provider-neutral payment migration. +- Request Network optional pay-in, webhook, and reconciliation support. +- Internal funds ledger and release/refund ledger gates. +- Optional Trezor safekeeping support. + +## Optionality Verdict + +Trezor safekeeping is optional by default. + +```env +TREZOR_SAFEKEEPING_REQUIRED=false +``` + +Only the literal value `true` enforces Trezor proof during release/refund confirmation. When unset, `false`, or any other value, release/refund confirmation continues through the existing payment adapter path. + +Enforcement is centralized in `backend/src/services/trezor/trezorService.ts` and called from `backend/src/services/payment/orchestration/releaseRefundService.ts`. + +## Focused Verification Command + +Run this command from the backend package: + +```bash +npm test -- __tests__/payment-adapter-registry.test.ts __tests__/request-network-adapter.test.ts __tests__/request-network-payin.test.ts __tests__/request-network-webhook.test.ts __tests__/payment-ledger.model.test.ts __tests__/payment-ledger.service.test.ts __tests__/payment-migration.service.test.ts __tests__/payment-release-refund-orchestration.test.ts __tests__/payment-release-refund-routes.test.ts __tests__/payment-reconciliation.service.test.ts __tests__/payment-observability-redaction.test.ts __tests__/payment-observability-events.test.ts __tests__/trezor-safekeeping.service.test.ts --runInBand +``` + +Expected result: + +```text +Test Suites: 13 passed, 13 total +Tests: 64 passed, 64 total +``` + +Also run: + +```bash +npm run typecheck +git diff --check +``` + +Expected result: both pass for backend changes. + +## Suite Coverage + +| Suite | Test count | Verifies | +| --- | ---: | --- | +| `payment-adapter-registry.test.ts` | 8 | Provider adapter selection, rollback defaults, enabled provider flags, Request Network alias support | +| `request-network-adapter.test.ts` | 6 | Request Network payload creation, parse/map helpers, webhook signature verification, adapter HTTP wiring | +| `request-network-payin.test.ts` | 3 | Pay-in creation, pending-intent dedupe, provider-disabled rejection | +| `request-network-webhook.test.ts` | 6 | Signature validation, test webhook allowlist, duplicate delivery handling, coordinator-blocked duplicate path | +| `payment-ledger.model.test.ts` | 3 | Ledger model entry types, required fields, unique sparse idempotency index | +| `payment-ledger.service.test.ts` | 9 | Append/idempotency behavior, balance aggregation, release/refund availability, held/disputed invariant | +| `payment-migration.service.test.ts` | 3 | SHKeeper migration dry-run counts, bounded sampling, ledger backfill candidate filtering | +| `payment-release-refund-orchestration.test.ts` | 5 | Release/refund instruction flow, ledger append, partial release, rollback compatibility, Trezor proof forwarding | +| `payment-release-refund-routes.test.ts` | 2 | Release/refund route ordering and controller dispatch | +| `payment-reconciliation.service.test.ts` | 6 | Dry-run/apply reconciliation, no-op alignment, missing refs, fallback Request Network references | +| `payment-observability-redaction.test.ts` | 3 | Recursive secret redaction and immutability | +| `payment-observability-events.test.ts` | 5 | Incident control snapshots and event construction | +| `trezor-safekeeping.service.test.ts` | 5 | Deterministic xpub derivation, xpub validation, registration proof, address allocation reuse, operation signature verification | + +## Known Gaps + +- No live Request Network API test is included in this CI-safe suite. +- No physical Trezor/hardware-device validation is included; Trezor tests use deterministic xpub/address/signature fixtures. +- Migration tests are read/report-oriented and do not execute destructive production backfills. +- Frontend checkout still needs a separate browser/build verification once frontend dependencies are installed. +- The existing `npm run test:payment` script points at a missing `__tests__/payment-services.test.ts`; use the focused command above instead. + +## Release Gate + +Before enabling Request Network for a non-test cohort: + +1. Run the focused verification command. +2. Run backend typecheck. +3. Test one Request Network sandbox pay-in with webhook callback. +4. Confirm reconciliation dry-run output is empty or expected. +5. Keep `PAYMENT_ROLLBACK_PROVIDER=shkeeper`. + +Before enabling Trezor safekeeping enforcement: + +1. Register an admin Trezor account through `/api/trezor/register`. +2. Confirm `/api/trezor/account` reports `registered: true`. +3. Generate and sign one `/api/trezor/operation-message`. +4. Confirm `/api/trezor/verify-operation` succeeds. +5. Set `TREZOR_SAFEKEEPING_REQUIRED=true`. +6. Confirm release/refund without Trezor proof is rejected and release/refund with proof succeeds. diff --git a/Taskmaster/Tasks/task-3.md b/Taskmaster/Tasks/task-3.md new file mode 100644 index 0000000..cc7122a --- /dev/null +++ b/Taskmaster/Tasks/task-3.md @@ -0,0 +1,39 @@ +--- +taskmaster_id: "3" +status: "done" +priority: "high" +depends_on: ["2"] +parent_id: "" +source: "taskmaster" +generated_at: "2026-05-24T07:09:45.397Z" +--- + +# 3 - Migrate payment architecture toward Request Network and internal funds management + +- [x] 3 - Migrate payment architecture toward Request Network and internal funds management #taskmaster #priority/high #status/done ⏫ 🆔 tm-3 ⛔ tm-2 + +## Metadata + +| Field | Value | +| --- | --- | +| Taskmaster ID | 3 | +| Status | done | +| Priority | high | +| Dependencies | 2 | +| Parent | None | + +## Description + +Plan and implement provider-neutral payment flows, Request Network pay-in support, funds ledger, webhook reconciliation, release/refund orchestration, UI migration, and SHKeeper decommissioning. + +## Details + +Source PRD: .taskmaster/docs/prd-request-network-migration-and-funds-management.md. The PRD recommends phased migration behind a provider adapter, Secure Payment Pages first, platform-controlled escrow/payee destination, and a first-class internal funds ledger before release/refund enforcement. + +Post-completion update: Task 3 now includes a CI-safe focused verification command for the provider-neutral payment migration plus optional Trezor safekeeping. Trezor safekeeping is optional by default via TREZOR_SAFEKEEPING_REQUIRED=false and only gates release/refund confirmation when explicitly enabled. Vault references: 04 - Flows/Trezor Safekeeping Flow.md, 03 - API Reference/Trezor API.md, and 08 - Operations/Payment and Trezor Verification Report.md. + +## Verification + +Use feature flags, provider fixture tests, webhook signature/idempotency tests, ledger invariant tests, migration dry-run reports, and limited cohort rollout before default provider switch. + +Focused verification command: npm test -- __tests__/payment-adapter-registry.test.ts __tests__/request-network-adapter.test.ts __tests__/request-network-payin.test.ts __tests__/request-network-webhook.test.ts __tests__/payment-ledger.model.test.ts __tests__/payment-ledger.service.test.ts __tests__/payment-migration.service.test.ts __tests__/payment-release-refund-orchestration.test.ts __tests__/payment-release-refund-routes.test.ts __tests__/payment-reconciliation.service.test.ts __tests__/payment-observability-redaction.test.ts __tests__/payment-observability-events.test.ts __tests__/trezor-safekeeping.service.test.ts --runInBand. Expected result: 13 suites, 64 tests passing. Also run npm run typecheck.