Versão para impressão - PKI Express
Uma cópia impressa de um PDF assinado perde as assinaturas digitais. A versão para impressão diz ao leitor quem assinou o documento e como
obter de volta o arquivo assinado: o PKI Express valida as assinaturas, marca em todas as páginas os nomes dos signatários e um
código de verificação e acrescenta uma página de manifesto com um QR code. O seu site, depois, localiza o documento por esse código.
O PKI Express acrescentou a edição de PDFs (o comando edit-pdf) na 1.3.0, justamente para gerar versões para impressão.
O código é Node.js, dos samples do PKI Suite, com o pki-express (1.16.2); o sample em
Python faz o mesmo.
Fluxo
- Gere um código de verificação para o PDF assinado e guarde-o junto com o arquivo.
- Abra e valide as assinaturas do PDF com o
PadesSignatureExplorer. - Monte as marcas com o
PdfHelper: os signatários em todas as páginas e um manifesto em uma página nova. - Chame
PdfMarker.apply(), que executa o comandoedit-pdfdo PKI Express e grava o PDF marcado. - Quando alguém digitar o código no seu site, localize o arquivo e mostre-o ou ofereça o download.
1. O código de verificação
O sample gera um código de 16 caracteres a partir de bytes aleatórios criptograficamente fortes e guarda, na sessão web, o código e o id do arquivo nos dois sentidos. Guarde-os no seu banco de dados.
let verificationCode = StorageMock.getVerificationCode(req.session, fileId);
if (!verificationCode) {
verificationCode = Util.generateVerificationCode();
StorageMock.setVerificationCode(req.session, fileId, verificationCode);
}
O código protege o acesso aos seus documentos: a biblioteca Java tem a classe AlphaCode para gerá-lo, descrita em
Gerando códigos alfanuméricos em Java.
2. Abrir as assinaturas
const sigExplorer = new PadesSignatureExplorer();
Util.setPkiDefaults(sigExplorer);
sigExplorer.validate = true;
sigExplorer.setSignatureFileFromPathSync(pdfPath);
sigExplorer.open().then((signature) => { /* build the marks from signature.signers */ });
Cada signatário tem certificate, signingTime e validationResults; veja Validar assinaturas.
3. Marcar todas as páginas
O PdfHelper é uma API fluente que monta marcas, containers e elementos (texto, imagem, QR code); o PdfMarker guarda a lista de marcas. O
sample põe o logotipo da ICP-Brasil no canto inferior direito e a mensagem ao longo da borda inferior e da borda direita de todas as
páginas:
const pdfMarker = new PdfMarker();
Util.setPkiDefaults(pdfMarker);
pdfMarker.setFileFromPathSync(pdfPath);
const pdf = new PdfHelper();
pdfMarker.marks.push(
pdf.mark()
.onAllPages()
.onContainer(pdf.container().width(1).anchorRight(1).height(1)
.anchorBottom(1))
.addElement(
pdf.imageElement()
.withOpacity(75)
.withImageContent(Util.getIcpBrasilLogoContent(), 'image/png'),
),
);
pdfMarker.marks.push(
pdf.mark()
.onAllPages()
.onContainer(pdf.container().height(2).anchorBottom().varWidth()
.margins(1.5, 3.5))
.addElement(pdf.textElement().withOpacity(75).addSectionFromText(allPagesMessage)),
);
allPagesMessagecita os signatários e informa o site de verificação e o código.- Tamanhos e posições ficam em centímetros por padrão (
measurementUnits). - Um elemento de texto pode ser girado com
rotate90CounterClockwise(), como o sample faz na borda direita.
4. Acrescentar a página de manifesto
Uma marca com onNewPage() acrescenta uma página. O sample a preenche de cima para baixo: o logotipo, um QR code com o link de verificação,
o título, o código, uma linha por signatário com um ícone de válido ou inválido e o link de verificação.
const manifestMark = pdf.mark()
.onNewPage()
.onContainer(pdf.container().varWidthAndHeight().margins(2.54, 2.54));
manifestMark.addElement(
pdf.qrCodeElement()
.onContainer(pdf.container().height(elementHeight).anchorTop(verticalOffset)
.width(elementHeight)
.anchorRight())
.withQRCodeData(verificationLink),
);
// ... more elements
pdfMarker.marks.push(manifestMark);
outputFile = `${uuidv4()}.pdf`;
pdfMarker.outputFile = path.join(APP_ROOT, 'app-data', outputFile);
return pdfMarker.apply();
apply()grava o PDF marcado emoutputFile, ou sobre o original comoverwriteOriginalFile.- TODO(docs): se a cópia marcada mantém as assinaturas originais (o
PdfMarkerdo PKI SDK as remove; veja a página do PKI SDK).
5. Verificar um código
A página de verificação interpreta o código, encontra o arquivo e abre de novo as assinaturas para mostrá-las:
const verificationCode = Util.parseVerificationCode(req.query.code);
const fileId = StorageMock.lookupVerificationCode(req.session, verificationCode);
const sigExplorer = new PadesSignatureExplorer();
Util.setPkiDefaults(sigExplorer);
sigExplorer.setSignatureFileFromPathSync(StorageMock.getDataPath(fileId));
sigExplorer.validate = true;
sigExplorer.open().then((signature) => { /* render the signers and a link to the file */ });
Para um arquivo CAdES
Para um .p7s, o sample em Node.js o abre com o CadesSignatureExplorer e marca um PDF vazio que vem com o sample; o resultado é um
manifesto que lista os signatários, com o código de verificação e um QR code.
Em cada linguagem
| Biblioteca | PdfMarker | PdfHelper (API fluente) |
|---|---|---|
| Node.js | sim; setFileFromPath, outputFile, marks, apply() | sim |
| Java | sim | sim |
| PHP | sim; setFile, setOutputFile, apply() | não: monte objetos PdfMark |
| Python | sim; set_file_from_path, output_file, marks, apply() | sim |
| Ruby | não | não |