Segurança e compatibilidade
Segurança
A confiança é mútua: o app host valida quem chama pelo pacote e pelo certificado de assinatura, e o seu app valida o host com verifyHost. Uma metade sozinha não protege a loja. As regras abaixo são obrigatórias para homologação.
| Regra | Por quê |
|---|---|
Intent sempre explícita (setPackage("com.tupifintech.pos.service")) | Com uma Intent implícita ou broadcast, qualquer app instalado poderia capturar o payload de pagamento. O PosIntegrationClient já monta a Intent assim |
| Valide o host antes da primeira operação | Sem verifyHost, um APK falso com o mesmo pacote pode responder approved com um cupom plausível |
| Dados de cartão nunca cruzam a fronteira entre os apps | Número completo, trilhas, bloco de senha e criptogramas ficam no terminal. O comprovante expõe só bandeira, 6 primeiros e 4 últimos dígitos |
| Senhas nunca trafegam na Intent | As senhas de usuários locais e de Supervisor são digitadas na tela do terminal |
Não envie dado de portador em metadata | O campo é gravado no terminal e segue para o backend |
| Operações administrativas exigem alguém no aparelho | O seu app pode pedir o credenciamento, a ativação e a gestão de usuários, mas quem conclui é a pessoa no terminal: aprova o app, digita o cadastro do estabelecimento ou a senha de Supervisor. Nenhum desses dados viaja na Intent |
| A ativação não troca o cadastro | Num terminal já vinculado a um estabelecimento, activate_terminal não abre formulário. Trocar o cadastro por Intent permitiria desviar os recebimentos para outro CNPJ; isso só é feito no app do terminal |
| Cada desfecho tem dono | Recuperação, idempotência e reimpressão só enxergam o que o seu pacote executou. Outro app credenciado não lê a sua venda pelo id, nem pelo id do gateway impresso no cupom |
Guarde o HOST_SHA256 no seu app | Atualize-o quando a Tupi anunciar uma rotação de chave do host. Numa rotação pelo esquema de assinatura v3, verifyHost continua reconhecendo a chave anterior |
Compatibilidade entre versões
O app host e o seu app são atualizados de forma independente, então em algum momento um falará uma versão diferente do outro. O protocolo usa JSON, e não objetos Android serializados, justamente para tolerar esse descompasso.
| Situação | Comportamento |
|---|---|
| Campo novo que a outra ponta não conhece | Ignorado |
| Valor de enum novo (status, erro, meio de pagamento) | Vira unknown; a message é preservada |
| Campo opcional ausente | Assume o valor padrão |
Campo obrigatório ausente (por exemplo, clientTransactionId, amountInCents de venda e Pix, transactionId de reimpressão e consulta) | Recusa com malformed_request |
protocolVersion que o host não suporta | Recusa com unsupported_protocol_version |
| Operação que o host não conhece | Recusa com unsupported_operation |
| Bloco de impressão ou alinhamento que o host não conhece | Recusa com malformed_request |
Recomendações:
- Trate
unknowncomo "não sei tratar": mostreerror.messagee não tome decisão de negócio. O códigounknowntambém aparece quando o host recebe uma falha sem código classificado, não só entre versões diferentes. - Use
terminal_statuspara lerhostVersionNameesupportedProtocolVersionse esconder funções que o host instalado não executa. - Atualize o contrato quando a Tupi publicar uma versão nova. Uma versão de contrato mais antiga continua funcionando: campos e valores novos são tratados como na tabela acima.