216 lines
7.0 KiB
Markdown
216 lines
7.0 KiB
Markdown
# SDK Web JavaScript (@cybercore/signer-sdk)
|
|
|
|
> **Manual de Integração de Aplicações Web Modernas com o Agente Desktop CyberCore Signer**
|
|
|
|
O **`@cybercore/signer-sdk`** é a biblioteca cliente oficial em JavaScript (TypeScript ready) desenvolvida para permitir que aplicações web modernas (React, Next.js, Vue, Angular ou JavaScript nativo) se comuniquem com o agente desktop **CyberCore Signer** através do protocolo local **CCSP/1**.
|
|
|
|
---
|
|
|
|
## 1. Instalação e Configuração
|
|
|
|
### 1.1 Instalação via Gerenciador de Pacotes
|
|
```bash
|
|
npm install @cybercore/signer-sdk
|
|
# ou
|
|
yarn add @cybercore/signer-sdk
|
|
# ou
|
|
pnpm add @cybercore/signer-sdk
|
|
```
|
|
|
|
### 1.2 Inicialização do Cliente
|
|
```javascript
|
|
import { CyberCoreSigner } from '@cybercore/signer-sdk';
|
|
|
|
const signer = new CyberCoreSigner({
|
|
applicationName: 'Portal Meu Negócio', // Nome exibido no diálogo nativo do usuário
|
|
port: 21325, // Porta padrão do agente local (opcional)
|
|
timeoutMs: 30000 // Timeout padrão para operações (opcional)
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Métodos da API
|
|
|
|
### 2.1 Verificação de Disponibilidade e Conexão
|
|
|
|
#### `isInstalled(timeoutMs = 2000): Promise<boolean>`
|
|
Testa de forma rápida e silenciosa se o agente desktop está ativo na máquina do usuário.
|
|
|
|
```javascript
|
|
const disponivel = await signer.isInstalled();
|
|
if (!disponivel) {
|
|
alert('O CyberCore Signer não foi detectado em sua máquina. Por favor, instale o aplicativo para continuar.');
|
|
}
|
|
```
|
|
|
|
#### `connect(): Promise<boolean>`
|
|
Inicia o handshake de autorização com o agente. Se a aplicação ainda não foi homologada pelo usuário, abre um diálogo nativo na tela do computador para autorização expressa.
|
|
|
|
```javascript
|
|
const autorizado = await signer.connect();
|
|
if (!autorizado) {
|
|
console.warn('O usuário recusou a autorização da aplicação.');
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 2.2 Descoberta de Certificados Digitais
|
|
|
|
#### `getCertificates(): Promise<Array<CertificateInfo>>`
|
|
Retorna a lista de certificados digitais válidos e disponíveis na máquina (A1 importados e A3 conectados via USB).
|
|
|
|
```javascript
|
|
const certificados = await signer.getCertificates();
|
|
|
|
certificados.forEach(cert => {
|
|
console.log(`[${cert.type}] ${cert.common_name}`);
|
|
console.log(`Titular: ${cert.subject_dn}`);
|
|
console.log(`Validade até: ${cert.valid_to}`);
|
|
console.log(`CPF/CNPJ: ${cert.cpf || cert.cnpj}`);
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
### 2.3 Operações de Assinatura Digital
|
|
|
|
#### `sign(options): Promise<SignatureResult>`
|
|
Assina o hash SHA-256 (digest) de qualquer informação. A chave privada nunca sai do computador e apenas o digest é assinado.
|
|
|
|
```javascript
|
|
const resultado = await signer.sign({
|
|
certificateId: 'win-4340656a',
|
|
digest: '47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=', // Hash SHA-256 em Base64
|
|
documentName: 'contrato_prestacao_servicos.pdf',
|
|
documentType: 'PDF'
|
|
});
|
|
|
|
console.log('Assinatura gerada (Base64):', resultado.signature);
|
|
console.log('Certificado do signatário:', resultado.certificate);
|
|
console.log('Cadeia de certificação:', resultado.certificate_chain);
|
|
```
|
|
|
|
#### `signPdf(file, options): Promise<SignatureResult>`
|
|
Calcula o hash do documento PDF no próprio navegador e solicita a assinatura ao CyberCore Signer.
|
|
|
|
```javascript
|
|
const inputElement = document.getElementById('arquivo-pdf');
|
|
const arquivoPdf = inputElement.files[0];
|
|
|
|
const resultadoPdf = await signer.signPdf(arquivoPdf, {
|
|
certificateId: certificados[0].id
|
|
});
|
|
|
|
console.log('PDF assinado digitalmente com sucesso!');
|
|
```
|
|
|
|
#### `signXml(xmlContent, options): Promise<SignatureResult>`
|
|
Assina o hash de documentos XML ou notas fiscais eletrônicas (NF-e, CT-e, MDF-e, XAdES). Aceita `string` com o XML ou arquivo `File`/`Blob`.
|
|
|
|
```javascript
|
|
const xmlString = '<infNFe Id="NFe3524...">...</infNFe>';
|
|
|
|
const resultadoXml = await signer.signXml(xmlString, {
|
|
certificateId: certificados[0].id,
|
|
documentName: 'nfe-3524.xml'
|
|
});
|
|
```
|
|
|
|
#### `signFile(file, options): Promise<SignatureResult>`
|
|
Assina arquivos genéricos de qualquer formato (ZIP, DOCX, XLSX, imagens, binários).
|
|
|
|
```javascript
|
|
const fileInput = document.getElementById('input-qualquer-arquivo');
|
|
|
|
const resultadoArquivo = await signer.signFile(fileInput.files[0], {
|
|
certificateId: certificados[0].id
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
### 2.4 Autenticação e Login Digital (Challenge-Response)
|
|
|
|
#### `authenticate(options): Promise<AuthResult>`
|
|
Realiza o login seguro de um usuário através de seu certificado digital ICP-Brasil. O backend da sua aplicação fornece um desafio único (*challenge / nonce*) e o CyberCore assina esse desafio.
|
|
|
|
```javascript
|
|
// 1. Obter desafio único do backend da sua aplicação
|
|
const { challenge } = await fetch('/api/auth/challenge').then(res => res.json());
|
|
|
|
// 2. Solicitar assinatura do desafio ao CyberCore Signer
|
|
const authResult = await signer.authenticate({
|
|
certificateId: certificados[0].id,
|
|
challenge: challenge
|
|
});
|
|
|
|
// 3. Enviar a assinatura e o certificado para o backend validar e autenticar a sessão
|
|
const response = await fetch('/api/auth/validate-login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
challenge: authResult.challenge,
|
|
signature: authResult.signature,
|
|
certificate: authResult.certificate
|
|
})
|
|
});
|
|
|
|
if (response.ok) {
|
|
console.log(`Login aprovado para: ${authResult.subjectName} (${authResult.subjectCpfCnpj})`);
|
|
window.location.href = '/dashboard';
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Tratamento Estruturado de Erros
|
|
|
|
O SDK expõe classes de erro dedicadas que herdam de `CyberCoreError`, permitindo tratar cenários de forma elegante na interface:
|
|
|
|
```javascript
|
|
import {
|
|
UserCancelledError,
|
|
PinIncorrectError,
|
|
TokenNotFoundError,
|
|
CertificateNotFoundError,
|
|
CertificateExpiredError
|
|
} from '@cybercore/signer-sdk/errors';
|
|
|
|
try {
|
|
const res = await signer.sign({
|
|
certificateId: certId,
|
|
digest: documentoDigest
|
|
});
|
|
} catch (error) {
|
|
if (error instanceof UserCancelledError) {
|
|
// Usuário cancelou a assinatura voluntariamente na janela nativa
|
|
console.info('Operação cancelada pelo usuário.');
|
|
} else if (error instanceof PinIncorrectError) {
|
|
// PIN do token A3 incorreto
|
|
alert('PIN incorreto! Por favor, digite o PIN correto do seu token.');
|
|
} else if (error instanceof TokenNotFoundError) {
|
|
// Token USB desconectado
|
|
alert('Token não encontrado! Por favor, conecte seu dispositivo USB para assinar.');
|
|
} else if (error instanceof CertificateExpiredError) {
|
|
// Certificado ultrapassou a data de validade
|
|
alert('O certificado selecionado expirou. Entre em contato com sua autoridade certificadora.');
|
|
} else {
|
|
// Demais falhas
|
|
console.error('Falha na operação com o CyberCore Signer:', error);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Documentação Relacionada e Recursos
|
|
|
|
- **Especificação Formal do Protocolo:** [`docs/CCSP.md`](./CCSP.md)
|
|
- **JSON Schema CCSP/1:** [`docs/ccsp-v1.schema.json`](./ccsp-v1.schema.json)
|
|
- **Compatibilidade de Navegadores & PNA:** [`docs/browser-compatibility.md`](./browser-compatibility.md)
|
|
- **Exemplos Didáticos:** [`sdk/examples/`](../sdk/examples/README.md)
|
|
- **Processo de Release do Pacote:** [`docs/sdk-release-process.md`](./sdk-release-process.md)
|
|
|