jquembi / document-seal
Selagem digital, marca d'agua rastreavel, verificacao publica e controlo de obsolescencia para documentos, relatorios e plataformas de geracao documental em Laravel.
Requires
- php: ^8.1
- ext-json: *
- ext-sodium: *
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/routing: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0|^10.0
- phpunit/phpunit: ^10.0|^11.0
Suggests
- chillerlan/php-qrcode: Necessario para gerar imagens de codigo QR de verificacao embutidas nos documentos selados.
- setasign/fpdi: Necessario para carimbar (stamp) fisicamente PDFs existentes com o selo de rastreio e QR de verificacao.
This package is auto-updated.
Last update: 2026-07-12 18:36:17 UTC
README
Selagem digital, verificação pública, marca d'água anti-vazamento e certificação digital de autenticidade para documentos, relatórios e qualquer plataforma que gere conteúdo (PDF, DOCX, HTML, relatórios de sistema) em aplicações Laravel.
O pacote é modular: cada organização escolhe exatamente quais funcionalidades quer ativar.
O que o pacote garante
- Autenticidade — cada documento recebe um hash de conteúdo (SHA-256) e uma assinatura digital Ed25519, gerada com a chave privada da organização.
- Rastreabilidade (módulo
tracking) — cada documento selado recebe umtracking_codeúnico (UUID) e uma página pública de verificação (/verificar-documento/{codigo}), acessível por link ou QR code. - Controlo de ciclo de vida — um documento pode ser marcado como
revoked(revogado, ex: emitido por engano) ouobsolete(substituído por nova versão), refletido instantaneamente em qualquer verificação futura — mesmo que o ficheiro já esteja a circular na internet. - Rastreio de vazamentos (módulo
watermark) — é possível emitir cópias individualizadas do mesmo documento para diferentes destinatários, cada uma com uma marca d'água invisível (caracteres Unicode de largura zero) embutida no texto. Se uma dessas cópias vazar, o pacote identifica exatamente qual destinatário a distribuiu. - QR code de verificação (módulo
qr_code) — geração da URL/imagem de QR para embutir em qualquer documento gerado. - Certificação digital de autenticidade (módulo
certification) — camada formal para documentos oficiais (certidões, contratos, diplomas, atas), com número de certificado sequencial, emissor identificado, validade e página pública própria de verificação. - Auditoria — toda verificação (válida, inválida, revogada, não encontrada) fica registada com IP, user agent e timestamp, quando o módulo
trackingestá ativo.
Instalação
composer require jquembi/document-seal php artisan vendor:publish --tag=document-seal-config php artisan migrate php artisan document-seal:generate-keys
Copie as chaves geradas para o .env:
DOCUMENT_SEAL_ORG_NAME="Nome da Organização"
DOCUMENT_SEAL_PRIVATE_KEY=...
DOCUMENT_SEAL_PUBLIC_KEY=...
A chave privada nunca deve ser versionada. Guarde-a num cofre de segredos (ex: AWS Secrets Manager, Vault) em produção.
Dependências opcionais
| Pacote | Uso |
|---|---|
chillerlan/php-qrcode |
Gera a imagem PNG do QR de verificação |
setasign/fpdi |
Permite carimbar fisicamente um PDF já existente com o selo/QR |
Sem elas, o pacote continua funcional — QrCodeService::verificationUrl() sempre devolve o link, mesmo sem imagem de QR.
Módulos personalizáveis
Cada organização ativa/desativa livremente cada módulo em config/document-seal.php (ou por variável de ambiente). A assinatura Ed25519 do documento (SealService::seal()) é sempre o núcleo disponível — os módulos abaixo são camadas independentes sobre ela.
// config/document-seal.php 'modes' => [ 'tracking' => env('DOCUMENT_SEAL_MODE_TRACKING', true), 'watermark' => env('DOCUMENT_SEAL_MODE_WATERMARK', true), 'qr_code' => env('DOCUMENT_SEAL_MODE_QR_CODE', true), 'certification' => env('DOCUMENT_SEAL_MODE_CERTIFICATION', true), ],
| Módulo | O que ativa | O que acontece se desativado |
|---|---|---|
tracking |
Página pública /verificar-documento/{codigo} e registo de auditoria (VerificationLog) |
SealService::verify() continua a calcular o resultado normalmente, mas não regista o acesso e a rota pública não é registada (404) |
watermark |
WatermarkService::issueRecipientCopy() e traceLeak() |
Estas chamadas lançam FeatureDisabledException; as funções utilitárias puras (encode/decode/embedInText/extractFromText) continuam sempre disponíveis |
qr_code |
QrCodeService::verificationUrl() e generatePngBase64() |
Estas chamadas lançam FeatureDisabledException |
certification |
CertificationService completo e a rota /verificar-documento/certificado/{numero} |
O serviço lança FeatureDisabledException; a rota não é registada (404) |
Exemplos de configuração por perfil de organização
Só quero selar e ter uma página pública de verificação (sem QR, sem watermark, sem certificação):
DOCUMENT_SEAL_MODE_TRACKING=true DOCUMENT_SEAL_MODE_WATERMARK=false DOCUMENT_SEAL_MODE_QR_CODE=false DOCUMENT_SEAL_MODE_CERTIFICATION=false
Só quero rastrear vazamentos internos, sem página pública nenhuma:
DOCUMENT_SEAL_MODE_TRACKING=false DOCUMENT_SEAL_MODE_WATERMARK=true DOCUMENT_SEAL_MODE_QR_CODE=false DOCUMENT_SEAL_MODE_CERTIFICATION=false
Emito documentos oficiais e preciso de certificação com validade:
DOCUMENT_SEAL_MODE_TRACKING=true DOCUMENT_SEAL_MODE_WATERMARK=false DOCUMENT_SEAL_MODE_QR_CODE=true DOCUMENT_SEAL_MODE_CERTIFICATION=true DOCUMENT_SEAL_CERT_VALIDITY_DAYS=365
Uma exceção clara (FeatureDisabledException) é sempre lançada ao tentar usar um módulo desativado — nunca falha silenciosamente.
Uso básico
1. Selar um documento
use Angotech\DocumentSeal\Services\SealService; $hash = $sealService->hashFile(storage_path('app/relatorio.pdf')); $documento = $sealService->seal($hash, [ 'title' => 'Relatório Financeiro Q2 2026', 'organization' => 'Angotech', 'metadata' => ['autor' => 'José', 'versao' => '1.0'], ]); echo $documento->tracking_code; // ex: 3f2a1c9e-...
Ou via linha de comando:
php artisan document-seal:seal /caminho/relatorio.pdf --title="Relatório Q2" --org="Angotech"
2. Gerar o QR / link de verificação (módulo qr_code)
use Angotech\DocumentSeal\Services\QrCodeService; $url = $qrCodeService->verificationUrl($documento->tracking_code); $png = $qrCodeService->generatePngBase64($documento->tracking_code); // null se a lib opcional não estiver instalada
Inclua o $url (ou o QR) no rodapé do PDF/DOCX gerado. Qualquer pessoa que aceda a esse link vê o estado real do documento — mesmo que o ficheiro tenha sido copiado, reenviado ou publicado fora do teu controlo.
3. Emitir cópias rastreáveis por destinatário — anti-vazamento (módulo watermark)
use Angotech\DocumentSeal\Services\WatermarkService; $recipient = $watermarkService->issueRecipientCopy($documento, [ 'name' => 'Maria Silva', 'email' => 'maria@empresa.co.ao', ]); // Antes de gerar o ficheiro final para a Maria, embuta a marca invisível no texto: $textoComMarca = $watermarkService->embedInText($textoOriginal, $recipient->recipient_code);
Se esse documento aparecer vazado na internet:
$origem = $watermarkService->traceLeak($textoEncontradoOnline); if ($origem) { echo "Vazado por: {$origem->recipient_name} ({$origem->recipient_email})"; }
Ou via consola:
php artisan document-seal:issue-copy {tracking_code} --name="Maria Silva" --email=maria@empresa.co.ao
php artisan document-seal:trace /caminho/ficheiro_vazado.txt
4. Revogar, marcar obsoleto ou reativar
php artisan document-seal:revoke {tracking_code} --reason="Emitido por engano"
php artisan document-seal:revoke {tracking_code} --obsolete --reason="Substituído pela versão 2.0"
php artisan document-seal:revoke {tracking_code} --reactivate
A partir do momento da revogação, a página pública de verificação e a resposta de SealService::verify() passam a refletir imediatamente o novo estado — independentemente de quantas cópias do ficheiro já estejam a circular.
5. Certificar um documento autenticado (módulo certification)
Para documentos que exigem prova formal de autenticidade e um responsável nomeado — certidões, contratos assinados, diplomas, atas oficiais — o selo simples pode ser reforçado com um certificado digital:
use Angotech\DocumentSeal\Services\CertificationService; $certificado = $certificationService->certify($documento, 'Maria Silva', [ 'issuer_role' => 'Diretora Jurídica', 'validity_days' => 365, // omitir para sem expiração 'metadata' => ['numero_processo' => 'PROC-2026-4471'], ]); echo $certificado->certificate_number; // ex: CERT-2026-000123
Verificação (por número de certificado, independente do tracking_code):
$resultado = $certificationService->verify('CERT-2026-000123'); // $resultado['result'] pode ser: // 'valid', 'invalid', 'revoked', 'expired', 'not_found', // ou 'underlying_seal_revoked' / 'underlying_seal_obsolete' // (quando o certificado é válido mas o selo do documento associado já não é)
Ou via consola:
php artisan document-seal:certify {tracking_code} --issuer="Maria Silva" --role="Diretora Jurídica" --valid-days=365
php artisan document-seal:verify-certificate CERT-2026-000123
php artisan document-seal:revoke-certificate CERT-2026-000123 --reason="fraude detetada"
A página pública correspondente fica em /verificar-documento/certificado/{numero_do_certificado} — pode ser impressa como QR no próprio documento oficial, separada da verificação do selo simples.
Diferença entre selo simples e certificado: o selo (SealService) prova que um ficheiro não foi alterado desde que saiu da organização. O certificado (CertificationService) vai além — atesta formalmente que um responsável identificado da organização autenticou aquele documento, com validade e possibilidade de revogação independente do selo.
Modelo de ameaça — o que este pacote resolve e o que não resolve
- Resolve: provar que um documento saiu da tua organização sem alterações (assinatura), permitir invalidar/atualizar publicamente um documento já distribuído (revogação), identificar a origem de uma cópia vazada (marca d'água por destinatário), e emitir prova formal de autenticidade com responsável nomeado (certificação).
- Não resolve: impedir fisicamente que alguém copie, imprima ou fotografe um documento. Nenhuma tecnologia de selagem consegue isso — o objetivo aqui é detetar e provar, não bloquear.
- A marca d'água de texto sobrevive a cópia/colagem digital. Para documentos impressos e depois escaneados (OCR), combine com um carimbo visível (QR/rodapé) gerado a partir do mesmo
recipient_code, usandosetasign/fpdi.
Testes
O pacote inclui uma suite completa com PHPUnit + Orchestra Testbench, cobrindo:
| Ficheiro | Cobertura |
|---|---|
tests/Unit/KeyManagerTest.php |
Geração de chaves, assinatura/verificação Ed25519, deteção de adulteração, fingerprint |
tests/Unit/SealServiceTest.php |
Selagem, verificação, revogação, obsolescência, reativação, auditoria |
tests/Unit/WatermarkServiceTest.php |
Codificação/decodificação da marca invisível, emissão de cópias, rastreio de vazamento |
tests/Unit/CertificationServiceTest.php |
Emissão, numeração sequencial, expiração, revogação, dependência do selo subjacente |
tests/Unit/FeatureGateTest.php |
Ativação/bloqueio de módulos |
tests/Feature/VerificationControllerTest.php |
Rota pública de verificação de selo, estados, cabeçalho noindex, auditoria |
tests/Feature/CertificationControllerTest.php |
Rota pública de verificação de certificado |
tests/Feature/ConsoleCommandsTest.php |
Comandos artisan de selagem/watermark/revogação |
tests/Feature/CertificationCommandsTest.php |
Comandos artisan de certificação |
tests/Feature/ModeGatingTest.php |
Cada módulo desativado bloqueia corretamente a funcionalidade e a rota correspondente |
tests/Feature/TrackingDisabledTest.php |
Selo continua funcional mesmo com tracking desativado (sem rota pública, sem log) |
Para correr localmente:
composer install
composer test
Ou diretamente com o binário do PHPUnit:
vendor/bin/phpunit
A integração contínua (.github/workflows/tests.yml) corre a suite em PHP 8.1–8.3 e Laravel 10/11 a cada push e pull request.
Estrutura de dados
sealed_documents— um registo por documento selado (hash, assinatura, estado, metadados).document_recipients— uma linha por cópia individual emitida, com o código de marca d'água correspondente (módulowatermark).document_verification_logs— auditoria de cada verificação realizada, apenas quandotrackingestá ativo.document_certificates— um registo por certificado digital emitido, com número sequencial, emissor, validade e estado (módulocertification).
Licença
MIT.