PHPackages                             jquembi/document-seal - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. jquembi/document-seal

ActiveLibrary

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.

02PHP

Since Jul 12Pushed 1mo agoCompare

[ Source](https://github.com/jquembi/Documents_seal)[ Packagist](https://packagist.org/packages/jquembi/document-seal)[ RSS](/packages/jquembi-document-seal/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (1)Used By (0)

Document Seal
=============

[](#document-seal)

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
----------------------

[](#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 um `tracking_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) ou `obsolete` (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 `tracking` está ativo.

Instalação
----------

[](#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

[](#dependências-opcionais)

PacoteUso`chillerlan/php-qrcode`Gera a imagem PNG do QR de verificação`setasign/fpdi`Permite carimbar fisicamente um PDF já existente com o selo/QRSem elas, o pacote continua funcional — `QrCodeService::verificationUrl()` sempre devolve o link, mesmo sem imagem de QR.

Módulos personalizáveis
-----------------------

[](#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óduloO que ativaO 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

[](#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
----------

[](#uso-básico)

### 1. Selar um documento

[](#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`)

[](#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`)

[](#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

[](#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`)

[](#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
----------------------------------------------------------------

[](#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`, usando `setasign/fpdi`.

Testes
------

[](#testes)

O pacote inclui uma suite completa com **PHPUnit + Orchestra Testbench**, cobrindo:

FicheiroCobertura`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
------------------

[](#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ódulo `watermark`).
- `document_verification_logs` — auditoria de cada verificação realizada, apenas quando `tracking` está ativo.
- `document_certificates` — um registo por certificado digital emitido, com número sequencial, emissor, validade e estado (módulo `certification`).

Licença
-------

[](#licença)

MIT.

###  Health Score

20

—

LowBetter than 12% of packages

Maintenance59

Moderate activity, may be stable

Popularity3

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 75% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/cca65e53909a62147ec68acd40e718c84392432a73c45ceef65407568c262732?d=identicon)[jquembi](/maintainers/jquembi)

---

Top Contributors

[![JoseQuembi1](https://avatars.githubusercontent.com/u/210159112?v=4)](https://github.com/JoseQuembi1 "JoseQuembi1 (3 commits)")[![jquembi](https://avatars.githubusercontent.com/u/269573441?v=4)](https://github.com/jquembi "jquembi (1 commits)")

### Embed Badge

![Health badge](/badges/jquembi-document-seal/health.svg)

```
[![Health](https://phpackages.com/badges/jquembi-document-seal/health.svg)](https://phpackages.com/packages/jquembi-document-seal)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
