# Verifica (JohnnyDevIT) — certificação de conteúdo de sites (protocolo VSP1) > Verifica certifica que o conteúdo servido por um domínio é o publicado pelo dono. O dono publica uma chave Ed25519 num TXT `_vsp.` (como o DKIM), assina fora do servidor um manifesto com o SHA-256 de cada arquivo (e a "superfície executável" das páginas dinâmicas), o hash do manifesto é registrado na blockchain VERA (testnet), e um monitor compara o site no ar com a última versão assinada a cada 10 minutos. Este arquivo é a especificação para agentes de IA que vão integrar o Verifica num projeto. Página para pessoas: https://johnnydevit.cloud/verifica/instrucoes ## Regras para o agente - NUNCA coloque a chave privada (`VSP_KEY`, formato `vsp1_...`, ou o arquivo `vsp-chave-*.json`) no código, em commits, em logs ou em mensagens. Ela vai só como segredo do deploy (GitHub Secrets, variável de ambiente do servidor de CI etc.). - Quem gera e guarda a chave é o dono, no painel: https://johnnydevit.cloud/verifica/painel (login por código no e-mail; a chave fica cifrada no navegador com a frase-senha do dono). Peça ao dono para copiar a chave no painel; não tente gerar chave em nome dele. - O TXT do DNS é publicado pelo dono no provedor de DNS. O agente informa o valor exato; não invente o valor. - Assine exatamente os arquivos que estarão no ar. Se o build muda depois da assinatura, o site fica "alterado" (vermelho). - Toda nova versão do site exige nova assinatura. Integre o passo ao pipeline de deploy. ## Integração recomendada (pipeline de deploy) 1. O dono já registrou o domínio no painel (TXT publicado + "Conferir DNS e registrar esta chave"). 2. O dono copiou a chave no painel e a gravou como segredo `VSP_KEY` no CI. 3. Baixe o comando (só precisa de Python 3.8+, sem dependências): `curl -fsSLo vsp-publish.py https://johnnydevit.cloud/verifica/static/vsp-publish.py` (ou copie o arquivo para o repositório) 4. Site estático — rode DEPOIS do build e ANTES de enviar os arquivos: `python3 vsp-publish.py --domain DOMINIO --dir ./dist` Isso grava `./dist/.well-known/vsp.json`; envie a pasta inteira em seguida. 5. Páginas dinâmicas (SSR) — rode DEPOIS do deploy (o comando lê as páginas no ar): `python3 vsp-publish.py --domain DOMINIO --page /login --page /conta --out CAMINHO_NO_SERVIDOR/.well-known/vsp.json` O vsp.json precisa ser servido em `https://DOMINIO/.well-known/vsp.json`. 6. Opções: `--base /subpasta/` (arquivos de --dir ficam numa subpasta do site); `--key-file vsp-chave-DOMINIO.json` (em vez de VSP_KEY); `--dir` e `--page` podem ser usados juntos (página em modo código vence o arquivo de mesmo caminho). 7. Verifique: `curl -s -X POST -H 'content-type: application/json' -d '{"domain":"DOMINIO"}' https://johnnydevit.cloud/verifica/api/check` → `check.status` deve ser `ok`. Exemplo GitHub Actions: ```yaml - name: Certificar versão no Verifica env: VSP_KEY: ${{ secrets.VSP_KEY }} run: | curl -fsSLo vsp-publish.py https://johnnydevit.cloud/verifica/static/vsp-publish.py python3 vsp-publish.py --domain exemplo.com.br --dir ./dist ``` ## Registro DNS - Nome: `_vsp.` — Tipo: TXT - Valor: `v=VSP1; k=ed25519; p=` - Exatamente um registro `v=VSP1` por nome. Os resolvedores Cloudflare e Google precisam concordar (propagação). - DNSSEC é recomendado (exibido como "DNSSEC ativo"). ## Manifesto VSP1 String JSON assinada byte a byte (Ed25519 sobre os bytes UTF-8 da string, sem canonicalização posterior): ```json {"v":"VSP1","domain":"exemplo.com.br","issued_at":1792415939,"prev":null, "files":{"/index.html":"","/app.js":""}, "pages":{"/conta":{"csp":"","code":["", "..."]}}} ``` - `issued_at`: unix time, no máximo 24 h no passado e 10 min no futuro. - `prev`: `manifest_sha` da última versão registrada (null na primeira). Obtenha em `GET /api/site/` → `versions[0].manifest_sha`. Impede repetir versões antigas. - `files` (modo exato): caminho URL → SHA-256 hex do corpo servido. Caminhos começam com `/`, sem `..`, `?`, `#`, `//` ou barra final. `/x/index.html` é buscado como `/x/`. `/.well-known/vsp.json` não entra. - `pages` (modo código, opcional): caminho → superfície executável, obtida com `POST /api/surface`. Os itens de `code` vêm ordenados e sem repetição. - Total de 1 a 500 itens (files + pages); até 25 MB por arquivo. Superfície executável (modo código) — o que o monitor compara numa página dinâmica: - `script:` (script externo) e `inline::` (script embutido executável); - `chunk:` (módulos pedidos pelo payload do Next.js); - `on:::` (handlers inline) e `jsurl:::` (URLs javascript:); - `frame:`, `form: `, `object::`, `link::` (stylesheet/modulepreload), `base:`, `meta::`; - `csp`: cabeçalho Content-Security-Policy com nonces trocados por `'nonce'`. Ignorados (dados): texto, `