@autra-io/react-native-card 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,52 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ - `AutraCardForm`: hosted-WebView card tokenization component. Loads only a
13
+ backend-created `hostedCardUrl` (hosted card session); no provider token
14
+ ever reaches the app. Strict postMessage schema with origin allow-list and
15
+ field allow-list on `tokenized` payloads.
16
+ - WebView hardening: HTTPS-only hosted URL, full navigation allow-list in
17
+ `onShouldStartLoadWithRequest` with wildcard `originWhitelist` (blocked
18
+ navigations never escape to the OS browser), `incognito` +
19
+ `cacheEnabled: false` (no disk persistence of the hosted page),
20
+ `mixedContentMode: 'never'`, `allowFileAccess: false`.
21
+ - Terminal guard: after a successful `tokenized` message, duplicate messages
22
+ and stray errors are ignored (no double `onSuccess`).
23
+ - `onHttpError` document-vs-sub-resource discrimination: sub-resource
24
+ failures (favicon/assets/page fetches) no longer abort the flow.
25
+ - `allowedOrigins` normalization: trailing slashes are canonicalized and
26
+ non-HTTPS entries dropped; an empty normalized list is a
27
+ `configuration_error`.
28
+ - Configuration errors are emitted from an effect (never during render).
29
+ - Functional mock-API React Native app test harness
30
+ (`test/functional-app/`).
31
+ - Public exports in `src/index.ts`
32
+ (`AutraCardForm`, `AUTRA_REACT_NATIVE_CARD_SDK_VERSION`,
33
+ `AutraCardTokenizedResult`, `AutraCardError`).
34
+ - Repository foundation: package scaffold (`package.json`, `tsconfig`, tsup,
35
+ Vitest, ESLint flat config, Prettier).
36
+ - CI workflow (Node 20 & 22) and package-smoke job.
37
+ - Security workflow: `npm audit` (gate), gitleaks (gate), semgrep (advisory).
38
+ - Dependabot (npm + github-actions), CODEOWNERS, PR template.
39
+ - Pre-commit configuration (pre-commit framework).
40
+ - GitHub Copilot review instructions.
41
+ - Integration documentation (`docs/platform.md`, `docs/integration/*`).
42
+ - Secret-safety: `.gitignore`/`.env.example` guardrails and package smoke test.
43
+
44
+ ### Changed
45
+
46
+ - Package prepared for public release: MIT license, `publishConfig.access:
47
+ public`; publishing remains manual and gated (see `docs/platform.md`).
48
+
49
+ ### Notes
50
+
51
+ - No version has been published to npm yet; the entries above will ship as
52
+ `0.1.0`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Autra
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,298 @@
1
+ # @autra-io/react-native-card
2
+
3
+ React Native SDK for secure card tokenization via Autra's hosted card page.
4
+ **Card data never touches your app or your servers.**
5
+
6
+ [![CI](https://github.com/autratech/autra-card-sdk-react-native/actions/workflows/ci.yml/badge.svg)](https://github.com/autratech/autra-card-sdk-react-native/actions/workflows/ci.yml)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
8
+ <!-- Enable after the first npm publish:
9
+ [![npm version](https://img.shields.io/npm/v/%40autra-io%2Freact-native-card.svg)](https://www.npmjs.com/package/@autra-io/react-native-card)
10
+ -->
11
+
12
+ > 🇧🇷 [Leia este README em português](./README.pt-BR.md) · Guias completos em
13
+ > português no portal do desenvolvedor <!-- PLACEHOLDER: developer portal URL -->
14
+
15
+ ## Table of contents
16
+
17
+ - [Features](#features)
18
+ - [Requirements](#requirements)
19
+ - [Installation](#installation)
20
+ - [How it works](#how-it-works)
21
+ - [Quickstart](#quickstart)
22
+ - [API reference](#api-reference)
23
+ - [Security & PCI](#security--pci)
24
+ - [Testing your integration](#testing-your-integration)
25
+ - [Troubleshooting](#troubleshooting)
26
+ - [Documentation](#documentation)
27
+ - [Contributing](#contributing)
28
+ - [Support](#support)
29
+ - [License](#license)
30
+
31
+ ## Features
32
+
33
+ - **Hosted-page tokenization** — the cardholder types PAN/CVV on an
34
+ Autra-hosted page rendered inside a WebView. Card data never transits your
35
+ app or your backend, which helps reduce your PCI DSS scope.
36
+ - **Hardened WebView out of the box** — HTTPS-only, full navigation
37
+ allow-list (blocked navigations never escape to the OS browser),
38
+ `mixedContentMode: 'never'`, incognito mode, no disk cache, no file access.
39
+ - **Strict message bridge** — origin allow-list and schema validation on every
40
+ message from the hosted page; a terminal guard makes `onSuccess` fire at
41
+ most once.
42
+ - **Typed end to end** — `AutraCardFormProps`, `AutraCardTokenizedResult` and
43
+ a normalized `AutraCardError` taxonomy, all in TypeScript.
44
+ - **Zero runtime dependencies** — the SDK adds nothing to your bundle beyond
45
+ its own component; `react-native-webview` is a peer dependency you control.
46
+
47
+ ## Requirements
48
+
49
+ | Dependency | Version |
50
+ | ---------------------- | --------- |
51
+ | React | >= 18.0.0 |
52
+ | React Native | >= 0.72.0 |
53
+ | `react-native-webview` | >= 13.0.0 |
54
+
55
+ - `react-native-webview` is a **required peer dependency** — install it in
56
+ your app (see below); the SDK does not bundle it.
57
+ - **Expo**: works with development builds / `expo prebuild` (because
58
+ `react-native-webview` contains native code). Expo Go is not supported.
59
+ <!-- PLACEHOLDER: confirm official Expo support statement with the team -->
60
+ - **New Architecture**: the SDK itself has no native code; support follows
61
+ your installed `react-native-webview` version.
62
+ <!-- PLACEHOLDER: confirm New Architecture statement with the team -->
63
+ - Node.js >= 20 is only required to develop this repository, not to use the
64
+ SDK.
65
+
66
+ ## Installation
67
+
68
+ ```bash
69
+ npm install @autra-io/react-native-card react-native-webview
70
+ # or
71
+ yarn add @autra-io/react-native-card react-native-webview
72
+ ```
73
+
74
+ iOS (bare React Native):
75
+
76
+ ```bash
77
+ cd ios && pod install
78
+ ```
79
+
80
+ Expo:
81
+
82
+ ```bash
83
+ npx expo install react-native-webview
84
+ npm install @autra-io/react-native-card
85
+ ```
86
+
87
+ ## How it works
88
+
89
+ ```mermaid
90
+ sequenceDiagram
91
+ participant App as Your app (SDK)
92
+ participant Backend as Your backend
93
+ participant Autra as Autra Platform API
94
+ participant Page as Autra hosted card page
95
+
96
+ App->>Backend: request a card session
97
+ Backend->>Autra: POST /v1/acquiring/card-sessions (service credentials)
98
+ Autra-->>Backend: hostedCardUrl (short-lived, single-use)
99
+ Backend-->>App: hostedCardUrl
100
+ App->>Page: <AutraCardForm hostedCardUrl /> loads the page in a WebView
101
+ Note over Page: Cardholder types PAN/CVV here —<br/>never in your app
102
+ Page->>Autra: tokenize (direct, over HTTPS)
103
+ Autra-->>Page: opaque token references
104
+ Page-->>App: postMessage: tokenized
105
+ App->>Backend: slugStoredCard (opaque) for future charges
106
+ ```
107
+
108
+ Card data flows only between the cardholder and Autra's hosted page — it never
109
+ transits your app or backend. Your systems only ever see two opaque values:
110
+ the short-lived `hostedCardUrl` going in, and the `slugStoredCard` /
111
+ `slugToken` references coming out.
112
+
113
+ ## Quickstart
114
+
115
+ ### Step 1 — Backend: create a hosted card session
116
+
117
+ Card sessions are created **server-side** with your Autra service credentials.
118
+ Never call this from the app, and never embed credentials in the app.
119
+
120
+ ```ts
121
+ // Your backend (Node example). Sandbox base URL: https://api.sandbox.autra.io
122
+ // Production: see the developer portal. <!-- PLACEHOLDER: production URL -->
123
+ app.post('/card-sessions', async (_req, res) => {
124
+ const response = await fetch('https://api.sandbox.autra.io/v1/acquiring/card-sessions', {
125
+ method: 'POST',
126
+ headers: {/* your Autra service credentials — server-side only */},
127
+ });
128
+ const { hostedCardUrl } = await response.json();
129
+ // hostedCardUrl is short-lived and single-use — mint one per attempt.
130
+ res.json({ hostedCardUrl });
131
+ });
132
+ ```
133
+
134
+ ### Step 2 — App: render the form
135
+
136
+ ```tsx
137
+ import { useState } from 'react';
138
+ import { Button, View } from 'react-native';
139
+ import {
140
+ AutraCardForm,
141
+ type AutraCardTokenizedResult,
142
+ type AutraCardError,
143
+ } from '@autra-io/react-native-card';
144
+
145
+ export function AddCardScreen() {
146
+ const [hostedCardUrl, setHostedCardUrl] = useState<string | null>(null);
147
+
148
+ async function startCardEntry() {
149
+ // Ask YOUR backend for a fresh session (Step 1). URLs are single-use:
150
+ // request a new one for every attempt — never hardcode or reuse them.
151
+ const response = await fetch('https://your-backend.example.com/card-sessions', {
152
+ method: 'POST',
153
+ });
154
+ const body = (await response.json()) as { hostedCardUrl: string };
155
+ setHostedCardUrl(body.hostedCardUrl);
156
+ }
157
+
158
+ if (!hostedCardUrl) {
159
+ return <Button title="Add card" onPress={startCardEntry} />;
160
+ }
161
+
162
+ return (
163
+ <View style={{ flex: 1 }}>
164
+ <AutraCardForm
165
+ hostedCardUrl={hostedCardUrl}
166
+ onReady={() => {
167
+ // Hosted page is interactive — hide your loading indicator.
168
+ }}
169
+ onSuccess={(result: AutraCardTokenizedResult) => {
170
+ // Send result.slugStoredCard to your backend and store it there.
171
+ // Your backend uses it later to charge the card — the app is done.
172
+ }}
173
+ onError={(error: AutraCardError) => {
174
+ if (error.code === 'token_expired' || error.retryable) {
175
+ // Sessions are short-lived: create a NEW session and retry.
176
+ setHostedCardUrl(null);
177
+ return;
178
+ }
179
+ // Non-retryable: surface a friendly message and report error.code.
180
+ }}
181
+ style={{ flex: 1 }}
182
+ />
183
+ </View>
184
+ );
185
+ }
186
+ ```
187
+
188
+ ## API reference
189
+
190
+ ### `<AutraCardForm />`
191
+
192
+ | Prop | Type | Required | Description |
193
+ | ---------------- | -------------------------------------------- | -------- | --------------------------------------------------------------------------------------------- |
194
+ | `hostedCardUrl` | `string` | yes | Short-lived hosted card session URL created by your backend. Must be HTTPS. |
195
+ | `onSuccess` | `(result: AutraCardTokenizedResult) => void` | yes | Fires **at most once**, on successful tokenization. Later messages are ignored. |
196
+ | `onError` | `(error: AutraCardError) => void` | yes | Fires on configuration, session, navigation or tokenization errors. |
197
+ | `onReady` | `(requestId?: string) => void` | no | Hosted page validated the session and is interactive. |
198
+ | `allowedOrigins` | `readonly string[]` | no | HTTPS origins allowed for navigation and messages. Defaults to the origin of `hostedCardUrl`. |
199
+ | `style` | `StyleProp<ViewStyle>` | no | Style for the underlying WebView. |
200
+ | `testID` | `string` | no | Test identifier forwarded to the WebView. |
201
+
202
+ ### `AutraCardTokenizedResult`
203
+
204
+ All fields are **opaque references** — the SDK never exposes card data.
205
+
206
+ | Field | Type | Description |
207
+ | --------------------- | --------- | ------------------------------------------------------------ |
208
+ | `slugStoredCard` | `string?` | Reference your backend uses to charge the stored card later. |
209
+ | `slugToken` | `string?` | Single-purpose token reference. |
210
+ | `tokenExpirationDate` | `string?` | Expiration of the token reference. |
211
+ | `brand` | `string?` | Card brand (display only). |
212
+ | `last4` | `string?` | Last four digits (display only). |
213
+ | `expirationMonth` | `string?` | Card expiration month (display only). |
214
+ | `expirationYear` | `string?` | Card expiration year (display only). |
215
+ | `requestId` | `string?` | Correlation id for support requests. |
216
+
217
+ At least one of `slugStoredCard` / `slugToken` is always present on success.
218
+
219
+ ### `AutraCardError`
220
+
221
+ `{ code, message, requestId?, retryable? }`. Handle by `code`; when
222
+ `retryable` is `true`, create a **new** session and retry.
223
+
224
+ | Code | Meaning | What to do |
225
+ | ------------------------- | ------------------------------------------------------------- | ----------------------------------------------- |
226
+ | `configuration_error` | Invalid/non-HTTPS `hostedCardUrl`, or empty `allowedOrigins`. | Fix the integration — not user-recoverable. |
227
+ | `token_expired` | Session expired or unauthorized (sessions are short-lived). | Create a new session and reload the form. |
228
+ | `message_origin_rejected` | Message or navigation from an origin outside the allow-list. | Investigate; do not weaken `allowedOrigins`. |
229
+ | `message_invalid` | Malformed message from the hosted page. | Retry with a new session; report `requestId`. |
230
+ | `validation_error` | Cardholder input rejected. | The hosted page guides the user; no app action. |
231
+ | `tokenization_failed` | Page failed to load or tokenization failed upstream. | If `retryable`, retry with a new session. |
232
+
233
+ ### `AUTRA_REACT_NATIVE_CARD_SDK_VERSION`
234
+
235
+ Version marker string, useful for support tickets and smoke tests.
236
+
237
+ ## Security & PCI
238
+
239
+ - Card data (PAN, CVV, cardholder data) is entered **only** on the
240
+ Autra-hosted page and sent directly to Autra — it never transits your app or
241
+ backend, which helps reduce your PCI DSS scope.
242
+ - Your app only handles the opaque, short-lived `hostedCardUrl` (in) and the
243
+ opaque `slugStoredCard` / `slugToken` references (out).
244
+ - Keep service credentials (`clientSecret`, strong access tokens) **server-side
245
+ only** — never embed them in the app.
246
+ - Never log PAN/CVV/cardholder data, and never log the `hostedCardUrl`. Use
247
+ `requestId` for correlation.
248
+ - The WebView is hardened by default: HTTPS-only, navigation allow-list,
249
+ no mixed content, incognito, no disk cache, no file access.
250
+
251
+ Found a vulnerability? See [SECURITY.md](./SECURITY.md) — please do not open a
252
+ public issue.
253
+
254
+ ## Testing your integration
255
+
256
+ - Use the **sandbox** environment (`https://api.sandbox.autra.io`) with mock
257
+ values only — never real card data.
258
+ <!-- PLACEHOLDER: sandbox test card numbers, if provided by the team -->
259
+ - For unit tests, inject your session-creation function and mock the WebView
260
+ bridge — see
261
+ [`test/functional-app/`](./test/functional-app/FunctionalAutraCardApp.ts)
262
+ for a complete reference harness driving `ready`, `tokenized` and `error`
263
+ flows with a mocked backend.
264
+
265
+ ## Troubleshooting
266
+
267
+ - **Blank WebView** — `react-native-webview` is not installed/linked. Install
268
+ it (see [Installation](#installation)) and run `pod install` on iOS.
269
+ - **`configuration_error` immediately** — the `hostedCardUrl` is malformed or
270
+ not HTTPS, or your custom `allowedOrigins` normalized to an empty list.
271
+ - **`token_expired`** — hosted sessions are short-lived and single-use. Create
272
+ a session right before rendering the form, one per attempt.
273
+ - **Nothing happens after submit** — check that you are not filtering the
274
+ hosted page's origin out via a custom `allowedOrigins`.
275
+ - **Cleartext/HTTP hosted URL** — not supported by design; the SDK rejects
276
+ non-HTTPS URLs.
277
+
278
+ ## Documentation
279
+
280
+ - Integration guides: developer portal
281
+ <!-- PLACEHOLDER: developer portal URL (EN + PT-BR) -->
282
+ - [Backend flow overview](./docs/integration/backend-flow.md)
283
+ - [SDK scope and limitations](./docs/integration/limitations.md)
284
+
285
+ ## Contributing
286
+
287
+ See [CONTRIBUTING.md](./CONTRIBUTING.md). Never include real card data or
288
+ secrets in issues, PRs or examples.
289
+
290
+ ## Support
291
+
292
+ - Bugs and feature requests:
293
+ [GitHub issues](https://github.com/autratech/autra-card-sdk-react-native/issues)
294
+ - Integration support: <!-- PLACEHOLDER: support channel/email -->
295
+
296
+ ## License
297
+
298
+ [MIT](./LICENSE)
@@ -0,0 +1,133 @@
1
+ <!--
2
+ Este arquivo espelha apenas o essencial (features, instalação, quickstart,
3
+ erros) do README.md. Ao alterar o quickstart ou a API no README.md,
4
+ atualize este arquivo também. A documentação completa vive no README.md.
5
+ -->
6
+
7
+ # @autra-io/react-native-card
8
+
9
+ SDK React Native para tokenização segura de cartões via página hospedada da
10
+ Autra. **Os dados do cartão nunca passam pelo seu app nem pelos seus
11
+ servidores.**
12
+
13
+ > 🌎 [Read this README in English](./README.md) (documentação completa) ·
14
+ > Guias completos no portal do desenvolvedor
15
+ > <!-- PLACEHOLDER: URL do portal do desenvolvedor -->
16
+
17
+ ## Por que usar
18
+
19
+ - **Tokenização em página hospedada** — o portador digita PAN/CVV em uma
20
+ página hospedada pela Autra, dentro de uma WebView. Os dados do cartão nunca
21
+ transitam pelo seu app ou backend, o que ajuda a reduzir seu escopo PCI DSS.
22
+ - **WebView endurecida por padrão** — HTTPS-only, allow-list de navegação,
23
+ sem conteúdo misto, incognito, sem cache em disco, sem acesso a arquivos.
24
+ - **Bridge de mensagens estrita** — validação de origem e de schema em toda
25
+ mensagem; `onSuccess` dispara no máximo uma vez.
26
+ - **Tipado de ponta a ponta** e **zero dependências de runtime**.
27
+
28
+ ## Instalação
29
+
30
+ ```bash
31
+ npm install @autra-io/react-native-card react-native-webview
32
+ # iOS (React Native bare): cd ios && pod install
33
+ # Expo: npx expo install react-native-webview
34
+ ```
35
+
36
+ Requisitos: React >= 18, React Native >= 0.72, `react-native-webview` >= 13
37
+ (peer dependency obrigatória). Expo: requer development build / `expo
38
+ prebuild` (Expo Go não é suportado).
39
+
40
+ ## Início rápido
41
+
42
+ ### Passo 1 — Backend: criar uma sessão de cartão hospedada
43
+
44
+ As sessões são criadas **no servidor**, com suas credenciais de serviço Autra.
45
+ Nunca chame esta API do app e nunca embuta credenciais no app.
46
+
47
+ ```ts
48
+ // Seu backend (exemplo Node). Sandbox: https://api.sandbox.autra.io
49
+ // Produção: consulte o portal do desenvolvedor. <!-- PLACEHOLDER: URL produção -->
50
+ app.post('/card-sessions', async (_req, res) => {
51
+ const response = await fetch('https://api.sandbox.autra.io/v1/acquiring/card-sessions', {
52
+ method: 'POST',
53
+ headers: {/* credenciais de serviço Autra — somente no servidor */},
54
+ });
55
+ const { hostedCardUrl } = await response.json();
56
+ // hostedCardUrl é de curta duração e uso único — gere uma por tentativa.
57
+ res.json({ hostedCardUrl });
58
+ });
59
+ ```
60
+
61
+ ### Passo 2 — App: renderizar o formulário
62
+
63
+ ```tsx
64
+ import { useState } from 'react';
65
+ import { Button, View } from 'react-native';
66
+ import {
67
+ AutraCardForm,
68
+ type AutraCardTokenizedResult,
69
+ type AutraCardError,
70
+ } from '@autra-io/react-native-card';
71
+
72
+ export function AdicionarCartaoScreen() {
73
+ const [hostedCardUrl, setHostedCardUrl] = useState<string | null>(null);
74
+
75
+ async function iniciarEntradaDeCartao() {
76
+ // Peça ao SEU backend uma sessão nova (Passo 1). URLs são de uso único:
77
+ // solicite uma nova a cada tentativa — nunca fixe ou reutilize.
78
+ const response = await fetch('https://seu-backend.example.com/card-sessions', {
79
+ method: 'POST',
80
+ });
81
+ const body = (await response.json()) as { hostedCardUrl: string };
82
+ setHostedCardUrl(body.hostedCardUrl);
83
+ }
84
+
85
+ if (!hostedCardUrl) {
86
+ return <Button title="Adicionar cartão" onPress={iniciarEntradaDeCartao} />;
87
+ }
88
+
89
+ return (
90
+ <View style={{ flex: 1 }}>
91
+ <AutraCardForm
92
+ hostedCardUrl={hostedCardUrl}
93
+ onReady={() => {
94
+ // Página hospedada pronta — esconda seu indicador de carregamento.
95
+ }}
96
+ onSuccess={(result: AutraCardTokenizedResult) => {
97
+ // Envie result.slugStoredCard ao seu backend e armazene lá.
98
+ // O backend usa essa referência para cobranças futuras.
99
+ }}
100
+ onError={(error: AutraCardError) => {
101
+ if (error.code === 'token_expired' || error.retryable) {
102
+ // Sessões expiram rápido: crie uma NOVA sessão e tente de novo.
103
+ setHostedCardUrl(null);
104
+ return;
105
+ }
106
+ // Não recuperável: mostre uma mensagem amigável e reporte error.code.
107
+ }}
108
+ style={{ flex: 1 }}
109
+ />
110
+ </View>
111
+ );
112
+ }
113
+ ```
114
+
115
+ ## Códigos de erro (`AutraCardError`)
116
+
117
+ | Código | Significado | O que fazer |
118
+ | ------------------------- | ------------------------------------------------------------- | ---------------------------------------------- |
119
+ | `configuration_error` | `hostedCardUrl` inválida/não-HTTPS ou `allowedOrigins` vazio. | Corrigir a integração — não é erro do usuário. |
120
+ | `token_expired` | Sessão expirada ou não autorizada. | Criar nova sessão e recarregar o formulário. |
121
+ | `message_origin_rejected` | Mensagem/navegação de origem fora da allow-list. | Investigar; não enfraquecer `allowedOrigins`. |
122
+ | `message_invalid` | Mensagem malformada da página hospedada. | Tentar com nova sessão; reportar `requestId`. |
123
+ | `validation_error` | Dados do cartão rejeitados. | A própria página orienta o usuário. |
124
+ | `tokenization_failed` | Falha de carregamento ou de tokenização. | Se `retryable`, tentar com nova sessão. |
125
+
126
+ ## Documentação completa
127
+
128
+ Referência completa da API, segurança & PCI, testes e troubleshooting:
129
+ [README.md (English)](./README.md).
130
+
131
+ ## Licença
132
+
133
+ [MIT](./LICENSE)
package/SECURITY.md ADDED
@@ -0,0 +1,61 @@
1
+ # Security Policy
2
+
3
+ `@autra-io/react-native-card` is a **payment-adjacent SDK**. Card data and
4
+ credentials demand strict handling. This policy is mandatory for all
5
+ contributors (human and AI).
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ - **Do not** open a public GitHub issue for security vulnerabilities.
10
+ - Report privately via
11
+ [GitHub private vulnerability reporting](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability)
12
+ on this repository, or by email to `security@autra.io`
13
+ <!-- PLACEHOLDER: confirm the public security contact email with the team -->.
14
+ - Include: affected version/commit, impact, and reproduction steps using
15
+ **non-sensitive, mock data only**.
16
+
17
+ > **Never** paste PAN, CVV, cardholder data, real tokens, secrets or sensitive
18
+ > logs into an issue, PR, comment or vulnerability report.
19
+
20
+ ## Handling card & payment data
21
+
22
+ - **Never** log or store PAN, CVV, expiry or cardholder data — anywhere
23
+ (app logs, SDK payloads, tests, fixtures, docs, examples).
24
+ - **Never** use real card data in tests or examples. Use mock/fake values.
25
+ - Logs and errors reference `requestId` / `correlationId` only.
26
+ - The tokenized card is referenced by an opaque `slugStoredCard`.
27
+
28
+ ## Credentials & tokens
29
+
30
+ - **`clientSecret` (OAuth) never goes to the mobile app.**
31
+ - **A strong `accessToken` never goes to the mobile app.**
32
+ - **No provider token of any kind reaches the app.** The app only ever handles
33
+ a short-lived, single-use **`hostedCardUrl`** (hosted card session) created
34
+ by your backend; card entry and tokenization happen inside the hosted page.
35
+ - Never commit secrets, tokens, private keys or credentials.
36
+ - `.env` and `.env.*` are git-ignored; only `.env.example` (placeholders) is
37
+ committed. Real credentials belong in your secret manager — never in the repo.
38
+
39
+ ## If a secret is exposed
40
+
41
+ 1. **Rotate the secret immediately** (before removing it from history).
42
+ 2. Report it through the vulnerability-reporting channel above.
43
+ 3. Remove it from the working tree and, if needed, purge from git history.
44
+ 4. Verify `gitleaks` passes and confirm no other copies remain.
45
+
46
+ ## Security tooling (must stay active)
47
+
48
+ - **pre-commit** hooks (`.pre-commit-config.yaml`): hygiene, secret/env guard,
49
+ gitleaks, prettier, eslint, typecheck, `no-commit-to-branch=main`.
50
+ - **CI security workflow** (`.github/workflows/security.yml`):
51
+ - `npm audit --omit=dev --audit-level=high` (GATE)
52
+ - `gitleaks` secret scan (GATE)
53
+ - `semgrep` SAST (advisory — may become a required gate later)
54
+
55
+ Do not disable or weaken these controls.
56
+
57
+ ## Supported versions
58
+
59
+ | Version | Supported |
60
+ | ------- | -------------------------------------- |
61
+ | `0.x` | Latest minor release (pre-1.0 preview) |