fix(#677): add CSP headers in vite.config.js#4
Open
jessicanath wants to merge 244 commits into
Open
Conversation
- Add webhook_dead_letters table migration
- Add DeadLetterRecord type and DLQ methods to IWebhookStore
(sendToDeadLetter, listDeadLetters, markDeadLetterReplayed)
for both InMemoryWebhookStore and PostgresWebhookStore
- Update WebhookDispatcher to move permanently failed deliveries
(after max retries) into the DLQ via onDeadLetter callback
- Add swiftremit_webhook_dead_letter_count Prometheus counter
- Add admin endpoints:
GET /api/webhooks/dead-letters (list with limit/offset)
POST /api/webhooks/dead-letters/:id/replay
…alth widget - abuse_protection.rs: add ledger-time boundary test for cooldown enforcement - config.rs/storage.rs: add runtime-adjustable MaxExpiredBatchSize with get/set - lib.rs: set_max_expired_batch_size admin fn (1-200 range); use runtime value in process_expired_remittances; emit daily_limit_updated event from set_daily_limit - events.rs: add emit_daily_limit_updated with old/new limit and admin fields - backend/stellar.ts: add parseDailyLimitUpdatedEvent helper - backend/webhook-handler.ts: route and handle daily_limit_updated events - frontend: add ContractHealth widget with auto-refresh, pause indicator, fee withdraw button; mount in App.jsx
- Add idempotent migrations for transaction indexes (sender, status) - Add admin_audit_log table migration + AdminAuditLogService - Expose GET /api/admin/audit-log with pagination and filtering - Wire audit log into RemittanceEventEmitter via emitAdminAction() - Split database.ts into domain repositories (Remittance, Kyc, Anchor, Webhook, FxRate) - Add repository unit tests with mocked Pool - Add OpenTelemetry tracing (HTTP, Express, pg) with OTLP exporter - Add withSpan() helper for manual instrumentation - Document Jaeger local setup in README and env vars in .env.example
…ter, simulate_upgrade - AnchorSelector: add currencies[] prop (backward-compat), per-currency fee breakdown - API: anchorStore.list() supports currencies[] with ALL-match SQL; anchors route parses currencies[] params - ProofOfPayout: hex proof hash with copy-to-clipboard, validation status, Stellar Expert verify link - TransactionHistory: search by ID/recipient (debounced 300ms), filter by status/asset/date range, URL param persistence - contract_upgrade.rs: add simulate_upgrade() read-only fn + UpgradeSimulationResult type - API: POST /api/admin/simulate-upgrade endpoint with OpenAPI docs
- Add Content-Security-Policy header in vite.config.js (dev server) - Add CSP, X-Frame-Options: DENY, X-Content-Type-Options: nosniff, and Referrer-Policy headers in vercel.json (production) - Policy allows self, Stellar SDK CDN origins, Freighter extension - No unsafe-inline scripts; style-src allows inline for CSS-in-JS - Add csp.test.ts to verify directive coverage Closes Haroldwonder#448
…nter (Haroldwonder#449) - Replace single global limiter with per-group limiters: - Public endpoints (/api/*): 100 req/min - Webhook endpoints (/api/webhook/*): 1000 req/min - Admin endpoints (/api/kyc/config): 20 req/min - All 429 responses include Retry-After header (seconds) - Add incrementRateLimitExceeded() to MetricsService - Expose swiftremit_rate_limit_exceeded_total{path} Prometheus counter - Add rate-limit.test.ts verifying 429 + Retry-After enforcement Closes Haroldwonder#449
…g webhooks (Haroldwonder#450) - Add anchor-toml-validator.ts: fetches and parses stellar.toml for a given home_domain, validates SIGNING_KEY matches DB public_key - Results cached in NodeCache for 24 h; invalidateTomlCache() for manual refresh - WebhookHandler.handleWebhook now calls validateAnchorToml() after anchor lookup; returns 403 on mismatch and logs suspicious activity - Add migration add_anchor_toml_validation.sql (toml_validated_at, toml_signing_key columns on anchors table) - Add anchor-toml-validator.test.ts covering match, mismatch, missing key, and network failure cases Closes Haroldwonder#450
…er#451) - Add backend/src/migrate.ts: - Creates schema_migrations table (id, filename, applied_at, checksum) - migrate(): reads *.sql files from backend/migrations/ in sorted order, skips already-applied ones, runs each in a transaction, records result - rollback(): finds last applied migration, runs matching .down.sql, removes record from schema_migrations - Standalone CLI: tsx src/migrate.ts [migrate|rollback] - Wire migrate() into startup in index.ts (runs before server listens) - Add npm scripts: migrate and migrate:rollback - Add migrate.test.ts covering: table creation, ordered apply, skip applied, rollback on error, rollback command, missing .down.sql Closes Haroldwonder#451
…nder#445) Replace mousedown listener with pointerdown so the dropdown closes reliably on both mouse and touch (iOS Safari / Android Chrome). Closes Haroldwonder#445
- Poll every 30s (configurable via pollingIntervalMs prop) when status is pending - Stop polling automatically on terminal status (approved/rejected) - Show subtle 'Checking...' indicator during each poll - pollingIntervalMs=0 disables polling Closes Haroldwonder#444
…er#446) - Fetch live FX rate from /api/fx-rates on step 4 (Review summary) - Display recipient payout estimate with rate and currency - Show rate timestamp and live countdown (valid for Xs) - Auto-refresh rate every 30s while user stays on review step Closes Haroldwonder#446
…ry (Haroldwonder#447) - Add JSON download: serialises all receipt fields to a .json file - Add PDF download: generates a print-ready HTML page via window.print() (no server-side dependency) - Receipt includes: id, amount, asset, recipient, status, timestamp, memo, details, downloadedAt - Download buttons appear per row in table view and per card in card view Closes Haroldwonder#447
…nchor timeout Haroldwonder#429 feat: Add subscribeToRemittanceEvents to SDK - New RemittanceEvent, SubscribeOptions, Unsubscribe types - SorobanRpc.getEvents polling with exponential backoff reconnect (1s→30s) - remittanceId/cursor filtering; unsubscribe function returned - README example + event type table; 5 new tests Haroldwonder#430 fix: FX rate cache graceful 429 handling - staleCache Map persists entries beyond TTL - 429 returns last known rate with stale:true flag - Jittered retry (60-120s) to avoid thundering herd - fetchFromExternalApi re-throws axios errors as-is - 2 new tests Haroldwonder#431 feat: FX rate staleness metrics - fx_rate_age_seconds{from,to} gauge per currency pair - fx_rate_cache_hits_total / fx_rate_cache_misses_total counters - Prometheus alert rules: FxRateStale (>300s), FxRateCacheMissRateHigh (>80%) - 4 new tests Haroldwonder#433 fix: SEP-24 pending_anchor timeout - ANCHOR_TIMEOUT_HOURS env (default 24h) - Transitions pending_anchor → error after timeout - stalledTransactionsTotal Prometheus counter - Webhook notification via ANCHOR_TIMEOUT_WEBHOOK_URL - 1 new test
Closes Haroldwonder#430 - On 429, return last known stale rate with stale:true flag - staleCache Map persists entries beyond TTL for 429 fallback - Jittered retry (60-120s) to avoid thundering herd - fetchFromExternalApi re-throws axios errors as-is - 2 new tests covering the 429 path
Closes Haroldwonder#431 - fx_rate_age_seconds{from,to} gauge per currency pair - fx_rate_cache_hits_total / fx_rate_cache_misses_total counters - alert_rules.yml: FxRateStale (>300s), FxRateCacheMissRateHigh (>80%) - prometheus.yml updated to reference rule file - 4 new tests
Closes Haroldwonder#433 - ANCHOR_TIMEOUT_HOURS env var (default: 24h) - pending_anchor transactions beyond threshold transitioned to error - stalledTransactionsTotal Prometheus counter - Webhook notification via ANCHOR_TIMEOUT_WEBHOOK_URL - Both env vars documented in .env.example - 1 new test covering the timeout scenario
Closes Haroldwonder#429 - subscribeToRemittanceEvents(callback, options?): Unsubscribe - Uses SorobanRpc.Server.getEvents (Horizon SSE for Soroban) - Filters by remittanceId; cursor support for resuming - Auto-reconnects with exponential back-off (1s -> 30s) - Typed events: created | completed | cancelled | failed | disputed - README example + event type table - 5 new tests in sdk/src/events.test.ts
- Add Socket.IO server attached to existing HTTP server (no second port)
- Implement JWT auth middleware for WS connections (401 on failure)
- Add remittance rooms (remittance:{id}) with ownership validation
- Emit status:updated to room on every status change, same event-loop tick
- Add in-process EventEmitter bus (remittanceEvents.ts) as the hook point
- Add /ws/health endpoint (development only) with client count + uptime
- Add RemittanceStore (PostgreSQL) with updateStatus() as single choke-point
- Add RemittanceService enforcing state machine, calls emitStatusChange()
after DB persist succeeds — never before, never in finally
- Add PATCH /api/remittances/:id/status and GET /api/remittances/:id routes
- Wire /api/remittances into app.ts with injectable service for testing
- Add 11 WebSocket tests covering auth, room join, event delivery, cleanup
- All 78 tests pass
Closes: WebSocket remittance status push
- List all registered webhook endpoints - Add/edit/delete subscriptions via /api/webhooks REST endpoints - Test delivery button with live feedback - Delivery history per subscription - Accessible UI with ARIA labels and keyboard navigation Closes Haroldwonder#436
- Full CRUD for anchor providers (add, edit, delete) - Enable/disable status toggle via PATCH /api/anchors/:id - Health check per anchor via /api/anchors/:id/health - Form validates required fields (name, domain) - Accessible UI with ARIA labels Closes Haroldwonder#437
- List all remittances in Disputed state via /api/remittances?status=Disputed - View evidence hash and remittance details per dispute - Resolve in favour of sender or agent with confirmation dialog - Audit trail of resolved disputes via /api/disputes/audit - Accessible UI with ARIA roles and keyboard navigation Closes Haroldwonder#438
- List all registered agents with stats (success rate, volume, last active) - Register new agent form via POST /api/agents - Remove agent with confirmation dialog - Warning on remove if agent has active in-flight remittances - KYC status and expiry visible per agent - Accessible UI with ARIA labels Closes Haroldwonder#439
…aroldwonder#428) - Add retries, retryDelayMs, retryBackoffFactor options to SwiftRemitClientOptions - Implement isTransientError (429, 503, ECONNRESET, ECONNREFUSED, ETIMEDOUT, network, timeout) - Implement withRetry helper with exponential backoff - Wrap server.sendTransaction in submitTransaction with retry - Wrap server.simulateTransaction in simulateCall with retry - Add 16 tests in sdk/src/retry.test.ts; all 19 SDK tests pass
- Call cancel_remittance on the Soroban contract when a SEP-24 transaction expires during polling - Mark transaction as 'refunded' (idempotency sentinel) so a second poll cycle does not re-trigger the refund - Dispatch sep24.expired_refund webhook event to all active subscribers - Gracefully handle missing external_transaction_id (no on-chain cancel, still marks refunded) and contract errors (logs, still marks refunded) - Add cancelRemittanceOnChain helper to stellar.ts - Add Sep24ExpiredRefundWebhookPayload type to types.ts - Add dispatchSep24ExpiredRefund to WebhookDispatcher - Add DB migration documenting idempotency strategy and index - Add 6-test integration suite covering all acceptance criteria
- Add ProposalState, ProposalAction, Proposal types to types.ts - Add parseProposal helper to convert.ts - Export new types and parseProposal from index.ts - Add getProposal, getActiveProposals, voteOnProposal, executeProposal to client.ts - getActiveProposals iterates IDs until ProposalNotFound, filters Pending/Approved - Add 10 tests in sdk/src/governance.test.ts; all 13 SDK tests pass - Update sdk/README.md with Governance section
…wonder#432) - /health is now async; runs SELECT 1 with a 2-second timeout - Returns 503 + {status:'degraded', db:'unhealthy'} when probe fails - Returns 200 + {status:'ok', db:'healthy'} on success - Adds db_pool_available_connections Prometheus gauge (pool.idleCount) - Adds 2-test suite covering healthy and DB-failure cases
…Haroldwonder#426) - Always call save_sliding_window_entry with the pruned entry before returning RateLimitExceeded, so stale timestamps are evicted even when the rate limit is hit - Add MAX_VEC_SIZE = MAX_TRANSFERS_PER_WINDOW * 2 constant - Truncate timestamps Vec with pop_front when it exceeds MAX_VEC_SIZE - Add test_timestamps_vec_stays_bounded_after_many_calls to verify the Vec never exceeds MAX_VEC_SIZE under sustained load
…r#424) - Replace global CbKey::UnpauseVoteCount (instance storage) with CbKey::UnpauseVoteCountForSeq(u64) (persistent storage) so each pause cycle has its own isolated vote counter - Add get_vote_count_for_seq / set_vote_count_for_seq helpers - Remove set_vote_count(env, 0) from do_emergency_pause (no longer needed; new seq key starts at 0 by default) - Update do_vote_unpause to read/write the seq-scoped counter - Update do_emergency_unpause quorum check to use seq-scoped counter - Update build_status to report the active seq's vote count - Add test_vote_count_isolated_across_pause_cycles: verifies cycle 2 starts at 0 and build_status reports 0 - Add test_voter_can_vote_in_new_cycle: verifies same admin can vote again after a new pause cycle begins
- Extend AgentStats with success_rate_bps (u32) and last_active_timestamp (u64) - success_rate_bps = successful_payouts / total * 10000 (bps) - Default for new agents: success_rate_bps=10000, last_active_timestamp=0 - confirm_payout: sets last_active_timestamp, recomputes success_rate_bps - mark_failed: sets last_active_timestamp, recomputes success_rate_bps - get_agent_stats public query already exposed; no change needed - SDK: add successRateBps and lastActiveTimestamp to AgentStats interface - SDK: update parseAgentStats to deserialise new fields - Tests: 4 new tests in src/test_agent_stats.rs covering default stats, post-confirm_payout, post-mark_failed, and mixed-outcome success_rate_bps=7500 - Fix: update AgentStats literal in test_escrow.rs to include new fields
…enum in parseContractError
…Haroldwonder#688 - Haroldwonder#685 Toast.tsx: add type-based auto-dismiss defaults (error=5s, success=3s) and pause-on-hover with remaining-time tracking - Haroldwonder#686 DisputeResolution.tsx: capture tx_hash from resolve response and display it with a Stellar Expert explorer link - Haroldwonder#687 sdk/src/test-utils.ts: extract makeProposalScVal into shared test utilities file and export it; update governance.test.ts import - Haroldwonder#688 settlements.ts: validate sender/agent are valid Stellar addresses (G... 56 chars) before processing net settlements
Add senderAddress prop to SendMoneyFlow and update isValidRecipient to reject addresses that match the sender's own address. Closes Haroldwonder#678
Remove stored walletSession from localStorage and reset connected state when Freighter reports a network different from the expected defaultNetwork, prompting the user to reconnect. Closes Haroldwonder#680
Intercept Tab/Shift+Tab when the dropdown is open to cycle focus through options instead of allowing it to escape the dropdown. Closes Haroldwonder#683
…nfig.js Configure server.headers with a strict CSP restricting script-src to 'self', blocking inline scripts, and limiting connect-src to known Stellar API origins. Closes Haroldwonder#677
…-619-620 fix: resolve issues Haroldwonder#617, Haroldwonder#618, Haroldwonder#619, Haroldwonder#620 — pagination, dispute event, daily limit, governance timelock
…n-error-export fix(backend): restore ValidationError prototype chain for instanceof (Haroldwonder#656)
…ate-limit-retry fix(frontend): retry with exponential backoff + fee cache for Horizon 429s (Haroldwonder#667)
…ountdown fix(frontend): FX rate countdown and expiry warning on review step (Haroldwonder#670)
…it-status-docs fix(sdk): document DailyLimitStatus stroops units and add stroopsToUsdc helper (Haroldwonder#676)
…-field-validation fix(Haroldwonder#655): validate SIGNING_KEY and NETWORK_PASSPHRASE in fetchAnchorToml
…ination fix(Haroldwonder#664): add pagination to fetchDisputes in DisputeResolution
…-state fix(Haroldwonder#663): add expired visual state to KycStatusBadge
…validation fix(Haroldwonder#672): fix parseContractError numeric enum validation
…88-toast-dispute-governance-settlements fix: toast auto-dismiss, dispute tx hash, test-utils export, address validation
…nsfer-check fix(Haroldwonder#678): prevent self-transfer in SendMoneyFlow
…ssion-network-mismatch fix(Haroldwonder#680): clear localStorage session on network mismatch
…ap-dropdown fix(Haroldwonder#683): trap keyboard focus within AnchorSelector dropdown
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes Haroldwonder#677
Changes
server.headerstovite.config.jswith aContent-Security-Policyheaderscript-src 'self'— blocks inline scripts and external script loadingconnect-srclimited to'self'and known Stellar API origins (horizon, horizon-testnet, stellar.expert)object-src 'none',frame-ancestors 'none',base-uri 'self'for additional hardening