Skip to content
GitLab
Projects Groups Topics Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Register
  • Sign in
  • A Ahad Mobile
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
  • Issues 0
    • Issues 0
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Terraform modules
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • holatech
  • Ahad Mobile
  • Merge requests
  • !87

feat: show card details through the keysecure pci iframe sdk

  • Review changes

  • Download
  • Patches
  • Plain diff
Merged Khanh Pham requested to merge feat/keysecure-sp4b2-card-details into develop Oct 02, 2026
  • Overview 0
  • Commits 10
  • Pipelines 1
  • Changes 27

Summary

Cardholders can now see their card number, expiry date and CVV in the app. The data is shown through KeySecure's PCI iframe SDK, so it never passes through our backend or the app's JavaScript.

  • Backend, GET /card-display: a new public page that loads the KeySecure SDK.
    • It picks the sandbox or production SDK from the KeySecure config.
    • Headers: a nonce CSP whose script-src allows only the nonce'd inline script and https://paysdk.keysecure.io, plus exact frame-src hosts, Cache-Control: no-store and Referrer-Policy: strict-origin.
    • The page needs no auth. It holds no secret and never echoes request input.
    • It reports to the app through window.ReactNativeWebView.postMessage: ready, success, failure with a code, and copy. It never posts the token or any card data.
  • App, card detail screen: "Card details" is enabled for ACTIVE cards. Tapping it goes through the passcode sheet, then calls POST /card-account/cards/:id/client-token (already in the backend), then opens a full-screen WebView overlay.
    • The one-time token lives only in component state. The mutation cache is reset as soon as the token is copied out.
    • The token is injected only after the page posts ready. It never goes into a URL, route param, storage or log.
    • The overlay closes when the token expires, when the screen loses focus, and on any SDK or page failure, an HTTP or render-process error, or a timeout. Every failure ends in a toast; the overlay never hangs.
    • While the overlay is open, screenshots and recording are blocked (expo-screen-capture) and the app-switcher snapshot is blurred on iOS.
    • The overlay only loads the page origin and the KeySecure hosts. It refuses to open if CARD_DISPLAY_URL is not https.
  • Dependencies and config:
    • react-native-webview and expo-screen-capture are new direct dependencies. They need a new binary; this cannot ship by OTA.
    • New FE env var CARD_DISPLAY_URL.
    • The client-token route is added to isCredentialCheck, so a wrong passcode is not refreshed and replayed.
  • "Coming soon" footer: removed from card detail.

Testing

  • FE: pnpm type-check is clean and pnpm jest passes 113 suites, 1061 tests.
  • BE: card-account jest passes 181 tests. The card-display-page spec has 13 tests: real Fastify requests, plus the bridge script run in a node vm sandbox.
  • eslint is clean on the changed files.

Notes / follow-ups

  • No SRI on the SDK script. KeySecure's SDK CDN (S3/CloudFront) sends no Access-Control-Allow-Origin, so an integrity/crossorigin tag would be blocked on our origin. CSP still pins the script origin. Ask ChainUp to enable CORS on that bucket so SRI can come back.
  • End-to-end test still blocked. It needs this branch on staging, the registered sandbox origin (https://ahad.holadev.xyz, done), and an ACTIVE card. Card issue still returns 3008 until ChainUp funds the reserve.
  • Production: API_URL is http today, so the overlay refuses to open in prod until there is an https origin, and that origin is registered in the production portal.
  • Device checks:
    • Android: does FLAG_SECURE cover the overlay?
    • Does the SDK use about:blank or srcdoc sub-frames (currently blocked by the allowlist)?
    • Does a real reveal finish within the 20 s timeouts?
  • Minor:
    • A token that resolves after the user leaves the screen can still mount the overlay off-screen until expiry.
    • CSP could pin the exact SDK path instead of the whole origin.

🤖 Generated with Claude Code

Assignee
Assign to
Reviewers
Request review from
Time tracking
Source branch: feat/keysecure-sp4b2-card-details