docs(sdk): add comprehensive integration examples in sdk/examples

This commit is contained in:
Claudecio Martins
2026-10-20 16:43:46 -03:00
parent 50b5feced5
commit b19d09a236
5 changed files with 345 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
/**
* Exemplo 01: Login Seguro via Certificado Digital (Challenge-Response)
*
* Demonstra como autenticar um usuário sem senhas, assinando um desafio emitido
* pelo servidor backend da sua aplicação web.
*/
import { CyberCoreSigner, AgentNotRunningError } from '@cybercore/signer-sdk';
async function main() {
const signer = new CyberCoreSigner({
applicationName: 'Portal Corporativo ERP'
});
// 1. Verifica se o agente desktop está ativo na máquina
const isRunning = await signer.isInstalled();
if (!isRunning) {
console.error('O CyberCore Signer não está em execução. Baixe e abra o aplicativo para continuar.');
return;
}
// 2. Conecta e obtém autorização
console.log('Conectando ao agente...');
await signer.connect();
// 3. Lista os certificados digitais disponíveis
const certs = await signer.getCertificates();
console.log(`Foram localizados ${certs.length} certificado(s) no computador:`);
certs.forEach((c, idx) => {
console.log(`[${idx + 1}] ${c.alias} (${c.certificate_type}) - ${c.subject_name}`);
});
if (certs.length === 0) {
console.warn('Nenhum certificado digital A1 ou token A3 encontrado.');
return;
}
// Seleciona o primeiro certificado disponível
const selectedCert = certs[0];
// 4. Obtém o desafio emitido pelo seu backend (simulado aqui)
const serverChallenge = `auth-session-${Date.now()}-${Math.random().toString(36).substring(2)}`;
console.log(`Desafio recebido do servidor: ${serverChallenge}`);
// 5. Executa a autenticação criptográfica
console.log('Solicitando confirmação de login no CyberCore Signer...');
const authResult = await signer.authenticate({
certificateId: selectedCert.id,
challenge: serverChallenge
});
console.log('Login realizado com sucesso!');
console.log('Titular:', authResult.subjectName);
console.log('CPF/CNPJ:', authResult.subjectCpfCnpj);
console.log('Algoritmo:', authResult.algorithm);
console.log('Assinatura do Desafio (Base64):', authResult.signature.substring(0, 32) + '...');
// O payload retornado deve ser enviado ao seu backend para verificação final:
// POST /api/auth/verify-signature { challenge, signature, certificate }
}
main().catch(err => {
if (err instanceof AgentNotRunningError) {
console.error('Agente offline!\n' + err.actionableGuidance);
} else {
console.error(`Erro no login (${err.code}):`, err.message);
}
});
+59
View File
@@ -0,0 +1,59 @@
/**
* Exemplo 02: Assinatura Desacoplada de Digest (Hash SHA-256)
*
* Demonstra a arquitetura recomendada do CCSP/1:
* O documento NUNCA sai do navegador / servidor da aplicação. Apenas o hash
* de 32 bytes (SHA-256) é enviado ao CyberCore Signer para ser assinado localmente.
*/
import { CyberCoreSigner } from '@cybercore/signer-sdk';
async function main() {
const signer = new CyberCoreSigner({
applicationName: 'Sistema de Prontuário Eletrônico'
});
await signer.connect();
const certs = await signer.getCertificates();
if (certs.length === 0) {
throw new Error('Nenhum certificado disponível.');
}
const selectedCert = certs[0];
// Simula o documento clínico ou contrato gerado na aplicação
const documentoTexto = 'Evolução clínica do paciente João da Silva - 20/10/2026. Procedimento sem intercorrências.';
// 1. Calcula o SHA-256 no próprio ambiente local
const digestBase64 = await signer._calculateSha256(documentoTexto);
console.log('Hash SHA-256 gerado localmente:', digestBase64);
// 2. Envia apenas o digest para o CyberCore Signer
console.log('Aguardando confirmação do usuário no diálogo nativo...');
const result = await signer.sign({
certificateId: selectedCert.id,
digest: digestBase64,
documentName: 'evolucao_clinica_1048.txt',
documentType: 'TXT',
purpose: 'Assinatura de Prontuário Médico',
expiresInSeconds: 120
});
console.log('Documento assinado com sucesso!');
console.log('Status:', result.status);
console.log('Request ID:', result.requestId);
console.log('Algoritmo:', result.algorithm);
console.log('Assinatura (Base64):', result.signature.substring(0, 48) + '...');
console.log('Cadeia X.509 recebida:', result.certificateChain.length, 'certificado(s)');
// 3. Validação preliminar da assinatura no client
const isValid = await signer.verify({
signature: result.signature,
digest: result.digest,
certificate: result.certificate
});
console.log('Assinatura é consistente?', isValid);
}
main().catch(console.error);
+61
View File
@@ -0,0 +1,61 @@
/**
* Exemplo 03: Assinatura de PDF Completo PAdES com Selo Visual
*
* Demonstra como assinar um arquivo PDF aplicando o selo gráfico ICP-Brasil ou Gov.br
* estilizado pelo CyberCore Signer, retornando o PDF assinado completo em Base64/Blob.
*/
import { CyberCoreSigner } from '@cybercore/signer-sdk';
async function main() {
const signer = new CyberCoreSigner({
applicationName: 'Assinador de Contratos Online'
});
await signer.connect();
// 1. Consulta os temas de selos visuais disponíveis no agente
const themesResp = await signer.getSealThemes();
console.log('Selo padrão configurado:', themesResp.default_seal_id);
console.log('Temas disponíveis:', themesResp.seals.map(s => s.name).join(', '));
// 2. Mock de um PDF de teste (no navegador, normalmente é obtido via <input type="file">)
const fakePdfContent = Buffer.from('%PDF-1.4\n1 0 obj\n<< /Type /Catalog >>\nendobj\n%%EOF');
const certs = await signer.getCertificates();
if (certs.length === 0) {
console.error('Nenhum certificado para assinatura.');
return;
}
// 3. Executa a assinatura com estampa gráfica posicionada no rodapé da última página
console.log('Enviando solicitação de assinatura PAdES...');
const result = await signer.signPdfDocument({
pdf: fakePdfContent,
certificateId: certs[0].id,
documentName: 'contrato_prestacao_servicos.pdf',
position: 'BOTTOM_RIGHT',
pageChoice: 'LAST_PAGE',
scale: 1.0,
visibleSeal: true,
sealThemeId: 'icp-brasil',
reason: 'Concordância integral com os termos do contrato',
location: 'Brasília - DF',
cpfDisplayMode: 'MASKED', // Exibe CPF mascarado no carimbo (ex: ***.456.789-**)
includeDateTime: true,
customExtraInfo: 'Matrícula: 55420-9'
});
console.log('PDF assinado com sucesso!');
console.log('Titular:', result.subjectName);
console.log('CPF/CNPJ:', result.subjectCpfCnpj);
console.log('Tamanho do PDF assinado:', result.signedPdf.length, 'caracteres Base64');
// No navegador web, você pode invocar diretamente:
// result.download('contrato_assinado.pdf');
// Ou obter os bytes binários para envio via fetch/multipart:
const pdfBytes = result.getSignedPdfBytes();
console.log('Bytes binários gerados:', pdfBytes.length);
}
main().catch(console.error);
+82
View File
@@ -0,0 +1,82 @@
/**
* Exemplo 04: Tratamento Estruturado e Acionável de Erros
*
* Demonstra como capturar cada erro específico do CCSP/1 e orientar
* o usuário final com mensagens claras e passos práticos de resolução.
*/
import {
CyberCoreSigner,
AgentNotRunningError,
ApplicationNotAuthorizedError,
UserCancelledError,
CertificateNotFoundError,
CertificateExpiredError,
CertificateInvalidError,
PrivateKeyNotAvailableError,
PinRequiredError,
PinIncorrectError,
TokenNotFoundError,
RequestExpiredError,
TimeoutError,
CyberCoreError
} from '@cybercore/signer-sdk';
async function performSigningOperation(signer, certId, fileDigest) {
try {
return await signer.sign({
certificateId: certId,
digest: fileDigest,
documentName: 'termo_responsabilidade.pdf'
});
} catch (err) {
if (err instanceof AgentNotRunningError) {
// O agente local está fechado ou bloqueado
console.warn('⚠️ AGENTE NÃO DETECTADO:');
console.warn(err.actionableGuidance);
// Sugestão de UI: exibir banner com botão "Baixar CyberCore Signer"
} else if (err instanceof ApplicationNotAuthorizedError) {
// O usuário clicou em "Rejeitar" no prompt de autorização da aplicação
console.warn('⚠️ APLICAÇÃO NÃO AUTORIZADA:');
console.warn('O usuário não autorizou este portal no diálogo de segurança do CyberCore Signer.');
} else if (err instanceof UserCancelledError) {
// O usuário cancelou a assinatura explicitamente na janela nativa
console.info('ℹ️ Assinatura cancelada pelo usuário.');
} else if (err instanceof CertificateExpiredError) {
console.error('❌ CERTIFICADO EXPIRADO: O certificado digital selecionado expirou.');
} else if (err instanceof CertificateInvalidError) {
console.error('❌ CERTIFICADO INVÁLIDO: O certificado possui estrutura corrompida ou foi revogado.');
} else if (err instanceof PrivateKeyNotAvailableError) {
console.error('❌ CHAVE PRIVADA INDISPONÍVEL: A chave privada deste certificado não está acessível no computador.');
} else if (err instanceof PinIncorrectError) {
console.error('❌ PIN INCORRETO: O PIN digitado para o token A3 está errado. Cuidado com o bloqueio do dispositivo.');
} else if (err instanceof PinRequiredError) {
console.error('❌ PIN OBRIGATÓRIO: É necessário fornecer o PIN do dispositivo criptográfico.');
} else if (err instanceof TokenNotFoundError) {
console.error('❌ TOKEN NÃO ENCONTRADO: O token USB ou smart card foi removido da porta USB.');
} else if (err instanceof RequestExpiredError) {
console.warn('⚠️ REQUISIÇÃO EXPIRADA: O tempo limite para confirmação do usuário esgotou.');
} else if (err instanceof TimeoutError) {
console.error('⏱️ TIMEOUT: O agente demorou mais tempo que o esperado para responder.');
} else if (err instanceof CyberCoreError) {
console.error(`⚠️ ERRO DO PROTOCOLO CCSP (${err.code}):`, err.message);
} else {
console.error('Erro desconhecido:', err);
}
throw err;
}
}
async function main() {
const signer = new CyberCoreSigner({ timeoutMs: 15000 });
const fakeDigest = Buffer.alloc(32, 9).toString('base64');
console.log('Testando tratamento de erros com certificado simulado expirado...');
try {
await performSigningOperation(signer, 'cert-expirado', fakeDigest);
} catch {
console.log('Tratamento de exceções concluído com sucesso.');
}
}
main().catch(() => {});
+75
View File
@@ -0,0 +1,75 @@
# Exemplos de Integração — CyberCore Signer Web SDK
Este diretório contém exemplos práticos e prontos para uso demonstrando os principais fluxos de integração do `@cybercore/signer-sdk` com aplicações web.
---
## 📁 Arquivos de Exemplo
| Arquivo | Descrição |
| :--- | :--- |
| [`01-crypto-login.js`](./01-crypto-login.js) | Autenticação segura por desafio criptográfico (Challenge-Response) sem senhas. |
| [`02-sign-digest.js`](./02-sign-digest.js) | Assinatura desacoplada em que o navegador calcula o hash SHA-256 e o CyberCore assina apenas o digest. |
| [`03-sign-pades.js`](./03-sign-pades.js) | Assinatura digital completa de PDF (PAdES) com selo gráfico posicionado (ICP-Brasil / Gov.br). |
| [`04-error-handling.js`](./04-error-handling.js) | Captura e tratamento estruturado de todos os erros do protocolo CCSP/1 com guia acionável. |
---
## 🚀 Como Executar
### Pré-requisitos
1. Agente desktop **CyberCore Signer** em execução na máquina (`127.0.0.1:21325`).
2. Node.js 18+ instalado.
### Execução direta via Node.js
Como o pacote usa módulos ES (`"type": "module"`), você pode testar diretamente com:
```bash
# Executar exemplo de login
node examples/01-crypto-login.js
# Executar exemplo de assinatura de digest
node examples/02-sign-digest.js
# Executar exemplo de assinatura PAdES com selo
node examples/03-sign-pades.js
# Executar exemplo de tratamento de erros
node examples/04-error-handling.js
```
---
## 💡 Uso em Projetos Frontend (React, Vue, Angular, Svelte, Vanilla)
Instale o pacote a partir do seu registry npm privado:
```bash
npm install @cybercore/signer-sdk
```
Importe os métodos e tipos em qualquer componente ou serviço web:
```typescript
import { CyberCoreSigner, AgentNotRunningError } from '@cybercore/signer-sdk';
const signer = new CyberCoreSigner({
applicationName: 'Meu Sistema Web'
});
async function assinarDocumento(arquivoPdf: File, certId: string) {
try {
const resultado = await signer.signPdfDocument({
pdf: arquivoPdf,
certificateId: certId,
position: 'BOTTOM_RIGHT',
sealThemeId: 'icp-brasil'
});
// Baixa o documento assinado no navegador
resultado.download('documento_assinado.pdf');
} catch (err) {
if (err instanceof AgentNotRunningError) {
alert(err.actionableGuidance);
}
}
}
```