@ninepayjs/guardian-sdk
v0.1.1
Published
SDK do Guardian (antifraude da NinePay): fingerprint do dispositivo e sinais de comportamento no checkout, sem o conteúdo dos campos.
Readme
Guardian SDK (@ninepayjs/guardian-sdk)
O lado do navegador do Guardian, o antifraude da NinePay: a impressão digital do dispositivo (ThumbmarkJS) e os sinais de comportamento no checkout (ritmo de digitação, mouse, toque, colagem, autopreenchimento), mandados para a API do Guardian. O session_id vai junto com o pagamento, e a API de pagamentos pede a análise ao Guardian antes de cobrar.
Instalar
O escopo é @ninepayjs, a organização da NinePay no npm (conta ti-ninepay). Um guardian-sdk sem escopo, ou em outro escopo, não é nosso.
npm install --save-exact @ninepayjs/guardian-sdkNuma página de pagamento, o SDK entra no bundle da página (a versão fixa no package-lock.json, revisada a cada troca), e não por <script> de uma CDN: assim ele não é um script de terceiro para o PCI DSS (req. 6.4.3), e a CSP não precisa liberar outro host em script-src.
Uso
import { init, flush, getSessionId } from '@ninepayjs/guardian-sdk'
await init({
publicKey: 'grd_pk_...', // a chave pública da company, presa à origem da página
inputFieldIds: ['cardNumber', 'cardHolder', 'email'],
styleNonce: '<o nonce da CSP da página>', // opcional, ver "CSP"
})
// Ao clicar em "Pagar":
await flush() // envia os eventos ainda pendentes
const sessionId = await getSessionId() // mande junto com o pagamento; se vier undefined, não mande o campo| Opção | Padrão | O que é |
|-|-|-|
| publicKey | — | A chave pública da company (grd_pk_...). Sem ela, ou numa origem que não está liberada na chave, o Guardian recusa a sessão (401/403). |
| apiUrl | https://guardian.ninepay.com.br/api | A API do Guardian (outra só em desenvolvimento). |
| interval | 5000 | De quanto em quanto tempo (ms) os eventos vão para a API. |
| inputFieldIds | — | Os ids dos campos cujo preenchimento é medido. |
| styleNonce | — | O nonce da CSP, para o <style> da detecção de autopreenchimento nos navegadores sem CSSStyleSheet construível. |
getSessionId()espera oinitterminar e devolveundefinedse a sessão não pôde ser criada. Sem sessão, o SDK não envia eventos.- Um envio que falha por rede,
429ou5xxdevolve os eventos ao lote seguinte, com no máximo 1.500 eventos de mouse e toque por lote (ficam os mais recentes). - Se o Guardian recusa a sessão (
404: vencida, depois de 1 h, ou de outra company;401: chave;403: origem), o SDK para de enviar, e ogetSessionId()passa a devolverundefined: o pagamento não leva uma sessão que o Guardian ignoraria. Um lote recusado por tamanho (413) é descartado.
O que sai do navegador
Só duas chamadas, as duas para a apiUrl, com a chave pública no cabeçalho x-guardian-key:
POST /sessions/init: o fingerprint e os componentes do dispositivo (thumbmarkData), uma vez por sessão.POST /sessions/event, a cadaintervale noflush(): o fingerprint, os movimentos do mouse e do toque (posição e tempo), o total de teclas (sem quais) e, por campo, os tempos e tamanhos do que foi digitado, colado ou preenchido.
Nunca sai o conteúdo de um campo, nem qual tecla foi apertada, nem o texto colado (só o tamanho dele). Um campo de CVV (autocomplete="cc-csc") nunca é medido, mesmo que esteja em inputFieldIds. Os testes (test/sdk.test.ts) conferem as três coisas e que nenhuma requisição vai para fora da apiUrl.
ThumbmarkJS
A versão é fixa (1.12.0) e a telemetria dele fica desligada (logging: false, collect_beacon: false): nada do dispositivo do cliente vai para thumbmarkjs.com. O código dele ainda traz, no caminho de logging (desligado), um script remoto executado com eval; ele nunca é alcançado, e numa página com CSP sem 'unsafe-eval' o navegador o barraria de qualquer jeito. Trocar de versão é um PR que revisa de novo esses caminhos.
CSP
connect-src: a origem daapiUrl(https://guardian.ninepay.com.br).- A detecção de autopreenchimento usa um CSS de animações. Ele vai por uma folha de estilo construída (
CSSStyleSheet+document.adoptedStyleSheets), que a CSP não barra; nos navegadores sem ela, por um<style>com ostyleNonce. - O ThumbmarkJS lê canvas, WebGL, áudio e fontes (com um
<iframe>about:blankque ele cria e tira na hora). Nada disso sai da página.
Desenvolvimento
npm ci
npm run typecheck
npm test
npm run build # dist/index.js e dist/index.d.ts
make dev # tsdown --watch no Docker; a página de teste manual é test/teste.htmlPublicar
npm version <patch|minor|major>
npm publish # o prepublishOnly roda tipos, testes e build antes