SDK JavaScript
Extensão, certificados A1 e A3, filtros e o cliente da API para Node.
O SDK JavaScript (@shieldsign/sdk) tem duas partes, que rodam em lugares diferentes:
| Parte | Roda em | Para quê |
|---|---|---|
ExtensionSigner, A3Signer, A1Signer e os filtros |
Navegador | Listar certificados, assinar com a extensão ou com um .pfx. Nunca usa chave de API. |
ShieldSignClient |
Node ou outro back-end JavaScript | Chamar a API com a chave de API. Não use no navegador. |
Instalação#
Baixe o SDK na página de Downloads. Há dois formatos:
- Um arquivo só (
shieldsign-sdk-<versão>.browser.mjs): copie para a pasta de arquivos públicos do seu sistema e importe. - Pacote npm (
shieldsign-sdk-<versão>.tgz): para quem usa bundler.npm install ./shieldsign-sdk-<versão>.tgz.
<script type="module">
import { ExtensionSigner } from "/assets/shieldsign-sdk-0.3.0.browser.mjs";
</script>
Com bundler: import { ExtensionSigner } from "@shieldsign/sdk";
No navegador#
Escolher quem assina#
import { A3Signer, A1Signer, ExtensionSigner } from "@shieldsign/sdk";
let signer;
if (await ExtensionSigner.isAvailable()) {
const [cert] = await ExtensionSigner.listCertificates(); // normalmente você mostra a lista e o usuário escolhe
signer = new A3Signer(cert.thumbprint); // token A3, cartão ou certificado do repositório do Windows
} else {
signer = await A1Signer.fromPfx(bytesDoPfx, senha); // A1 em arquivo: sem instalar nada
}
Todo signer tem certificate() (o DER, como Uint8Array), sign(dados, algoritmo) e, no caso de A3Signer, signMany(lista, algoritmo), que assina vários documentos com uma só aprovação e um só PIN.
O fluxo completo, ligando o signer ao seu servidor, está em Assinar PDFs no seu sistema.
A lista de certificados#
Cada item de ExtensionSigner.listCertificates() traz:
| Campo | O que é |
|---|---|
thumbprint |
SHA-256 do certificado: identificador estável. |
subjectDn, issuerDn |
DN em RFC 4514 (CN=NOME:123,OU=…,O=ICP-Brasil,C=BR). É o mesmo formato que a API devolve e que acceptableIssuers aceita. |
subjectCn, issuerCn |
Só o Common Name, pronto para a tela; o do titular já sem o :CPF/CNPJ. |
subjectName, issuerName |
Texto para exibir. Não compare por eles. |
serialNumber, notBefore, notAfter, keyUsage |
Os dados do certificado. |
pkiBrazil |
CPF, CNPJ e demais campos ICP-Brasil (veja Identidade do certificado). Sempre existe; fora da ICP-Brasil, tudo null. |
keyStorage |
"token", "file", "cloud" ou "unknown". Informativo: é uma heurística sobre o provedor de chaves do Windows. Serve para a tela, nunca para segurança. |
icpBrasil |
Heurística: o emissor tem O=ICP-Brasil. Não valida a cadeia: quem valida é a API. |
isTest |
Heurística: AC de teste conhecida pelo nome, ou validade absurdamente longa. |
sources |
Onde está a chave (pkcs11 para token, os para o repositório do sistema). |
A lista já não traz raízes nem intermediárias, só o certificado do titular.
A tela é só organização
No navegador, filtrar por CPF ou emissor organiza a interface: não é controle de acesso. Para regra de negócio e auditoria, use o que a API devolve no prepare e no complete.
Filtros prontos#
Os filtros são combináveis e a lista já volta ordenada, com a validade mais distante primeiro:
import { ExtensionSigner, certFilters as f, filterCertificates } from "@shieldsign/sdk";
const certs = filterCertificates(
await ExtensionSigner.listCertificates(),
f.validNow(), // dentro da validade
f.canSign(), // pode assinar documentos
f.icpBrasilChain(), // emissor O=ICP-Brasil
f.notTest(), // esconde os de teste
f.eCpf(), // ou f.eCnpj(), f.cpf("111.444.777-35"), f.cnpj("…"), f.issuer("AC Soluti")
);
Exemplos com pkiBrazil:
const certs = await ExtensionSigner.listCertificates();
const soEcnpj = certs.filter((c) => c.pkiBrazil.kind === "pj");
const daEmpresa = certs.filter((c) => c.pkiBrazil.cnpj === "11222333000181");
Erros#
import { ExtensionError } from "@shieldsign/sdk";
try {
await assinar(arquivos, signer);
} catch (e) {
if (e instanceof ExtensionError) {
// e.code: extension_not_found | user_cancelled | pin_incorrect | pin_locked | timeout | ...
}
}
A tabela completa dos códigos está em Extensão e agente.
No servidor Node: ShieldSignClient#
Para back-ends JavaScript. Ele faz o fluxo inteiro (iniciar, preparar, assinar com o signer que você passar, concluir e baixar), repetindo o complete com a mesma Idempotency-Key em caso de falha de rede.
import { ShieldSignClient, A1Signer } from "@shieldsign/sdk";
const client = new ShieldSignClient({
apiUrl: "https://api.pki.shieldsign.com.br",
apiKey: process.env.SHIELDSIGN_KEY,
// completeRetries: 2, retryDelayMs: 400 // padrões
});
const r = await client.signPades({
pdf: new Uint8Array(await readFile("contrato.pdf")),
signer: await A1Signer.fromPfx(pfxBytes, senha),
signaturePolicyId: "pades-icpbrasil-ad-rb",
securityContextId: "icp-brasil",
});
// r.signedPdf (Uint8Array), r.certificate, r.warnings
| Método | O que faz |
|---|---|
signPades(opções) |
Assina um PDF. Aceita acceptableIssuers, visualRepresentation, signatureFieldName e beforeSign. |
signPadesBatch(opções) |
Assina vários PDFs com uma só aprovação. |
verifyPades({ pdf, securityContextId }) |
Verifica as assinaturas de um PDF (Verificar assinaturas). |
authenticateWithCertificate({ signer, origin, securityContextId }) |
Login por certificado (Login com certificado). |
beforeSign(certificado) roda depois do prepare e antes do PIN, com a identidade já validada pela API. Lance um erro para recusar (por exemplo, CPF diferente do esperado): a sessão é descartada e nada é assinado nem cobrado.
Os erros da API viram ShieldSignApiError, com status, code (estável) e, nas recusas de certificado, reason. Veja Erros.