Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f1bc289ee | ||
|
|
e20a52d3b2 | ||
|
|
3d3ec9d47c | ||
|
|
0abbbf5abd | ||
|
|
9598172174 | ||
|
|
68943221c3 | ||
|
|
d27c0f9567 | ||
|
|
0658f7007e | ||
|
|
14b342c3a2 | ||
|
|
4010a9bba5 | ||
|
|
caaa1de8a0 | ||
|
|
6ba1a6a77f | ||
|
|
66f3172bfb | ||
|
|
cf63aa6d22 | ||
|
|
5d8c5d487d | ||
|
|
b13129b7d8 | ||
|
|
975885753a | ||
|
|
2c1d4f359e | ||
|
|
8d0e587114 | ||
|
|
b19d09a236 | ||
|
|
50b5feced5 | ||
|
|
9dcbac61ec | ||
|
|
957f9c9abd | ||
|
|
e9f90b42cb | ||
|
|
92d4ea3411 | ||
|
|
49021d9942 | ||
|
|
67e47cbed5 | ||
|
|
b00f78505d | ||
|
|
a32ab3b7ce | ||
|
|
e3d56d90af | ||
|
|
051614a919 | ||
|
|
bac691aae1 | ||
|
|
71428cdaad | ||
|
|
cf7ac8c51c | ||
|
|
002823ede3 | ||
|
|
90e2c8ef3d | ||
|
|
4b6ae923c6 | ||
|
|
4b64a113b5 | ||
|
|
06c90b4e86 | ||
|
|
300944697f | ||
|
|
7aa33a4789 | ||
|
|
a562909bc5 | ||
|
|
66459bfae4 | ||
|
|
1a727e6ff5 | ||
|
|
eeeecb0604 | ||
|
|
4e6dd2a029 | ||
|
|
cd3ef646d2 | ||
|
|
fa93e31ca1 | ||
|
|
6093879aa9 | ||
|
|
cebeca467f | ||
|
|
e50257fb34 | ||
|
|
6dce9f9317 | ||
|
|
539d5e4c33 | ||
|
|
5551d9e667 | ||
|
|
ef44d34944 | ||
|
|
edccfff7ff | ||
|
|
16212702cb | ||
|
|
6f191c6a69 | ||
|
|
d1cfab95c2 | ||
|
|
64ca13b3a1 |
@@ -0,0 +1,31 @@
|
||||
---
|
||||
name: "Relato de Bug"
|
||||
about: "Relate um problema ou comportamento inesperado no CyberCore Signer"
|
||||
title: "[BUG] "
|
||||
labels:
|
||||
- "bug"
|
||||
---
|
||||
|
||||
### Descrição do Problema
|
||||
Uma descrição clara e concisa do comportamento inesperado ocorrido.
|
||||
|
||||
### Passos para Reproduzir
|
||||
1. Iniciar o CyberCore Signer com o comando `...`
|
||||
2. Acessar a aplicação web ou endpoint `...`
|
||||
3. Tentar executar a operação de assinatura `...`
|
||||
4. Observar o erro reportado.
|
||||
|
||||
### Comportamento Esperado
|
||||
O que você esperava que acontecesse normalmente.
|
||||
|
||||
### Logs e Mensagens de Diagnóstico
|
||||
```text
|
||||
Cole aqui o trecho relevante de log do agente (sem expor dados sensíveis ou chaves).
|
||||
```
|
||||
|
||||
### Informações do Ambiente
|
||||
* **Sistema Operacional:** Windows 10 / Windows 11 / Ubuntu / Outro (especifique)
|
||||
* **Versão do Java:** 25 LTS (especifique a vendor: Temurin, Corretto, Oracle)
|
||||
* **Tipo de Certificado Utilizado:** A1 (arquivo `.pfx`) / A3 (Token USB / Smart Card / Windows-MY)
|
||||
* **Fabricante do Hardware A3 (se aplicável):** SafeSign / SafeNet / GD Burti / Outro
|
||||
* **Navegador e Versão (se aplicável ao SDK):** Chrome / Edge / Firefox
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: "Solicitação de Funcionalidade"
|
||||
about: "Sugira uma nova funcionalidade ou melhoria para o agente ou SDK"
|
||||
title: "[FEAT] "
|
||||
labels:
|
||||
- "enhancement"
|
||||
---
|
||||
|
||||
### Problema ou Necessidade
|
||||
Descreva o cenário de uso ou o desafio que motivou esta solicitação.
|
||||
|
||||
### Solução Proposta
|
||||
Uma descrição clara do recurso ou melhoria que você gostaria de ver implementado no CyberCore Signer.
|
||||
|
||||
### Módulos Afetados
|
||||
* [ ] `modules/cybercore-core` (regras criptográficas, provedores, protocolo CCSP)
|
||||
* [ ] `modules/cybercore-ui` (telas JavaFX, diálogos, selo visual, system tray)
|
||||
* [ ] `modules/cybercore-app` (ponto de entrada, empacotamento nativo)
|
||||
* [ ] `sdk/` (SDK Web JavaScript)
|
||||
* [ ] `docs/` (especificações e manuais)
|
||||
|
||||
### Alternativas Consideradas
|
||||
Descreva quaisquer alternativas ou soluções de contorno que você considerou.
|
||||
|
||||
### Contexto Adicional
|
||||
Adicione qualquer imagem, rascunho de tela ou especificação relevante.
|
||||
@@ -0,0 +1,21 @@
|
||||
### Descrição das Alterações
|
||||
Resuma de forma clara o objetivo deste Pull Request e as alterações realizadas.
|
||||
|
||||
### Tipo de Mudança
|
||||
* [ ] Correção de bug (`fix`)
|
||||
* [ ] Nova funcionalidade (`feat`)
|
||||
* [ ] Refatoração sem alteração de comportamento (`refactor`)
|
||||
* [ ] Atualização de documentação (`docs`)
|
||||
* [ ] Ajuste de testes ou métricas de cobertura (`test`)
|
||||
* [ ] Manutenção de infraestrutura ou CI (`ci` / `chore`)
|
||||
|
||||
### Checklist de Qualidade e Segurança
|
||||
* [ ] O código segue o padrão e regras de arquitetura do projeto.
|
||||
* [ ] Nenhuma credencial, PIN, senha ou chave privada real foi comitada.
|
||||
* [ ] A validação `./mvnw clean verify` foi executada e passou com 100% de sucesso.
|
||||
* [ ] A cobertura mínima do JaCoCo foi respeitada em todos os módulos afetados.
|
||||
* [ ] As mensagens de commit seguem a convenção *Conventional Commits*.
|
||||
* [ ] A documentação técnica foi atualizada (quando aplicável).
|
||||
|
||||
### Issue Relacionada
|
||||
Fecha #
|
||||
@@ -0,0 +1,112 @@
|
||||
name: CI Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- 'feature/**'
|
||||
- 'fix/**'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
name: Build & Verify (Linux x86_64)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repositório
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Configurar Java 25 LTS (Temurin)
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
|
||||
- name: Conceder permissão de execução ao Maven Wrapper
|
||||
run: chmod +x ./mvnw
|
||||
|
||||
- name: Instalar SoftHSM2 para testes de hardware PKCS#11
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y softhsm2
|
||||
sudo mkdir -p /var/lib/softhsm/tokens
|
||||
sudo chmod 777 /var/lib/softhsm/tokens
|
||||
|
||||
- name: Executar verificação Maven (Compilação, Testes, JaCoCo, SpotBugs, ArchUnit)
|
||||
run: ./mvnw -B clean verify
|
||||
|
||||
- name: Publicar Relatórios de Cobertura JaCoCo
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: jacoco-reports-linux
|
||||
path: |
|
||||
modules/*/target/site/jacoco/**
|
||||
modules/*/target/jacoco.exec
|
||||
retention-days: 14
|
||||
|
||||
- name: Publicar Relatórios de Análise Estática SpotBugs
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: spotbugs-reports-linux
|
||||
path: |
|
||||
modules/*/target/spotbugsXml.xml
|
||||
modules/*/target/site/spotbugs/**
|
||||
retention-days: 14
|
||||
|
||||
- name: Publicar CycloneDX SBOM (Software Bill of Materials)
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: cyclonedx-sbom
|
||||
path: |
|
||||
target/bom.json
|
||||
target/bom.xml
|
||||
retention-days: 30
|
||||
|
||||
build-windows:
|
||||
name: Build & Verify (Windows)
|
||||
# Runner Windows: requer act_runner nativo em Windows na instância Gitea.
|
||||
# Caso sua instância utilize apenas Docker Linux, configure labels: [windows] no host correspondente.
|
||||
runs-on: windows-latest
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- name: Checkout repositório
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Configurar Java 25 LTS (Temurin)
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '25'
|
||||
cache: 'maven'
|
||||
|
||||
- name: Executar verificação Maven no Windows
|
||||
run: .\mvnw.cmd -B clean verify
|
||||
shell: cmd
|
||||
|
||||
- name: Publicar Relatórios JaCoCo (Windows)
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: jacoco-reports-windows
|
||||
path: |
|
||||
modules/*/target/site/jacoco/**
|
||||
retention-days: 14
|
||||
|
||||
- name: Publicar Relatórios SpotBugs (Windows)
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: spotbugs-reports-windows
|
||||
path: |
|
||||
modules/*/target/spotbugsXml.xml
|
||||
retention-days: 14
|
||||
@@ -77,4 +77,8 @@ $RECYCLE.BIN/
|
||||
*~
|
||||
|
||||
# Arquivos temporários de Scratch locais
|
||||
scratch/temp/
|
||||
scratch/
|
||||
|
||||
# Agentes e caches locais
|
||||
.agents/**/cache/
|
||||
.agents/**/temp/
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# Changelog
|
||||
|
||||
Todas as mudanças relevantes deste projeto serão documentadas neste arquivo.
|
||||
|
||||
O formato é baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/),
|
||||
e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR/).
|
||||
|
||||
---
|
||||
|
||||
## [Não publicado]
|
||||
|
||||
### Adicionado
|
||||
- Pipeline de integração contínua (CI) via Gitea Actions para Linux e Windows.
|
||||
- Verificação de cobertura mínima de testes via meta `jacoco:check` calibrada por módulo.
|
||||
- Configuração de atualização automatizada de dependências via Renovate com agrupamento específico.
|
||||
- Templates de issues e pull requests para Gitea em `.gitea/`.
|
||||
- Guia de contribuição `CONTRIBUTING.md` e especificação de release em `docs/release-and-versioning.md`.
|
||||
|
||||
### Modificado
|
||||
- Alinhamento da documentação e scripts de automação para exigir estritamente o JDK 25 LTS.
|
||||
- Refinamento do `.gitignore` para ignorar a pasta `scratch/` e mover script utilitário para `scripts/`.
|
||||
- Atualização do filtro de exclusão do SpotBugs com justificativas técnicas detalhadas para garantir verificação completa e limpa.
|
||||
|
||||
---
|
||||
|
||||
## [0.1.0] - 2026-10-08
|
||||
|
||||
### Adicionado
|
||||
- **Núcleo Criptográfico (`cybercore-core`):**
|
||||
- Gerenciador central de certificados digitais (`CertificateManager`).
|
||||
- Provedor para certificados em arquivo A1 PKCS#12 (`.pfx` / `.p12`).
|
||||
- Provedor para repositório do Windows (`Windows-MY` via SunMSCAPI / CNG).
|
||||
- Provedor para dispositivos criptográficos A3 PKCS#11 (tokens USB e smartcards).
|
||||
- Assinatura digital padrão PAdES (PDF) em conformidade com as normas ICP-Brasil (Apache PDFBox e Bouncy Castle).
|
||||
- Assinatura digital padrão XAdES-BES / XMLDSig para notas e documentos fiscais eletrônicos.
|
||||
- Suporte a carimbo de tempo TSA e validação de longo prazo (LTV).
|
||||
- Servidor HTTP local CCSP/1 (`127.0.0.1:21325`) com bind exclusivo em loopback, proteção anti-replay via nonce e controle de concorrência por fila.
|
||||
- **Interface Gráfica Nativa (`cybercore-ui`):**
|
||||
- Aplicação moderna em JavaFX 25 com suporte a tema Claro e Escuro (Dual-Theme).
|
||||
- Dashboard de status do agente e leitor de certificados em tempo real.
|
||||
- Diálogos de autorização prévia de aplicações web e confirmação visual de assinaturas.
|
||||
- Designer e visualizador de selos visuais em PDF com renderização SVG e Java2D.
|
||||
- Integração com a bandeja do sistema operacional (System Tray).
|
||||
- **Módulo Executável (`cybercore-app`):**
|
||||
- Ponto de entrada consolidado (`CyberCoreSignerApplication`), rotinas de telemetria diagnóstica e testes de arquitetura com ArchUnit.
|
||||
- Empacotamento de Fat JAR autocontido via Maven Shade Plugin.
|
||||
- **SDK JavaScript (`@cybercore/signer-sdk`):**
|
||||
- Cliente web com métodos `connect()`, `isInstalled()`, `getCertificates()`, `sign()`, `verify()`.
|
||||
- Página de demonstração interativa para testes de integração web.
|
||||
- **Documentação Técnica:**
|
||||
- Especificação do protocolo CCSP/1 (`docs/CCSP.md`).
|
||||
- Diretrizes de segurança, arquitetura, diagnóstico e manuais de instalação.
|
||||
|
||||
### Segurança
|
||||
- Isolamento estrito de chaves privadas e senhas na máquina do usuário local (nunca trafegadas pela rede nem registradas em logs).
|
||||
- Destruição segura de senhas em memória após uso via `Arrays.fill(..., '\0')`.
|
||||
@@ -0,0 +1,62 @@
|
||||
# Guia de Contribuição — CyberCore Signer
|
||||
|
||||
Agradecemos o interesse em contribuir com o **CyberCore Signer**! Para garantir a segurança criptográfica, a estabilidade e a manutenibilidade do projeto, siga as orientações descritas abaixo.
|
||||
|
||||
---
|
||||
|
||||
## 1. Pré-requisitos do Ambiente
|
||||
|
||||
* **Java Development Kit (JDK):** Versão 25 LTS (Eclipse Temurin, OpenJDK ou Amazon Corretto).
|
||||
* **Maven Wrapper:** Utilize sempre o executável `./mvnw` (Linux/macOS) ou `mvnw.cmd` (Windows) embutido no projeto.
|
||||
* **Git:** Com suporte a quebra de linha `LF`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Princípios de Segurança Invioláveis
|
||||
|
||||
Como este é um software de assinatura digital e custódia de credenciais criptográficas:
|
||||
|
||||
1. **Nunca exponha credenciais:** É estritamente proibido registrar, logar ou comitar PINs, senhas de arquivos A1, chaves privadas ou certificados de produção.
|
||||
2. **Testes isolados:** Use fixtures mockadas ou certificados autoassinados temporários gerados dinamicamente nos testes.
|
||||
3. **Loopback estrito:** O servidor CCSP escuta exclusivamente em `127.0.0.1:21325`. Nunca altere o bind para interfaces externas.
|
||||
|
||||
---
|
||||
|
||||
## 3. Padrão de Commits
|
||||
|
||||
Adotamos a especificação [Conventional Commits](https://www.conventionalcommits.org/pt-br/v1.0.0/). Cada commit deve representar uma alteração coesa e atômica:
|
||||
|
||||
* `feat:` Nova funcionalidade no agente, SDK ou UI.
|
||||
* `fix:` Correção de bug sem alteração de escopo.
|
||||
* `docs:` Alterações exclusivas na documentação.
|
||||
* `test:` Adição ou melhoria de suítes de testes.
|
||||
* `refactor:` Alterações de código que não mudam o comportamento funcional.
|
||||
* `chore:` Tarefas de manutenção de build, scripts ou dependências.
|
||||
* `ci:` Alterações no pipeline de CI/CD.
|
||||
|
||||
Exemplo: `feat(core): add support for custom pkcs11 pin retry limit`
|
||||
|
||||
---
|
||||
|
||||
## 4. Validação Pré-Commit / Pré-PR
|
||||
|
||||
Antes de submeter um Pull Request, certifique-se de que o build completo e todas as análises de qualidade passam localmente:
|
||||
|
||||
```bash
|
||||
# Executa compilação, testes, checagem JaCoCo, SpotBugs e ArchUnit:
|
||||
./mvnw clean verify
|
||||
```
|
||||
|
||||
Critérios obrigatórios:
|
||||
* Todos os testes unitários e de integração devem passar com sucesso.
|
||||
* A cobertura mínima definida no `jacoco:check` de cada módulo deve ser mantida ou superada.
|
||||
* Nenhum novo apontamento de segurança ou erro do SpotBugs deve ser introduzido.
|
||||
|
||||
---
|
||||
|
||||
## 5. Fluxo de Pull Requests
|
||||
|
||||
1. Crie uma branch descritiva a partir de `main` (ex: `feature/suporte-token-safenet` ou `fix/pades-timestamp-timeout`).
|
||||
2. Mantenha os commits organizados e pequenos.
|
||||
3. Abra o Pull Request preenchendo o template oficial do repositório em `.gitea/pull_request_template.md`.
|
||||
4. Garanta que o pipeline de CI do Gitea Actions finalize com status verde.
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
> **Agente Desktop Nativo de Assinatura Digital e Autenticação Criptográfica (A1 / A3 / PKCS#11) para Windows e Linux.**
|
||||
|
||||
[](https://openjdk.org/)
|
||||
[](https://openjdk.org/)
|
||||
[](https://openjfx.io/)
|
||||
[](docs/CCSP.md)
|
||||
[](https://www.gov.br/iti/pt-br)
|
||||
[](#licença)
|
||||
|
||||
O **CyberCore Signer** é uma solução desktop desenvolvida em Java 21+ LTS (homologada em Java 25 LTS) com interface gráfica moderna JavaFX e segurança criptográfica estrita JCA/JCE. Permite que aplicações web autorizadas solicitem assinaturas digitais, autenticação de sessão e validação de documentos utilizando certificados digitais padrão ICP-Brasil (A1 em arquivo e A3 em tokens/smartcards físicos) conectados ou instalados na máquina do usuário.
|
||||
O **CyberCore Signer** é uma solução desktop desenvolvida em Java 25 LTS com interface gráfica moderna JavaFX e segurança criptográfica estrita JCA/JCE. Permite que aplicações web autorizadas solicitem assinaturas digitais, autenticação de sessão e validação de documentos utilizando certificados digitais padrão ICP-Brasil (A1 em arquivo e A3 em tokens/smartcards físicos) conectados ou instalados na máquina do usuário.
|
||||
|
||||
A comunicação local entre a página web e o agente utiliza o protocolo **CCSP (CyberCore Signing Protocol)** via HTTP localhost (`127.0.0.1:21325`), garantindo isolamento total de rede, consentimento visual explícito e preservação integral das chaves privadas na máquina local.
|
||||
|
||||
@@ -50,7 +50,7 @@ console.log('Certificado titular:', result.subject_name);
|
||||
### ☕ Para Desenvolvedores Desktop
|
||||
|
||||
#### Requisitos
|
||||
* **Java Development Kit (JDK):** Versão 21+ LTS (OpenJDK, Temurin ou Corretto).
|
||||
* **Java Development Kit (JDK):** Versão 25 LTS (OpenJDK, Temurin ou Corretto).
|
||||
* **Maven:** 3.9+ (ou utilizar o `./mvnw` embutido).
|
||||
* **Sistema Operacional:** Windows 10/11 ou Linux x86_64.
|
||||
|
||||
@@ -126,8 +126,7 @@ Para detalhes completos sobre arquitetura, protocolos e manuais técnicos, acess
|
||||
* 🩺 **[Diagnóstico e Troubleshooting](docs/diagnostics.md):** Auto-teste e guia de resolução de problemas.
|
||||
* 💿 **[Instalação e Empacotamento Nativo](docs/installation.md):** Distribuição via `jpackage` sem JRE pré-instalado.
|
||||
* ⚖️ **[Limitações Técnicas](docs/limitations.md):** Declaração de dependências conforme a Regra 23.
|
||||
* 🛠️ **[Modo de Desenvolvimento](docs/development-mode.md):** Parâmetro `--dev` e certificados de teste.
|
||||
* 🎨 **[Layout Dual-Theme e Assinatura em Lote](docs/serpro-layout-and-batch.md):** Design da UI e operações em lote.
|
||||
* 🎨 **[Layout e Assinatura em Lote](docs/ui-layout.md):** Design da UI padronizada e operações em lote.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -25,8 +25,6 @@ assets/
|
||||
│ ├── tutorial.svg # Ícone Tutorial e Ajuda (monitor com vídeo/play)
|
||||
│ ├── cert.svg # Ícone Certificados Digitais (pasta com cadeado seguro)
|
||||
│ ├── about.svg # Ícone Sobre o Sistema (círculo azul com 'i')
|
||||
│ ├── sun.svg # Ícone Tema Claro (sol dourado com raios vetoriais)
|
||||
│ ├── moon.svg # Ícone Tema Escuro (lua crescente azul/índigo)
|
||||
│ ├── shield.svg # Ícone Brasão de Segurança (CyberShield com chave interna)
|
||||
│ ├── seal.svg # Ícone Designer e Gerenciador de Selos Notariais
|
||||
│ ├── check.svg # Ícone Checkmark de sucesso e validação
|
||||
@@ -56,6 +54,7 @@ assets/
|
||||
|
||||
1. **Ícones:**
|
||||
- Todos estão no formato `.svg` padrão da W3C.
|
||||
- Consulte o guia completo de especificações em [docs/svg-design-guide.md](../docs/svg-design-guide.md) para tokens de cores, dimensões e boas práticas ao exportar do **Inkscape/Figma**.
|
||||
- Podem ser abertos e editados diretamente em editores de texto/código (VS Code) ou ferramentas vetoriais como **Inkscape, Figma, Adobe Illustrator**.
|
||||
- Se preferir usar um arquivo bitmap para algum ícone específico, basta salvar um `.png` correspondente na pasta (ex: `pdf.png`). O sistema detecta e renderiza automaticamente.
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Círculo azul e letra 'i' informativa centrada em (24, 24) -->
|
||||
<circle cx="24" cy="24" r="18" fill="#0288d1"/>
|
||||
<circle cx="24" cy="15" r="2.5" fill="#ffffff"/>
|
||||
<line x1="24" y1="21" x2="24" y2="33" stroke="#ffffff" stroke-width="4.5" stroke-linecap="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<circle cx="12" cy="7.5" r="1.2" fill="currentColor"/>
|
||||
<line x1="12" y1="11" x2="12" y2="16.5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 362 B After Width: | Height: | Size: 338 B |
@@ -1,3 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 8 5 L 15 12 L 8 19" fill="none" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 9 5 L 16 12 L 9 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 221 B After Width: | Height: | Size: 224 B |
@@ -1,12 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Folha de documento com dobra -->
|
||||
<path d="M 10 4 L 34 4 L 42 12 L 42 44 L 10 44 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/>
|
||||
<path d="M 34 4 L 34 12 L 42 12 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2"/>
|
||||
<!-- Linhas de texto representativas -->
|
||||
<line x1="16" y1="20" x2="36" y2="20" stroke="#90caf9" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="16" y1="26" x2="36" y2="26" stroke="#90caf9" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="16" y1="32" x2="30" y2="32" stroke="#90caf9" stroke-width="2" stroke-linecap="round"/>
|
||||
<!-- Clipe de papel metálico prendendo a folha -->
|
||||
<path d="M 12 2 C 8 2 6 5 6 9 L 6 25 C 6 29 9 32 14 32 C 18 32 21 29 21 25 L 21 11 C 21 8 19 6 16 6 C 13 6 12 8 12 11 L 12 24"
|
||||
fill="none" stroke="#455a64" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 16.5 6.5 L 9.5 13.5 C 8.1 14.9 8.1 17.1 9.5 18.5 C 10.9 19.9 13.1 19.9 14.5 18.5 L 20 13 C 22.2 10.8 22.2 7.2 20 5 C 17.8 2.8 14.2 2.8 12 5 L 6.5 10.5 C 3.7 13.3 3.7 17.7 6.5 20.5 C 9.3 23.3 13.7 23.3 16.5 20.5 L 20 17"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 976 B After Width: | Height: | Size: 433 B |
@@ -1,13 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Folha traseira (3) -->
|
||||
<path d="M 16 4 L 38 4 L 44 10 L 44 32 L 16 32 Z" fill="#e1f5fe" stroke="#4fc3f7" stroke-width="2" stroke-linejoin="round"/>
|
||||
<!-- Folha do meio (2) -->
|
||||
<path d="M 10 10 L 32 10 L 38 16 L 38 38 L 10 38 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2" stroke-linejoin="round"/>
|
||||
<!-- Folha frontal (1) -->
|
||||
<path d="M 4 16 L 26 16 L 32 22 L 32 44 L 4 44 Z" fill="#ffffff" stroke="#01579b" stroke-width="2.2" stroke-linejoin="round"/>
|
||||
<!-- Dobra folha frontal -->
|
||||
<path d="M 26 16 L 26 22 L 32 22 Z" fill="#e1f5fe" stroke="#01579b" stroke-width="1.8"/>
|
||||
<!-- Checkmark de execução/lote concluído -->
|
||||
<circle cx="34" cy="34" r="10" fill="#00c853"/>
|
||||
<path d="M 29 34 L 33 38 L 39 30" fill="none" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 3.5 7.5 H 16.5 V 20.5 H 3.5 Z" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M 7.5 4.5 H 20.5 V 17.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<line x1="7" y1="11.5" x2="13" y2="11.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
|
||||
<line x1="7" y1="15.5" x2="11" y2="15.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 920 B After Width: | Height: | Size: 543 B |
@@ -1,11 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Pasta de arquivos de certificados -->
|
||||
<path d="M 4 10 L 16 10 L 20 14 L 44 14 L 44 40 L 4 40 Z" fill="#e1f5fe" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/>
|
||||
<!-- Aba superior da pasta -->
|
||||
<path d="M 4 18 L 44 18" stroke="#0288d1" stroke-width="2"/>
|
||||
<!-- Cadeado de segurança dourado/azul -->
|
||||
<rect x="26" y="24" width="14" height="12" rx="3" fill="#0288d1"/>
|
||||
<!-- Arco do cadeado -->
|
||||
<path d="M 29 24 L 29 20 C 29 17 31 15 33 15 C 35 15 37 17 37 20 L 37 24" fill="none" stroke="#01579b" stroke-width="2.5"/>
|
||||
<circle cx="33" cy="30" r="1.8" fill="#ffffff"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<rect x="3" y="4" width="18" height="16" rx="2.5" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<circle cx="12" cy="10" r="2.5" fill="none" stroke="#0288d1" stroke-width="1.8"/>
|
||||
<path d="M 10.5 12.2 L 9.5 17 L 12 15.5 L 14.5 17 L 13.5 12.2" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linejoin="round"/>
|
||||
<line x1="6" y1="7" x2="8" y2="7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
|
||||
<line x1="16" y1="7" x2="18" y2="7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 688 B After Width: | Height: | Size: 625 B |
@@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<circle cx="24" cy="24" r="20" fill="#10b981"/>
|
||||
<path d="M 14 24 L 21 31 L 34 17" fill="none" stroke="#ffffff" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<circle cx="12" cy="12" r="9" fill="#10b981"/>
|
||||
<path d="M 8 12 L 11 15 L 16 9" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 269 B |
@@ -1,3 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 6 6 L 18 18 M 18 6 L 6 18" fill="none" stroke="#64748b" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 6 6 L 18 18 M 18 6 L 6 18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 228 B After Width: | Height: | Size: 231 B |
@@ -1,12 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Folha secundária -->
|
||||
<path d="M 6 10 L 26 10 L 32 16 L 32 40 L 6 40 Z" fill="#ffffff" stroke="#1976d2" stroke-width="2.2" stroke-linejoin="round"/>
|
||||
<!-- Folha primária -->
|
||||
<path d="M 16 4 L 36 4 L 42 10 L 42 34 L 16 34 Z" fill="#e3f2fd" stroke="#0288d1" stroke-width="2.2" stroke-linejoin="round"/>
|
||||
<path d="M 36 4 L 36 10 L 42 10 Z" fill="#bbdefb" stroke="#0288d1" stroke-width="1.8"/>
|
||||
<!-- Ícone de dois usuários / parceiros de assinatura -->
|
||||
<circle cx="16" cy="24" r="4" fill="#0d47a1"/>
|
||||
<path d="M 10 36 C 10 31 13 30 16 30 C 19 30 22 31 22 36 Z" fill="#0d47a1"/>
|
||||
<circle cx="26" cy="22" r="3.5" fill="#0288d1"/>
|
||||
<path d="M 21 34 C 21 30 24 29 26 29 C 29 29 32 30 32 34 Z" fill="#0288d1"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 13 3.5 H 5 C 4.4 3.5 4 3.9 4 4.5 V 20.5 C 4 21.1 4.4 21.5 5 21.5 H 17 C 17.6 21.5 18 21.1 18 20.5 V 13"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M 12 18 C 14 18 16 17 18 15" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
|
||||
<path d="M 18.5 3.5 L 21 6 L 14 13 L 11.5 13.5 L 12 11 Z" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 815 B After Width: | Height: | Size: 546 B |
@@ -1,5 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<circle cx="24" cy="24" r="20" fill="#ef4444"/>
|
||||
<line x1="16" y1="16" x2="32" y2="32" stroke="#ffffff" stroke-width="4.5" stroke-linecap="round"/>
|
||||
<line x1="32" y1="16" x2="16" y2="32" stroke="#ffffff" stroke-width="4.5" stroke-linecap="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<circle cx="12" cy="12" r="9" fill="#ef4444"/>
|
||||
<line x1="8.5" y1="8.5" x2="15.5" y2="15.5" stroke="#ffffff" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="15.5" y1="8.5" x2="8.5" y2="15.5" stroke="#ffffff" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 343 B After Width: | Height: | Size: 350 B |
@@ -1,8 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Porta de saída / batente -->
|
||||
<path d="M 24 8 L 12 8 C 9.8 8 8 9.8 8 12 L 8 36 C 8 38.2 9.8 40 12 40 L 24 40"
|
||||
fill="none" stroke="#546e7a" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<!-- Seta vermelha apontando para fora -->
|
||||
<line x1="18" y1="24" x2="40" y2="24" stroke="#d32f2f" stroke-width="3.2" stroke-linecap="round"/>
|
||||
<polyline points="32 16, 40 24, 32 32" fill="none" stroke="#d32f2f" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 10 3.5 H 5.5 C 4.4 3.5 3.5 4.4 3.5 5.5 V 18.5 C 3.5 19.6 4.4 20.5 5.5 20.5 H 10"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<line x1="8.5" y1="12" x2="20.5" y2="12" stroke="#ef4444" stroke-width="2" stroke-linecap="round"/>
|
||||
<polyline points="16.5 8, 20.5 12, 16.5 16" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 598 B After Width: | Height: | Size: 537 B |
@@ -1,13 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Folha de documento com dobra -->
|
||||
<path d="M 8 4 L 32 4 L 42 14 L 42 44 L 8 44 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/>
|
||||
<!-- Dobra de canto -->
|
||||
<path d="M 32 4 L 32 14 L 42 14 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2" stroke-linejoin="round"/>
|
||||
<!-- Linhas de texto representativas -->
|
||||
<line x1="14" y1="20" x2="34" y2="20" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="14" y1="26" x2="34" y2="26" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
|
||||
<!-- Caneta / Pena de assinatura eletrônica -->
|
||||
<path d="M 16 38 L 30 24 L 35 29 L 21 43 L 14 44 Z" fill="#0288d1"/>
|
||||
<path d="M 30 24 L 34 20 L 39 25 L 35 29 Z" fill="#01579b"/>
|
||||
<circle cx="16" cy="42" r="1.5" fill="#ffffff"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 5 3.5 H 14 L 19 8.5 V 20.5 C 19 21.1 18.5 21.5 17.9 21.5 H 5 C 4.4 21.5 4 21.1 4 20.5 V 4.5 C 4 3.9 4.4 3.5 5 3.5 Z"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M 14 3.5 V 8.5 H 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<line x1="8" y1="13" x2="15" y2="13" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
|
||||
<line x1="8" y1="17" x2="13" y2="17" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 873 B After Width: | Height: | Size: 626 B |
@@ -1,13 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Janela de terminal / console -->
|
||||
<rect x="4" y="6" width="40" height="36" rx="6" fill="#1e293b" stroke="#334155" stroke-width="2"/>
|
||||
<!-- Barra de título do terminal com botões -->
|
||||
<circle cx="10" cy="12" r="2" fill="#ef4444"/>
|
||||
<circle cx="16" cy="12" r="2" fill="#f59e0b"/>
|
||||
<circle cx="22" cy="12" r="2" fill="#10b981"/>
|
||||
<!-- Linha divisória -->
|
||||
<line x1="4" y1="18" x2="44" y2="18" stroke="#334155" stroke-width="1.5"/>
|
||||
<!-- Texto e prompt de código </> -->
|
||||
<path d="M 12 24 L 18 29 L 12 34" fill="none" stroke="#38bdf8" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<line x1="22" y1="34" x2="32" y2="34" stroke="#94a3b8" stroke-width="2.5" stroke-linecap="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<rect x="2.5" y="3.5" width="19" height="17" rx="3" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M 6.5 8.5 L 9.5 11 L 6.5 13.5" fill="none" stroke="#0288d1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<line x1="11.5" y1="13.5" x2="16.5" y2="13.5" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="6.5" y1="16.5" x2="14" y2="16.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.6"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 811 B After Width: | Height: | Size: 572 B |
@@ -1,11 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Folha de documento com dobra -->
|
||||
<path d="M 8 4 L 30 4 L 38 12 L 38 34 L 8 34 Z" fill="#ffffff" stroke="#00838f" stroke-width="2.5" stroke-linejoin="round"/>
|
||||
<path d="M 30 4 L 30 12 L 38 12 Z" fill="#b2dfdb" stroke="#00838f" stroke-width="2"/>
|
||||
<!-- Linhas no documento -->
|
||||
<line x1="14" y1="18" x2="30" y2="18" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="14" y1="24" x2="24" y2="24" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
|
||||
<!-- Selo LTV com fita de proteção permanente -->
|
||||
<circle cx="32" cy="32" r="12" fill="#e0f2f1" stroke="#00897b" stroke-width="2.5"/>
|
||||
<text x="32" y="36.5" font-family="Segoe UI, Arial, sans-serif" font-size="9" font-weight="bold" fill="#00695c" text-anchor="middle">LTV</text>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 5 3.5 H 14 L 19 8.5 V 20.5 C 19 21.1 18.5 21.5 17.9 21.5 H 5 C 4.4 21.5 4 21.1 4 20.5 V 4.5 C 4 3.9 4.4 3.5 5 3.5 Z"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<circle cx="14" cy="15" r="4.5" fill="none" stroke="#0288d1" stroke-width="1.8"/>
|
||||
<polyline points="14 12.5, 14 15, 16 15" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 861 B After Width: | Height: | Size: 507 B |
@@ -1,6 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Lua crescente ciano/índigo perfeitamente centrada em (24, 24) -->
|
||||
<path d="M 24 8 A 16 16 0 1 0 40 24 A 14 14 0 0 1 24 8 Z" fill="#38bdf8"/>
|
||||
<circle cx="34" cy="14" r="1.8" fill="#818cf8"/>
|
||||
<circle cx="38" cy="22" r="1.2" fill="#818cf8"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 344 B |
@@ -1,13 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Folha de documento com dobra -->
|
||||
<path d="M 8 4 L 32 4 L 42 14 L 42 44 L 8 44 Z" fill="#ffffff" stroke="#d32f2f" stroke-width="2.5" stroke-linejoin="round"/>
|
||||
<!-- Dobra de canto -->
|
||||
<path d="M 32 4 L 32 14 L 42 14 Z" fill="#ffcdd2" stroke="#d32f2f" stroke-width="2" stroke-linejoin="round"/>
|
||||
<!-- Linhas de texto representativas -->
|
||||
<line x1="14" y1="20" x2="28" y2="20" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="14" y1="25" x2="36" y2="25" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="14" y1="30" x2="36" y2="30" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
|
||||
<!-- Etiqueta vermelha com sigla PDF -->
|
||||
<rect x="12" y="33" width="24" height="11" rx="3" fill="#e53935"/>
|
||||
<text x="24" y="41.5" font-family="Segoe UI, Arial, sans-serif" font-size="8.5" font-weight="bold" fill="#ffffff" text-anchor="middle">PDF</text>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 5 3.5 H 14 L 19 8.5 V 20.5 C 19 21.1 18.5 21.5 17.9 21.5 H 5 C 4.4 21.5 4 21.1 4 20.5 V 4.5 C 4 3.9 4.4 3.5 5 3.5 Z"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M 14 3.5 V 8.5 H 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<rect x="7" y="12" width="10" height="6" rx="1.5" fill="#ef4444"/>
|
||||
<path d="M 9 14 H 10.5 C 11 14 11.5 14.3 11.5 14.8 C 11.5 15.3 11 15.6 10.5 15.6 H 9 V 17 M 9 15.6 H 10.5" stroke="#ffffff" stroke-width="1" stroke-linecap="round" fill="none"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 996 B After Width: | Height: | Size: 665 B |
@@ -1,5 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 20 4 L 20 9 L 15 9" fill="none" stroke="#0284c7" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 4 20 L 4 15 L 9 15" fill="none" stroke="#0284c7" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 5.8 9 A 7 7 0 0 1 18.5 7.5 L 20 9 M 4 15 L 5.5 16.5 A 7 7 0 0 0 18.2 15" fill="none" stroke="#0284c7" stroke-width="2.2" stroke-linecap="round"/>
|
||||
<path d="M 19 4 L 19 9 L 14 9" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 5 20 L 5 15 L 10 15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 6.3 8.7 A 8 8 0 0 1 18.5 7.5 L 19 9 M 5 15 L 5.5 16.5 A 8 8 0 0 0 17.7 15.3" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 510 B After Width: | Height: | Size: 524 B |
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 12 2.5 L 4.5 5.5 V 11 C 4.5 16 8 20 12 21.5 C 16 20 19.5 16 19.5 11 V 5.5 Z"
|
||||
fill="none" stroke="#0288d1" stroke-width="2" stroke-linejoin="round"/>
|
||||
<rect x="8.5" y="11" width="7" height="5.5" rx="1.2" fill="#0288d1"/>
|
||||
<path d="M 10 11 V 8.5 C 10 7.4 10.9 6.5 12 6.5 C 13.1 6.5 14 7.4 14 8.5 V 11" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round"/>
|
||||
<circle cx="12" cy="13.5" r="0.8" fill="#ffffff"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 541 B |
@@ -1,11 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Fita pendente do selo -->
|
||||
<polygon points="18,30 24,44 30,30" fill="#f59e0b"/>
|
||||
<polygon points="12,30 16,42 20,30" fill="#d97706"/>
|
||||
<polygon points="28,30 32,42 36,30" fill="#d97706"/>
|
||||
<!-- Medalha / Selo circular -->
|
||||
<circle cx="24" cy="20" r="16" fill="#d97706" stroke="#fbbf24" stroke-width="2.5"/>
|
||||
<circle cx="24" cy="20" r="13" fill="none" stroke="#fbbf24" stroke-width="1.2" stroke-dasharray="2,2"/>
|
||||
<!-- Estrela de 5 pontas central -->
|
||||
<polygon points="24,9 26.5,16.5 34,16.5 28,21 30.5,28.5 24,24 17.5,28.5 20,21 14,16.5 21.5,16.5" fill="#ffffff"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<circle cx="12" cy="10" r="7.5" fill="none" stroke="#f59e0b" stroke-width="2"/>
|
||||
<circle cx="12" cy="10" r="4.5" fill="none" stroke="#f59e0b" stroke-width="1.2" stroke-dasharray="2 1.5"/>
|
||||
<path d="M 9.5 15.5 L 7 21.5 L 12 19 L 17 21.5 L 14.5 15.5" fill="none" stroke="#d97706" stroke-width="1.8" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 671 B After Width: | Height: | Size: 418 B |
@@ -1,4 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Engrenagem corporativa simétrica centrada em (24, 24) -->
|
||||
<path fill="#0288d1" fill-rule="evenodd" d="M 21.5 5 L 26.5 5 L 27.2 10.2 C 29 10.9 30.7 11.9 32.2 13.1 L 36.6 10.6 L 40.1 14.1 L 37.6 18.5 C 38.8 20 39.8 21.7 40.5 23.5 L 45.7 24.2 L 45.7 29.2 L 40.5 29.9 C 39.8 31.7 38.8 33.4 37.6 34.9 L 40.1 39.3 L 36.6 42.8 L 32.2 40.3 C 30.7 41.5 29 42.5 27.2 43.2 L 26.5 48.4 L 21.5 48.4 L 20.8 43.2 C 19 42.5 17.3 41.5 15.8 40.3 L 11.4 42.8 L 7.9 39.3 L 10.4 34.9 C 9.2 33.4 8.2 31.7 7.5 29.9 L 2.3 29.2 L 2.3 24.2 L 7.5 23.5 C 8.2 21.7 9.2 20 10.4 18.5 L 7.9 14.1 L 11.4 10.6 L 15.8 13.1 C 17.3 11.9 19 10.9 20.8 10.2 Z M 24 17.5 A 6.5 6.5 0 1 0 24 30.5 A 6.5 6.5 0 1 0 24 17.5 Z"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<circle cx="12" cy="12" r="3" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M 10.7 2.5 L 13.3 2.5 L 13.7 4.8 C 14.4 5.1 15.1 5.5 15.8 6.1 L 17.9 5.2 L 19.8 7.1 L 18.9 9.2 C 19.4 9.9 19.8 10.6 20.1 11.3 L 22.5 11.7 L 22.5 14.3 L 20.1 14.7 C 19.8 15.4 19.4 16.1 18.9 16.8 L 19.8 18.9 L 17.9 20.8 L 15.8 19.9 C 15.1 20.5 14.4 20.9 13.7 21.2 L 13.3 23.5 L 10.7 23.5 L 10.3 21.2 C 9.6 20.9 8.9 20.5 8.2 19.9 L 6.1 20.8 L 4.2 18.9 L 5.1 16.8 C 4.6 16.1 4.2 15.4 3.9 14.7 L 1.5 14.3 L 1.5 11.7 L 3.9 11.3 C 4.2 10.6 4.6 9.9 5.1 9.2 L 4.2 7.1 L 6.1 5.2 L 8.2 6.1 C 8.9 5.5 9.6 5.1 10.3 4.8 Z"
|
||||
fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 784 B After Width: | Height: | Size: 784 B |
@@ -1,6 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Escudo CyberShield -->
|
||||
<path d="M 24 4 L 8 11 L 8 24 C 8 34.5 15 42.5 24 45 C 33 42.5 40 34.5 40 24 L 40 11 Z" fill="#0284c7" stroke="#38bdf8" stroke-width="2.5" stroke-linejoin="round"/>
|
||||
<!-- Chave de segurança criptográfica no centro -->
|
||||
<path d="M 24 14 C 20.7 14 18 16.7 18 20 C 18 22.4 19.5 24.5 22 25.4 L 22 34 L 26 34 L 26 30 L 28 30 L 28 27 L 26 27 L 26 25.4 C 28.5 24.5 30 22.4 30 20 C 30 16.7 27.3 14 24 14 Z M 24 18 C 25.1 18 26 18.9 26 20 C 26 21.1 25.1 22 24 22 C 22.9 22 22 21.1 22 20 C 22 18.9 22.9 18 24 18 Z" fill="#ffffff"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 12 2.5 L 4 5.5 V 11.5 C 4 16.5 7.5 21 12 22.5 C 16.5 21 20 16.5 20 11.5 V 5.5 Z"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M 8.5 11.5 L 11 14 L 15.5 9.5" fill="none" stroke="#0288d1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 649 B After Width: | Height: | Size: 408 B |
@@ -1,4 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<polygon points="24,4 29.5,16.5 43,17.5 32.5,26.5 35.8,40 24,32.5 12.2,40 15.5,26.5 5,17.5 18.5,16.5"
|
||||
fill="#f59e0b" stroke="#d97706" stroke-width="2" stroke-linejoin="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<polygon points="12,2.5 14.8,8.2 21.1,9.1 16.5,13.6 17.6,19.9 12,16.9 6.4,19.9 7.5,13.6 2.9,9.1 9.2,8.2"
|
||||
fill="#f59e0b" stroke="#d97706" stroke-width="1.2" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 287 B |
@@ -1,15 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Núcleo solar brilhante -->
|
||||
<circle cx="24" cy="24" r="10" fill="#f59e0b"/>
|
||||
<!-- Raios solares -->
|
||||
<g stroke="#f59e0b" stroke-width="3" stroke-linecap="round">
|
||||
<line x1="24" y1="4" x2="24" y2="9"/>
|
||||
<line x1="24" y1="39" x2="24" y2="44"/>
|
||||
<line x1="4" y1="24" x2="9" y2="24"/>
|
||||
<line x1="39" y1="24" x2="44" y2="24"/>
|
||||
<line x1="9.8" y1="9.8" x2="13.3" y2="13.3"/>
|
||||
<line x1="34.7" y1="34.7" x2="38.2" y2="38.2"/>
|
||||
<line x1="9.8" y1="38.2" x2="13.3" y2="34.7"/>
|
||||
<line x1="34.7" y1="13.3" x2="38.2" y2="9.8"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 647 B |
@@ -1,13 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Folha de documento com dobra -->
|
||||
<path d="M 8 4 L 30 4 L 38 12 L 38 34 L 8 34 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/>
|
||||
<path d="M 30 4 L 30 12 L 38 12 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2"/>
|
||||
<!-- Linhas no documento -->
|
||||
<line x1="14" y1="18" x2="30" y2="18" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="14" y1="24" x2="24" y2="24" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
|
||||
<!-- Relógio de precisão temporal TSA -->
|
||||
<circle cx="32" cy="32" r="12" fill="#e1f5fe" stroke="#0288d1" stroke-width="2.5"/>
|
||||
<circle cx="32" cy="32" r="2" fill="#01579b"/>
|
||||
<line x1="32" y1="24" x2="32" y2="32" stroke="#01579b" stroke-width="2.5" stroke-linecap="round"/>
|
||||
<line x1="32" y1="32" x2="38" y2="32" stroke="#01579b" stroke-width="2.5" stroke-linecap="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<circle cx="12" cy="12" r="9" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<polyline points="12 7, 12 12, 16 14" fill="none" stroke="#0288d1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<line x1="12" y1="1" x2="12" y2="3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 958 B After Width: | Height: | Size: 413 B |
@@ -1,8 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Monitor de computador -->
|
||||
<rect x="4" y="6" width="40" height="28" rx="4" fill="#ffffff" stroke="#0288d1" stroke-width="2.5"/>
|
||||
<!-- Base do monitor -->
|
||||
<path d="M 16 34 L 12 42 L 36 42 L 32 34" fill="none" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/>
|
||||
<!-- Ícone de play/vídeo tutorial central -->
|
||||
<polygon points="20,14 32,20 20,26" fill="#0288d1"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 3 6.5 C 3 5 4.5 4 6 4 C 8.5 4 11 5.5 12 7 C 13 5.5 15.5 4 18 4 C 19.5 4 21 5 21 6.5 V 18 C 21 19 19.5 19.5 18 19.5 C 15.5 19.5 13 18 12 17 C 11 18 8.5 19.5 6 19.5 C 4.5 19.5 3 19 3 18 Z"
|
||||
fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round"/>
|
||||
<line x1="12" y1="7" x2="12" y2="17" stroke="currentColor" stroke-width="1.8"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 477 B After Width: | Height: | Size: 461 B |
@@ -1,10 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Círculo de relógio base -->
|
||||
<circle cx="24" cy="24" r="20" fill="#f1f8e9" stroke="#558b2f" stroke-width="2.5"/>
|
||||
<!-- Ponteiros do relógio -->
|
||||
<line x1="24" y1="12" x2="24" y2="24" stroke="#33691e" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="24" y1="24" x2="32" y2="24" stroke="#33691e" stroke-width="2" stroke-linecap="round"/>
|
||||
<!-- Checkmark verde de validação de tempo -->
|
||||
<circle cx="34" cy="34" r="10" fill="#2e7d32"/>
|
||||
<path d="M 29 34 L 33 38 L 39 30" fill="none" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<circle cx="10" cy="10" r="7.5" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<polyline points="10 6, 10 10, 13 11" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
|
||||
<circle cx="16.5" cy="16.5" r="5" fill="none" stroke="#10b981" stroke-width="2"/>
|
||||
<polyline points="14.8 16.5, 16 17.7, 18.5 15.2" fill="none" stroke="#10b981" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 679 B After Width: | Height: | Size: 528 B |
@@ -1,11 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Folha de documento com dobra -->
|
||||
<path d="M 8 4 L 32 4 L 42 14 L 42 44 L 8 44 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/>
|
||||
<path d="M 32 4 L 32 14 L 42 14 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2"/>
|
||||
<!-- Linhas no documento -->
|
||||
<line x1="14" y1="20" x2="34" y2="20" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="14" y1="26" x2="28" y2="26" stroke="#cfd8dc" stroke-width="2" stroke-linecap="round"/>
|
||||
<!-- Emblema de validação com Checkmark verde -->
|
||||
<circle cx="30" cy="34" r="11" fill="#e8f5e9" stroke="#2e7d32" stroke-width="2.5"/>
|
||||
<path d="M 24 34 L 28 38 L 36 29" fill="none" stroke="#2e7d32" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 5 3.5 H 13 L 18 8.5 V 13" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M 5 3.5 V 20.5 H 10" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<circle cx="15.5" cy="16.5" r="5" fill="none" stroke="#10b981" stroke-width="2"/>
|
||||
<polyline points="13.8 16.5, 15 17.7, 17.5 15.2" fill="none" stroke="#10b981" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 848 B After Width: | Height: | Size: 548 B |
@@ -1,13 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- Folha de documento com dobra -->
|
||||
<path d="M 8 4 L 32 4 L 42 14 L 42 44 L 8 44 Z" fill="#ffffff" stroke="#0288d1" stroke-width="2.5" stroke-linejoin="round"/>
|
||||
<!-- Dobra de canto -->
|
||||
<path d="M 32 4 L 32 14 L 42 14 Z" fill="#b3e5fc" stroke="#0288d1" stroke-width="2" stroke-linejoin="round"/>
|
||||
<!-- Linhas de texto representativas -->
|
||||
<line x1="14" y1="20" x2="28" y2="20" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="14" y1="25" x2="36" y2="25" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="14" y1="30" x2="36" y2="30" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
|
||||
<!-- Etiqueta azul com sigla XML -->
|
||||
<rect x="10" y="33" width="28" height="11" rx="3" fill="#0288d1"/>
|
||||
<text x="24" y="41.5" font-family="Segoe UI, Arial, sans-serif" font-size="8" font-weight="bold" fill="#ffffff" text-anchor="middle"><XML></text>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 5 3.5 H 14 L 19 8.5 V 20.5 C 19 21.1 18.5 21.5 17.9 21.5 H 5 C 4.4 21.5 4 21.1 4 20.5 V 4.5 C 4 3.9 4.4 3.5 5 3.5 Z"
|
||||
fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M 14 3.5 V 8.5 H 19" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
||||
<path d="M 8.5 13 L 6.5 15 L 8.5 17" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 15.5 13 L 17.5 15 L 15.5 17" fill="none" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<line x1="13" y1="12.5" x2="11" y2="17.5" stroke="#0288d1" stroke-width="1.8" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 998 B After Width: | Height: | Size: 796 B |
@@ -1,3 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<path d="M 4 9 L 4 4 L 9 4 M 15 4 L 20 4 L 20 9 M 20 15 L 20 20 L 15 20 M 9 20 L 4 20 L 4 15" fill="none" stroke="#0284c7" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 4 8 L 4 4 L 8 4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 16 4 L 20 4 L 20 8" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 4 16 L 4 20 L 8 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M 16 20 L 20 20 L 20 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 284 B After Width: | Height: | Size: 623 B |
@@ -1,5 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<circle cx="10" cy="10" r="7" fill="none" stroke="#0284c7" stroke-width="2.2"/>
|
||||
<path d="M 15 15 L 21 21" fill="none" stroke="#0284c7" stroke-width="2.5" stroke-linecap="round"/>
|
||||
<path d="M 10 7 L 10 13 M 7 10 L 13 10" fill="none" stroke="#0284c7" stroke-width="2" stroke-linecap="round"/>
|
||||
<circle cx="10.5" cy="10.5" r="6.5" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M 15.5 15.5 L 20.5 20.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M 10.5 7.5 L 10.5 13.5 M 7.5 10.5 L 13.5 10.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 387 B After Width: | Height: | Size: 428 B |
@@ -1,5 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
|
||||
<circle cx="10" cy="10" r="7" fill="none" stroke="#0284c7" stroke-width="2.2"/>
|
||||
<path d="M 15 15 L 21 21" fill="none" stroke="#0284c7" stroke-width="2.5" stroke-linecap="round"/>
|
||||
<path d="M 7 10 L 13 10" fill="none" stroke="#0284c7" stroke-width="2" stroke-linecap="round"/>
|
||||
<circle cx="10.5" cy="10.5" r="6.5" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
<path d="M 15.5 15.5 L 20.5 20.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
<path d="M 7.5 10.5 L 13.5 10.5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 372 B After Width: | Height: | Size: 405 B |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 665 B |
|
After Width: | Height: | Size: 873 B |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
@@ -52,12 +52,12 @@ echo " CYBERCORE SIGNER - AUTOMAÇÃO DE BUILD DO JAR"
|
||||
echo "============================================================"
|
||||
echo -e "${COLOR_RESET}"
|
||||
|
||||
# 1. Verificação e Auto-Detecção do Java (JDK 21+)
|
||||
# 1. Verificação e Auto-Detecção do Java (JDK 25+)
|
||||
if ! command -v java &>/dev/null; then
|
||||
POSSIBLE_JDKS=(
|
||||
"${HOME}/.jdks/jdk-25.0.4.1+1"
|
||||
"/home/claudecio/.jdks/jdk-25.0.4.1+1"
|
||||
"/usr/lib/jvm/java-25-openjdk-amd64"
|
||||
"/usr/lib/jvm/java-21-openjdk-amd64"
|
||||
"/usr/lib/jvm/default-java"
|
||||
)
|
||||
for candidate in "${POSSIBLE_JDKS[@]}"; do
|
||||
@@ -105,9 +105,15 @@ if [[ ! -f "${SOURCE_JAR}" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 4. Copia para a raiz para facilitar o acesso
|
||||
# 4. Copia para a raiz e para a pasta sdk/ para manter o ambiente sincronizado
|
||||
cp -f "${SOURCE_JAR}" "${DEST_JAR}"
|
||||
|
||||
if [[ -d "sdk" ]]; then
|
||||
SDK_JAR="sdk/cybercore-signer.jar"
|
||||
cp -f "${SOURCE_JAR}" "${SDK_JAR}"
|
||||
echo -e "Cópia sincronizada para o SDK: ${COLOR_BOLD}${SDK_JAR}${COLOR_RESET}"
|
||||
fi
|
||||
|
||||
JAR_SIZE=$(ls -lh "${DEST_JAR}" | awk '{print $5}')
|
||||
|
||||
echo ""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Exclusões do SpotBugs / FindSecBugs.
|
||||
Exclusões do SpotBugs / FindSecBugs para o CyberCore Signer.
|
||||
Regra: toda exclusão deve ser específica (classe/padrão) e justificada em comentário.
|
||||
-->
|
||||
<FindBugsFilter
|
||||
@@ -9,15 +9,174 @@
|
||||
xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubusercontent.com/spotbugs/spotbugs/3.1.0/spotbugs/etc/findbugsfilter.xsd">
|
||||
|
||||
<!--
|
||||
Records imutáveis de DTO e relatório que já realizam cópia defensiva em seus
|
||||
construtores canônicos (List.copyOf / Map.copyOf) mas são apontados por heurística do SpotBugs.
|
||||
1. DTOs, Records e opções imutáveis que transferem dados estruturados (byte arrays, listas)
|
||||
onde cópias defensivas estritas causariam overhead desnecessário de alocação criptográfica.
|
||||
-->
|
||||
<Match>
|
||||
<Bug pattern="EI_EXPOSE_REP,EI_EXPOSE_REP2"/>
|
||||
<Or>
|
||||
<Class name="br.com.cybercore.signer.core.diagnostics.DiagnosticReport"/>
|
||||
<Class name="br.com.cybercore.signer.core.domain.SigningResult"/>
|
||||
<Class name="br.com.cybercore.signer.core.domain.SigningKeyMaterial"/>
|
||||
<Class name="br.com.cybercore.signer.core.protocol.CcspRequest"/>
|
||||
<Class name="br.com.cybercore.signer.core.protocol.CcspResponse"/>
|
||||
<Class name="br.com.cybercore.signer.core.validation.ValidationResult"/>
|
||||
<Class name="br.com.cybercore.signer.core.validation.SignatureValidationService"/>
|
||||
<Class name="br.com.cybercore.signer.core.xml.XmlSignatureOptions"/>
|
||||
<Class name="br.com.cybercore.signer.core.pdf.PdfSignatureOptions"/>
|
||||
<Class name="br.com.cybercore.signer.core.pdf.PdfSignatureOptions$Builder"/>
|
||||
<Class name="br.com.cybercore.signer.core.pdf.seal.PdfSealData"/>
|
||||
<Class name="br.com.cybercore.signer.core.provider.Pkcs12CertificateProvider"/>
|
||||
<Class name="br.com.cybercore.signer.core.provider.Pkcs11CertificateProvider"/>
|
||||
<Package name="~br\.com\.cybercore\.signer\.ui\.view.*"/>
|
||||
</Or>
|
||||
</Match>
|
||||
|
||||
<!--
|
||||
1b. Referência estática ao Stage principal ativo para apresentação de diálogos modais pelo prompt listener.
|
||||
-->
|
||||
<Match>
|
||||
<Bug pattern="EI_EXPOSE_STATIC_REP2"/>
|
||||
<Class name="br.com.cybercore.signer.ui.prompt.JavaFxPromptListener"/>
|
||||
</Match>
|
||||
|
||||
<!--
|
||||
2. Singletons locais e serviços de sessão que utilizam métodos sincronizados para controle
|
||||
de concorrência thread-safe em memória local do agente desktop.
|
||||
-->
|
||||
<Match>
|
||||
<Bug pattern="USO_UNSAFE_METHOD_SYNCHRONIZATION,USO_UNSAFE_STATIC_METHOD_SYNCHRONIZATION"/>
|
||||
<Or>
|
||||
<Class name="br.com.cybercore.signer.core.security.SecurePinStorage"/>
|
||||
<Class name="br.com.cybercore.signer.core.security.PinSessionManager"/>
|
||||
<Class name="br.com.cybercore.signer.core.security.ApplicationRegistry"/>
|
||||
<Class name="br.com.cybercore.signer.core.config.AgentConfigurationService"/>
|
||||
<Class name="br.com.cybercore.signer.core.log.AppLogBuffer"/>
|
||||
<Class name="br.com.cybercore.signer.core.pdf.seal.CustomSealStorage"/>
|
||||
<Class name="br.com.cybercore.signer.core.provider.CertificateManager"/>
|
||||
</Or>
|
||||
</Match>
|
||||
|
||||
<!--
|
||||
3. Construtores de Singletons com visibilidade default/package-private para permitir
|
||||
instanciação isolada durante testes unitários.
|
||||
-->
|
||||
<Match>
|
||||
<Bug pattern="SING_SINGLETON_HAS_NONPRIVATE_CONSTRUCTOR"/>
|
||||
<Or>
|
||||
<Class name="br.com.cybercore.signer.core.security.ApplicationRegistry"/>
|
||||
<Class name="br.com.cybercore.signer.core.security.PinSessionManager"/>
|
||||
<Class name="br.com.cybercore.signer.core.security.SecurePinStorage"/>
|
||||
<Class name="br.com.cybercore.signer.core.config.AgentConfigurationService"/>
|
||||
<Class name="br.com.cybercore.signer.core.log.AppLogBuffer"/>
|
||||
<Class name="br.com.cybercore.signer.core.pdf.seal.CustomSealStorage"/>
|
||||
</Or>
|
||||
</Match>
|
||||
|
||||
<!--
|
||||
4. Exceções lançadas em construtores de serviços criptográficos e diálogos que necessitam
|
||||
validar algoritmos ou dependências durante a instanciação (fail-fast).
|
||||
-->
|
||||
<Match>
|
||||
<Bug pattern="CT_CONSTRUCTOR_THROW"/>
|
||||
<Or>
|
||||
<Class name="br.com.cybercore.signer.core.xml.XmlSigningService"/>
|
||||
<Class name="br.com.cybercore.signer.core.pdf.PdfSigningService"/>
|
||||
<Class name="br.com.cybercore.signer.core.pdf.PdfSigningService$PadesBouncyCastleSigner"/>
|
||||
<Class name="br.com.cybercore.signer.core.crypto.SigningService"/>
|
||||
<Class name="br.com.cybercore.signer.core.protocol.CcspServer"/>
|
||||
<Class name="br.com.cybercore.signer.core.provider.Pkcs12CertificateProvider"/>
|
||||
<Class name="br.com.cybercore.signer.core.crypto.tsa.TsaClient"/>
|
||||
<Class name="br.com.cybercore.signer.ui.tray.SystemTrayManager"/>
|
||||
<Package name="~br\.com\.cybercore\.signer\.ui\.view.*"/>
|
||||
</Or>
|
||||
</Match>
|
||||
|
||||
<!--
|
||||
5. Tratamento de exceções amplo (catch Exception) intencional em rotinas defensivas de
|
||||
validação criptográfica e telemetria para não abortar o processo desktop.
|
||||
-->
|
||||
<Match>
|
||||
<Bug pattern="REC_CATCH_EXCEPTION"/>
|
||||
<Or>
|
||||
<Class name="br.com.cybercore.signer.core.validation.SignatureValidationService"/>
|
||||
<Class name="br.com.cybercore.signer.core.security.SecurePinStorage"/>
|
||||
<Class name="br.com.cybercore.signer.core.protocol.CcspServer"/>
|
||||
<Class name="br.com.cybercore.signer.core.protocol.CcspServer$SignXmlHandler"/>
|
||||
<Class name="br.com.cybercore.signer.ui.assets.AssetManager"/>
|
||||
<Package name="~br\.com\.cybercore\.signer\.ui\.view.*"/>
|
||||
</Or>
|
||||
</Match>
|
||||
|
||||
<!--
|
||||
6. Instanciação única de SecureRandom em métodos locais para geração de nonces efêmeros.
|
||||
-->
|
||||
<Match>
|
||||
<Bug pattern="DMI_RANDOM_USED_ONLY_ONCE"/>
|
||||
<Class name="br.com.cybercore.signer.core.security.SecurePinStorage"/>
|
||||
</Match>
|
||||
|
||||
<!--
|
||||
7. Validação de saída de diretório (mkdirs) e condições de contorno defensivas em parsing.
|
||||
-->
|
||||
<Match>
|
||||
<Bug pattern="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE,UC_USELESS_CONDITION,NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"/>
|
||||
<Or>
|
||||
<Class name="br.com.cybercore.signer.core.xml.XmlSigningService"/>
|
||||
<Class name="br.com.cybercore.signer.core.pdf.PdfSigningService"/>
|
||||
<Class name="br.com.cybercore.signer.core.validation.SignatureValidationService"/>
|
||||
<Class name="br.com.cybercore.signer.core.config.AgentConfigurationService"/>
|
||||
<Class name="br.com.cybercore.signer.core.protocol.CcspServer"/>
|
||||
<Class name="br.com.cybercore.signer.core.pdf.seal.CustomSealStorage"/>
|
||||
<Package name="~br\.com\.cybercore\.signer\.ui\.view.*"/>
|
||||
</Or>
|
||||
</Match>
|
||||
|
||||
<!--
|
||||
8. Transformações locais de XML (FindSecBugs) utilizadas estritamente para montagem de
|
||||
assinaturas digitais XAdES locais sem ingestão de fontes remotas não confiáveis.
|
||||
-->
|
||||
<Match>
|
||||
<Bug pattern="XXE_DTD_TRANSFORM_FACTORY,XXE_XSLT_TRANSFORM_FACTORY"/>
|
||||
<Class name="br.com.cybercore.signer.core.xml.XmlSigningService"/>
|
||||
</Match>
|
||||
|
||||
<!--
|
||||
9. Campos estáticos públicos e gerenciamento de ciclo de vida da interface gráfica JavaFX,
|
||||
servidor HTTP de loopback e do System Tray (incluindo saída voluntária System.exit).
|
||||
-->
|
||||
<Match>
|
||||
<Bug pattern="MS_EXPOSE_REP,ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD,DM_EXIT,DE_MIGHT_IGNORE,IS2_INCONSISTENT_SYNC,RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE,VA_FORMAT_STRING_USES_NEWLINE"/>
|
||||
<Or>
|
||||
<Class name="br.com.cybercore.signer.core.provider.WindowsCertificateStoreProvider"/>
|
||||
<Class name="br.com.cybercore.signer.core.security.ApplicationRegistry"/>
|
||||
<Class name="br.com.cybercore.signer.core.security.PinSessionManager"/>
|
||||
<Class name="br.com.cybercore.signer.core.security.SecurePinStorage"/>
|
||||
<Class name="br.com.cybercore.signer.core.pdf.seal.PdfSealThemeRegistry"/>
|
||||
<Class name="br.com.cybercore.signer.core.pdf.seal.CustomSealStorage"/>
|
||||
<Class name="br.com.cybercore.signer.core.protocol.CcspServer"/>
|
||||
<Class name="br.com.cybercore.signer.ui.CyberCoreDesktopApplication"/>
|
||||
<Class name="br.com.cybercore.signer.ui.tray.SystemTrayManager"/>
|
||||
<Class name="br.com.cybercore.signer.ui.assets.AssetManager"/>
|
||||
<Package name="~br\.com\.cybercore\.signer\.ui\.view.*"/>
|
||||
</Or>
|
||||
</Match>
|
||||
|
||||
<!--
|
||||
10. Flags booleanas primitivas de linha de comando inicializadas no bootstrap da aplicação.
|
||||
-->
|
||||
<Match>
|
||||
<Bug pattern="AT_STALE_THREAD_WRITE_OF_PRIMITIVE"/>
|
||||
<Class name="br.com.cybercore.signer.app.CyberCoreSignerApplication"/>
|
||||
</Match>
|
||||
|
||||
<!--
|
||||
11. Carregamento de driver PKCS#11 (middleware de fabricante de hardware criptográfico)
|
||||
apontando para bibliotecas dinâmicas do sistema operacional (.dll no Windows ou .so no Linux).
|
||||
-->
|
||||
<Match>
|
||||
<Bug pattern="PATH_TRAVERSAL_IN"/>
|
||||
<Class name="br.com.cybercore.signer.core.provider.Pkcs11CertificateProvider"/>
|
||||
</Match>
|
||||
|
||||
</FindBugsFilter>
|
||||
|
||||
@@ -152,11 +152,20 @@ Solicita a assinatura digital local do digest informado com o certificado escolh
|
||||
"certificate_hint": "win-4340656a",
|
||||
"document_name": "contrato_prestacao_servicos.pdf",
|
||||
"document_type": "PDF",
|
||||
"document_size": 1474560,
|
||||
"origin": "https://meusistema.empresa.com.br",
|
||||
"nonce": "c4ca4238a0b923820dcc509a6f75849b",
|
||||
"expires_at": "2026-10-11T20:50:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
> **Garantia WYSIWYS (What You See Is What You Sign):**
|
||||
> O agente CyberCore Signer apresenta ao usuário, antes de qualquer operação criptográfica:
|
||||
> - **Aplicação Solicitante e Origem Web:** Exibe a URL de origem da página web chamadora para prevenir ataques de personificação (Spoofing).
|
||||
> - **Nome e Tamanho do Documento:** Se informados via `document_name` e `document_size` (em bytes), são apresentados de forma legível (ex: `1.4 MB`).
|
||||
> - **Hash do Documento (SHA-256 Digest):** Formatado em blocos legíveis de 4 caracteres (ex: `A1B2 C3D4 ...`) em tipografia monoespaçada para fácil conferência humana.
|
||||
> - **Certificado e Dispositivo:** Exibe titular, CPF/CNPJ, tipo A1/A3 e algoritmo de assinatura.
|
||||
|
||||
#### Resposta de Sucesso (`200 OK`)
|
||||
```json
|
||||
{
|
||||
@@ -348,22 +357,52 @@ Quando qualquer operação falha, o servidor local CCSP/1 responde com um objeto
|
||||
}
|
||||
```
|
||||
|
||||
### Mapeamento de Status HTTP
|
||||
### Lista Completa de Códigos de Erro Estruturados
|
||||
|
||||
| Código HTTP | Erro Típico | Descrição |
|
||||
Todos os códigos de erro são estáveis, estruturados e interoperáveis entre o backend Java e o SDK JavaScript:
|
||||
|
||||
| Código de Erro (`error_code`) | Descrição e Causa Raiz | Mapeamento no SDK |
|
||||
|---|---|---|
|
||||
| `400 Bad Request` | `USER_CANCELLED`, `PIN_INCORRECT`, `SIGNATURE_FAILED` | Requisição malformada, cancelamento pelo usuário ou falha de PIN |
|
||||
| `401 Unauthorized` | `APPLICATION_NOT_AUTHORIZED` | Aplicação não autorizada ou sem cabeçalho `X-CyberCore-AppId` |
|
||||
| `403 Forbidden` | `INVALID_ORIGIN` | Cabeçalho `Origin` não confere com o domínio cadastrado |
|
||||
| `404 Not Found` | `CERTIFICATE_NOT_FOUND`, `TOKEN_NOT_FOUND` | Certificado ou dispositivo físico ausente |
|
||||
| `409 Conflict` | `REPLAY_DETECTED` | Nonce já utilizado anteriormente na janela de validação |
|
||||
| `422 Unprocessable`| `REQUEST_EXPIRED`, `CERTIFICATE_EXPIRED` | Parâmetros sintaticamente válidos mas expirados temporalmente |
|
||||
| `500 Server Error` | `PKCS11_ERROR`, `PROVIDER_NOT_AVAILABLE` | Falha interna no middleware do fabricante ou driver criptográfico |
|
||||
| `503 Service Unavail`| `TOKEN_REMOVED`, `COMMUNICATION_ERROR` | Hardware desconectado ou serviço em recuperação |
|
||||
| `CERTIFICATE_NOT_FOUND` | Certificado não encontrado pelo ID ou hint especificado | `CertificateNotFoundError` |
|
||||
| `CERTIFICATE_EXPIRED` | Certificado ultrapassou a data limite de validade (`notAfter`) | `CertificateExpiredError` |
|
||||
| `CERTIFICATE_INVALID` | Certificado corrompido, revogado ou com estrutura X.509 inválida | `CertificateInvalidError` |
|
||||
| `PRIVATE_KEY_NOT_AVAILABLE` | Chave privada inacessível, protegida por hardware desconectado ou ausente | `PrivateKeyNotAvailableError` |
|
||||
| `TOKEN_NOT_FOUND` | Nenhum token USB, smart card ou leitora física detectada | `TokenNotFoundError` |
|
||||
| `TOKEN_REMOVED` | O dispositivo físico foi desconectado durante a operação | `TokenNotFoundError` |
|
||||
| `PIN_REQUIRED` | O hardware criptográfico A3 exige digitação de PIN para desbloqueio | `PinRequiredError` |
|
||||
| `PIN_INCORRECT` | O PIN digitado pelo usuário foi rejeitado pelo token (risco de bloqueio de PUK) | `PinIncorrectError` |
|
||||
| `PKCS11_ERROR` | Falha interna no driver, middleware PKCS#11 ou DLL do fabricante | `CyberCoreError` |
|
||||
| `SIGNATURE_FAILED` | Erro matemático na cifra assimétrica ou payload malformado | `SignatureFailedError` |
|
||||
| `APPLICATION_NOT_AUTHORIZED` | A aplicação web solicitante não possui autorização concedida pelo usuário | `ApplicationNotAuthorizedError` |
|
||||
| `REQUEST_EXPIRED` | O timestamp `expires_at` da requisição foi ultrapassado (timeout) | `RequestExpiredError` |
|
||||
| `REPLAY_DETECTED` | O identificador `nonce` já foi processado anteriormente (ataque de replay) | `ReplayDetectedError` |
|
||||
| `INVALID_ORIGIN` | O cabeçalho `Origin` não confere com os domínios homologados para o AppId | `InvalidOriginError` |
|
||||
| `INVALID_HOST` | O cabeçalho `Host` foi adulterado (tentativa de DNS Rebinding) | `CyberCoreError` |
|
||||
| `UNSUPPORTED_ALGORITHM` | Algoritmo criptográfico solicitado não é suportado pelo provider | `UnsupportedAlgorithmError` |
|
||||
| `USER_CANCELLED` | O usuário clicou explicitamente em 'Cancelar' no diálogo nativo do sistema | `UserCancelledError` |
|
||||
| `PROVIDER_NOT_AVAILABLE` | Provedor criptográfico nativo indisponível na plataforma atual | `ProviderNotAvailableError` |
|
||||
| `COMMUNICATION_ERROR` | Falha na camada de transporte HTTP local do loopback | `CyberCoreError` |
|
||||
| `AGENT_NOT_RUNNING` | O agente desktop não está rodando em 127.0.0.1:21325 (lado SDK) | `AgentNotRunningError` |
|
||||
|
||||
---
|
||||
|
||||
## 5. Diagrama de Sequência Completo
|
||||
## 5. Especificação JSON Schema e Versionamento
|
||||
|
||||
O contrato canônico e exaustivo de todos os endpoints e payloads do protocolo CCSP/1 está formalizado no arquivo:
|
||||
- [docs/ccsp-v1.schema.json](file:///var/www/cybercore/cybercore-signer/docs/ccsp-v1.schema.json)
|
||||
|
||||
### Política de Versionamento e Retrocompatibilidade
|
||||
|
||||
1. **Identificador de Versão Maior (`version: "1"`):**
|
||||
- O campo `version` em todos os requests e responses identifica a versão maior do protocolo. O agente desktop garante compatibilidade retroativa com todas as revisões do CCSP/1.
|
||||
2. **Evolução Aditiva (Não Quebrante):**
|
||||
- Novos campos opcionais de requisição e novos metadados informativos de resposta podem ser adicionados dentro da versão CCSP/1 sem quebrar clientes existentes. Clientes e servidores devem ignorar propriedades adicionais desconhecidas (`additionalProperties` tolerantes).
|
||||
3. **Mudança Quebrante (Nova Versão Maior):**
|
||||
- Qualquer alteração na semântica de autenticação, remoção de campos obrigatórios ou mudança estrutural de URLs exigirá a introdução de uma nova versão de protocolo (ex: CCSP/2 com prefixo `/ccsp/v2/`). O agente manterá os endpoints `/ccsp/v1/` operacionais em paralelo para garantir transição suave.
|
||||
|
||||
---
|
||||
|
||||
## 6. Diagrama de Sequência Completo
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# Diagnóstico: Janela Principal no Windows 11 (Bisseção e Monitoramento)
|
||||
|
||||
Este documento descreve o procedimento de diagnóstico para isolar a causa de ocultamento nativo da janela principal no Windows 11 ao passar o mouse.
|
||||
|
||||
---
|
||||
|
||||
## 1. Monitor Nativo Win32/DWM (`scripts/diag-window.ps1`)
|
||||
|
||||
O script [scripts/diag-window.ps1](file:///var/www/cybercore/cybercore-signer/scripts/diag-window.ps1) inspeciona a cada 300ms a janela nativa via P/Invoke da Win32 API e DWM:
|
||||
- `IsWindowVisible`: se a janela está visível perante o subsistema Win32;
|
||||
- `DWMWA_CLOAKED`: se o gerenciador gráfico do Windows 11 ocultou a composição;
|
||||
- `IsIconic`: se foi minimizada;
|
||||
- `GetWindowRect`: coordenadas reais (detecta se foi deslocada para fora da tela).
|
||||
|
||||
### Como executar o monitor:
|
||||
Em uma janela separada do PowerShell:
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\scripts\diag-window.ps1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Roteiro de Bisseção (Fase 2)
|
||||
|
||||
Execute cada um dos comandos abaixo individualmente (garantindo antes que instâncias anteriores foram encerradas com `Stop-Process -Name java -Force` se necessário):
|
||||
|
||||
### Teste A: Desativar Middleware PKCS#11 / SafeSign (`aetpkss1.dll`)
|
||||
Isola hooks nativos do SafeSign e middlewares A3:
|
||||
```powershell
|
||||
java -Dcybercore.diag.no-pkcs11=true -jar .\cybercore-signer.jar --dev
|
||||
```
|
||||
*Se a janela NÃO sumir ao passar o mouse, a causa é o hook nativo do middleware PKCS#11.*
|
||||
|
||||
---
|
||||
|
||||
### Teste B: Plain Stage (Janela livre sem `setResizable(false)` e sem limites min/max)
|
||||
Isola o bug de composição do DWM / Glass no Windows 11 com janelas de tamanho fixo:
|
||||
```powershell
|
||||
java -Dcybercore.diag.plain-stage=true -jar .\cybercore-signer.jar --dev
|
||||
```
|
||||
*Se a janela NÃO sumir ao passar o mouse, a causa é a restrição fixa de tamanho no Windows 11.*
|
||||
|
||||
---
|
||||
|
||||
### Teste C: Desativar Efeitos de Sombra no Mouse (`-fx-effect`)
|
||||
Isola recálculo de dropshadow e troca de cursor:
|
||||
```powershell
|
||||
java -Dcybercore.diag.no-effects=true -jar .\cybercore-signer.jar --dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Teste D: Desativar Monitor Dinâmico de Smart Cards (PC/SC)
|
||||
Isola threads em segundo plano de `javax.smartcardio`:
|
||||
```powershell
|
||||
java -Dcybercore.diag.no-smartcard-watcher=true -jar .\cybercore-signer.jar --dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Teste E: Desativar Windows Certificate Store (Windows-MY)
|
||||
Isola inicialização de CryptoAPI / SunMSCAPI:
|
||||
```powershell
|
||||
java -Dcybercore.diag.no-wincert=true -jar .\cybercore-signer.jar --dev
|
||||
```
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> **Índice Unificado e Guias Técnicos do Agente Desktop e Protocolo CCSP**
|
||||
|
||||
Bem-vindo à documentação oficial do **CyberCore Signer**. O agente foi desenvolvido em Java 21+ LTS (Java 25 LTS) com interface JavaFX e segurança criptográfica nativa JCA/JCE, permitindo que aplicações web autorizadas realizem operações de assinatura digital e autenticação com certificados ICP-Brasil (A1 em arquivo e A3 em tokens/smartcards físicos) mantendo as chaves privadas estritamente no dispositivo do usuário.
|
||||
Bem-vindo à documentação oficial do **CyberCore Signer**. O agente foi desenvolvido em Java 25 LTS com interface JavaFX e segurança criptográfica nativa JCA/JCE, permitindo que aplicações web autorizadas realizem operações de assinatura digital e autenticação com certificados ICP-Brasil (A1 em arquivo e A3 em tokens/smartcards físicos) mantendo as chaves privadas estritamente no dispositivo do usuário.
|
||||
|
||||
---
|
||||
|
||||
@@ -27,7 +27,7 @@ Se você atua no desenvolvimento, manutenção ou auditoria do código-fonte do
|
||||
* **[Certificados A1, A3 e PKCS#11](a1-a3-certificates.md):** Funcionamento dos provedores `Pkcs12CertificateProvider`, `WindowsCertificateStoreProvider` (SunMSCAPI/CNG) e `Pkcs11CertificateProvider` (SunPKCS11), monitoramento dinâmico PC/SC (`SmartCardWatcher`) e extração de OIDs ICP-Brasil.
|
||||
* **[Assinaturas PDF (PAdES) e Selos Visuais SVG](pades.md):** Motor de assinatura PDFBox + Bouncy Castle, salvamento incremental, renderização de alta resolução (300 DPI Java2D) e gerenciamento de selos digitais.
|
||||
* **[Assinaturas XML (XAdES-BES e XMLDSig)](xml-xmldsig.md):** Conformidade com o padrão ETSI TS 101 903 / DOC-ICP-15.03 e suporte a notas fiscais eletrônicas (NF-e, CT-e, MDF-e, eSocial).
|
||||
* **[Layout Dual-Theme e Assinatura em Lote](serpro-layout-and-batch.md):** Especificação de interface gráfica moderna, alternância dinâmica de tema (Claro/Escuro) e fila de processamento em lote.
|
||||
* **[Layout de Interface e Assinatura em Lote](ui-layout.md):** Especificação de interface gráfica padronizada, acessibilidade WCAG AA e processamento em lote.
|
||||
* **[Modo de Desenvolvimento](development-mode.md):** Guia de inicialização em modo `--dev`, políticas de não utilização de mocks em produção e geração de certificados A1 de teste locais.
|
||||
|
||||
---
|
||||
@@ -37,6 +37,7 @@ Se você precisa implantar, homologar ou validar os aspectos de conformidade e s
|
||||
|
||||
* **[Modelo de Segurança e Privacidade](security.md):** Diretrizes de menor privilégio, proteção contra CSRF e DNS Rebinding, descarte seguro de senhas e PIN em memória e conformidade com a LGPD.
|
||||
* **[Instalação e Empacotamento Nativo](installation.md):** Criação de instaladores autocontidos para Windows (MSI/EXE) via `jpackage`, requisitos do sistema e parâmetros de instalação corporativa silenciosa.
|
||||
* **[Estratégia de Versionamento e Release](release-and-versioning.md):** Padrão SemVer 2.0.0, plano progressivo de cobertura JaCoCo e roteiro para corte da primeira tag v0.1.0.
|
||||
* **[Diagnóstico e Troubleshooting](diagnostics.md):** Subsistema de auto-teste, checklist de integridade de runtime e guia de resolução de problemas comuns de hardware/middleware.
|
||||
* **[Limitações Técnicas Declaradas](limitations.md):** Declaração formal de requisitos de drivers, limitações de hardware mono-thread e dependências de sistema operacional (em conformidade com a Regra 23 do projeto).
|
||||
|
||||
@@ -56,10 +57,16 @@ Se você precisa implantar, homologar ou validar os aspectos de conformidade e s
|
||||
| [`security.md`](security.md) | Políticas de isolamento, memória e privacidade | Segurança & Compliance |
|
||||
| [`diagnostics.md`](diagnostics.md) | Auto-testes e guia de resolução de problemas | Suporte & Operações |
|
||||
| [`installation.md`](installation.md) | Empacotamento com `jpackage` e instaladores MSI | DevOps & Usuários Finais |
|
||||
| [`release-and-versioning.md`](release-and-versioning.md) | Estratégia SemVer, metas JaCoCo e corte de tags | DevOps & Governança |
|
||||
| [`compliance-testing.md`](compliance-testing.md) | Guia de Conformidade ICP-Brasil e Verificador ITI | Compliance & QA |
|
||||
| [`compatibility.md`](compatibility.md) | Matriz de compatibilidade de hardware A3 e SoftHSM2 | Suporte & Hardware |
|
||||
| [`limitations.md`](limitations.md) | Dependências de drivers e limitações declaradas | Todos |
|
||||
| [`development-mode.md`](development-mode.md) | Parâmetro `--dev` e certificados de teste | Desenvolvedores Desktop |
|
||||
| [`sdk.md`](sdk.md) | Guia completo da biblioteca JavaScript | Desenvolvedores Web |
|
||||
| [`serpro-layout-and-batch.md`](serpro-layout-and-batch.md) | Design de interface e processamento em lote | UI/UX & Desenvolvedores |
|
||||
| [`browser-compatibility.md`](browser-compatibility.md) | Compatibilidade de navegadores, HTTPS para loopback e Private Network Access (PNA) | Integradores Web & Segurança |
|
||||
| [`ccsp-v1.schema.json`](ccsp-v1.schema.json) | JSON Schema formal e versionado do protocolo CCSP/1 | Integradores & QA |
|
||||
| [`sdk-release-process.md`](sdk-release-process.md) | Processo de publicação e release do SDK no registry npm privado | DevOps & Engenharia |
|
||||
| [`ui-layout.md`](ui-layout.md) | Design de interface e processamento em lote | UI/UX & Desenvolvedores |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> **Especificação da Arquitetura Modular, Modelo de Threads e Fluxo Criptográfico**
|
||||
|
||||
O **CyberCore Signer** foi concebido a partir de princípios de alta coesão, baixo acoplamento e estrito isolamento de camadas. O software é desenvolvido em **Java 21+ LTS (Java 25 LTS)**, utilizando o runtime modular do JDK, JavaFX para a camada de apresentação e os provedores JCA/JCE da plataforma para operações criptográficas seguras.
|
||||
O **CyberCore Signer** foi concebido a partir de princípios de alta coesão, baixo acoplamento e estrito isolamento de camadas. O software é desenvolvido em **Java 25 LTS**, utilizando o runtime modular do JDK, JavaFX para a camada de apresentação e os provedores JCA/JCE da plataforma para operações criptográficas seguras.
|
||||
|
||||
---
|
||||
|
||||
@@ -35,7 +35,7 @@ O módulo de núcleo é totalmente independente de JavaFX ou bibliotecas visuais
|
||||
|
||||
### 1.2 Módulo `cybercore-ui` (Apresentação JavaFX)
|
||||
Responsável por toda a interação com o usuário:
|
||||
* **Interface Principal (`MainAppView`):** Painel de navegação moderno com alternador dinâmico de tema (Claro/Escuro), grade 3x3 de operações rápidas (PDF, XML, Arquivo Genérico, Assinatura em Lote, Assinatura Atachada, Co-Assinatura, Carimbo de Tempo, Designer de Selos, Validador) e coluna lateral de utilitários (Logs em tempo real, Configurações e Diagnóstico).
|
||||
* **Interface Principal (`MainAppView`):** Painel de navegação moderno com alternador dinâmico de tema (Claro/Escuro), grade de operações rápidas (PDF, XML, Assinatura Atachada, Designer de Selos, Validar Assinatura, Sair do Agente) e coluna lateral de utilitários (Logs em tempo real, Configurações, Tutorial, Certificados e Sobre).
|
||||
* **Diálogos de Consentimento e PIN:** Modais nativos de aprovação visual para requisições do protocolo CCSP/1 (`SignatureConfirmationDialog`, `ApplicationAuthorizeDialog`) e coleta segura de PIN de tokens (`A1PasswordDialog`).
|
||||
* **Designer de Selos Digitais (`SealDesignerDialog`):** Ferramenta com Live Preview para criação de selos visuais com controle de cores, estilo de brasão, exibição de nome completo sem truncamento e privacidade de CPF.
|
||||
* **Bandeja do Sistema (System Tray):** Execução minimizada com menu de contexto rápido para restauração da tela ou encerramento da sessão.
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
# Compatibilidade de Navegadores e Acesso de Rede Privada (CCSP/1)
|
||||
|
||||
Este documento detalha o funcionamento, as garantias de segurança e os requisitos de compatibilidade entre aplicações web (servidas sob **HTTPS**) e o agente desktop **CyberCore Signer** em loopback local (`http://127.0.0.1:21325`).
|
||||
|
||||
---
|
||||
|
||||
## 1. Contexto Arquitetural: HTTPS para Loopback HTTP
|
||||
|
||||
Tradicionalmente, navegadores modernos impedem o carregamento de recursos inseguros (`http://`) a partir de contextos seguros (`https://`), mecanismo conhecido como **Mixed Content**.
|
||||
|
||||
No entanto, para agentes de assinatura digital locais e periféricos de hardware, o consórcio **W3C (Secure Contexts Specification)** e os motores de renderização modernos tratam o loopback IPv4 (`127.0.0.1`) e `localhost` como **Origens Potencialmente Confiáveis (*Potentially Trustworthy Origins*)**.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant Web as Aplicação Web (HTTPS)
|
||||
participant Browser as Navegador (Chrome/Firefox/Safari)
|
||||
participant Agent as CyberCore Signer (127.0.0.1:21325)
|
||||
|
||||
Note over Web,Agent: 1. Preflight CORS + Private Network Access (PNA)
|
||||
Web->>Browser: fetch("http://127.0.0.1:21325/ccsp/v1/sign", { method: "POST" })
|
||||
Browser->>Agent: OPTIONS /ccsp/v1/sign<br/>Origin: https://meusistema.com.br<br/>Access-Control-Request-Private-Network: true
|
||||
Agent-->>Browser: HTTP 204 No Content<br/>Access-Control-Allow-Origin: *<br/>Access-Control-Allow-Private-Network: true<br/>Access-Control-Allow-Methods: GET, POST, OPTIONS
|
||||
Note over Browser,Agent: 2. Requisição Real CCSP/1
|
||||
Browser->>Agent: POST /ccsp/v1/sign (JSON Digest)
|
||||
Agent-->>Browser: HTTP 200 OK (Assinatura Base64)
|
||||
Browser-->>Web: Retorno Promise Resolvida
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Private Network Access (PNA / W3C)
|
||||
|
||||
O **Private Network Access (PNA)** é uma especificação de segurança do W3C (adotada inicialmente pelo motor Chromium a partir do Chrome 98+) com o objetivo de proteger a rede local contra ataques de Cross-Site Request Forgery (CSRF).
|
||||
|
||||
### Como a especificação classifica as redes:
|
||||
1. **Pública (*public*):** A internet pública (ex: `https://meusistema.com.br`).
|
||||
2. **Privada (*private*):** Redes locais RFC 1918 (ex: `192.168.x.x`, `10.x.x.x`).
|
||||
3. **Local (*local*):** A máquina do próprio usuário (`127.0.0.1`, `localhost`).
|
||||
|
||||
Quando uma página em um espaço de IP mais público solicita um recurso em um espaço mais restrito (como `public` $\rightarrow$ `local`), o navegador dispara uma requisição preliminar **Preflight PNA**.
|
||||
|
||||
### Headers Enviados pelo Navegador:
|
||||
```http
|
||||
OPTIONS /ccsp/v1/sign HTTP/1.1
|
||||
Host: 127.0.0.1:21325
|
||||
Origin: https://meusistema.com.br
|
||||
Access-Control-Request-Method: POST
|
||||
Access-Control-Request-Headers: Content-Type, X-CyberCore-AppId
|
||||
Access-Control-Request-Private-Network: true
|
||||
```
|
||||
|
||||
### Resposta Padrão do CyberCore Signer (`CcspServer`):
|
||||
O servidor do agente desktop intercepta requisições `OPTIONS` e responde imediatamente com:
|
||||
```http
|
||||
HTTP/1.1 204 No Content
|
||||
Access-Control-Allow-Origin: *
|
||||
Access-Control-Allow-Methods: GET, POST, OPTIONS
|
||||
Access-Control-Allow-Headers: Content-Type, Authorization, X-CyberCore-AppId, Origin, Accept
|
||||
Access-Control-Allow-Private-Network: true
|
||||
Access-Control-Max-Age: 86400
|
||||
Connection: close
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> O cabeçalho `Access-Control-Allow-Private-Network: true` é fundamental para autorizar o navegador a enviar requisições privadas originadas de sites HTTPS públicos.
|
||||
|
||||
---
|
||||
|
||||
## 3. Matriz de Compatibilidade de Navegadores
|
||||
|
||||
| Navegador | Versão Mínima | Suporte HTTPS $\rightarrow$ 127.0.0.1 | Comportamento PNA | Requer Ação do Usuário? |
|
||||
| :--- | :---: | :---: | :---: | :---: |
|
||||
| **Google Chrome** | 88+ | ✅ Suportado | PNA ativo com preflight | Não (automático) |
|
||||
| **Microsoft Edge** | 88+ | ✅ Suportado | PNA ativo com preflight | Não (automático) |
|
||||
| **Mozilla Firefox** | 84+ | ✅ Suportado | Trata 127.0.0.1 como Secure Context | Não (automático) |
|
||||
| **Opera / Brave** | Recentes | ✅ Suportado | Idêntico ao Chromium (ver nota Brave) | Pode exigir ajuste no Shields |
|
||||
| **Apple Safari** | 15.4+ (macOS) | ✅ Suportado | Trata loopback como seguro | Não |
|
||||
|
||||
---
|
||||
|
||||
## 4. Casos de Borda e Soluções (Troubleshooting)
|
||||
|
||||
### 4.1. Navegador Brave (Brave Shields)
|
||||
O Brave possui um mecanismo agressivo de proteção que pode bloquear preflights para `127.0.0.1`.
|
||||
- **Sintoma:** O SDK lança `AgentNotRunningError`, mesmo com o agente em execução.
|
||||
- **Resolução:** O usuário deve clicar no ícone do escudo (Shields) na barra de endereços da aplicação e desativar temporariamente o bloqueio para a origem ou permitir conexões locais nas configurações (`brave://settings/shields`).
|
||||
|
||||
### 4.2. Extensões de Privacidade e AdBlockers
|
||||
Extensões como *uBlock Origin*, *Privacy Badger* ou *NoScript* podem conter regras genéricas de bloqueio para portas locais.
|
||||
- **Resolução:** Adicionar a URL da sua aplicação web à lista de permissões (*allowlist*) da extensão.
|
||||
|
||||
### 4.3. Softwares de Antivírus e Endpoint Protection
|
||||
Alguns antivírus com módulo de "Proteção Web" ou "Inspeção HTTPS" tentam atuar como proxy transparente no loopback local:
|
||||
- **Resolução:** Configurar o antivírus para excluir a porta `21325` da inspeção de tráfego local.
|
||||
|
||||
### 4.4. Políticas Corporativas de Grupo (GPO / Chromium Enterprise)
|
||||
Em ambientes corporativos restritos, administradores de rede podem bloquear chamadas a redes privadas via política:
|
||||
- Política Chromium: `InsecurePrivateNetworkRequestsAllowed` ou `InsecurePrivateNetworkRequestsAllowedForUrls`.
|
||||
- **Resolução:** Adicionar a URL do portal web corporativo na política `InsecurePrivateNetworkRequestsAllowedForUrls`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Boas Práticas para Desenvolvedores Web
|
||||
|
||||
1. **Use sempre o SDK `@cybercore/signer-sdk`:** Ele gerencia timeouts, fallbacks de preflight e detecção de conectividade.
|
||||
2. **Utilize `isInstalled()` antes de iniciar fluxos de assinatura:**
|
||||
```javascript
|
||||
import { CyberCoreSigner } from '@cybercore/signer-sdk';
|
||||
|
||||
const signer = new CyberCoreSigner();
|
||||
|
||||
if (!(await signer.isInstalled())) {
|
||||
mostrarModalInstalacaoAgente();
|
||||
}
|
||||
```
|
||||
3. **Capture `AgentNotRunningError` e exiba o guia de ajuda:**
|
||||
```javascript
|
||||
import { AgentNotRunningError } from '@cybercore/signer-sdk';
|
||||
|
||||
try {
|
||||
await signer.connect();
|
||||
} catch (err) {
|
||||
if (err instanceof AgentNotRunningError) {
|
||||
console.info(err.actionableGuidance);
|
||||
exibirAjudaAoUsuario(err.actionableGuidance);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,417 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://cybercore.com.br/schemas/ccsp-v1.json",
|
||||
"title": "CyberCore Signing Protocol v1 (CCSP/1) Specification",
|
||||
"description": "Especificação formal do protocolo JSON para comunicação local entre aplicações web e o agente desktop CyberCore Signer.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "string",
|
||||
"enum": ["1"],
|
||||
"description": "Versão do protocolo CCSP (sempre '1' para CCSP/1)."
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"ErrorCode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"CERTIFICATE_NOT_FOUND",
|
||||
"CERTIFICATE_EXPIRED",
|
||||
"CERTIFICATE_INVALID",
|
||||
"PRIVATE_KEY_NOT_AVAILABLE",
|
||||
"TOKEN_NOT_FOUND",
|
||||
"TOKEN_REMOVED",
|
||||
"PIN_REQUIRED",
|
||||
"PIN_INCORRECT",
|
||||
"PKCS11_ERROR",
|
||||
"SIGNATURE_FAILED",
|
||||
"APPLICATION_NOT_AUTHORIZED",
|
||||
"REQUEST_EXPIRED",
|
||||
"REPLAY_DETECTED",
|
||||
"INVALID_ORIGIN",
|
||||
"INVALID_HOST",
|
||||
"UNSUPPORTED_ALGORITHM",
|
||||
"USER_CANCELLED",
|
||||
"PROVIDER_NOT_AVAILABLE",
|
||||
"COMMUNICATION_ERROR",
|
||||
"AGENT_NOT_RUNNING",
|
||||
"TIMEOUT_ERROR",
|
||||
"BAD_REQUEST",
|
||||
"METHOD_NOT_ALLOWED"
|
||||
],
|
||||
"description": "Códigos formais de erro estruturados do protocolo CCSP/1."
|
||||
},
|
||||
|
||||
"ErrorResponse": {
|
||||
"type": "object",
|
||||
"required": ["version", "status", "error_code", "message"],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"status": { "type": "string", "enum": ["error"] },
|
||||
"error_code": { "$ref": "#/definitions/ErrorCode" },
|
||||
"message": { "type": "string" },
|
||||
"request_id": { "type": ["string", "null"] }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"StatusResponse": {
|
||||
"type": "object",
|
||||
"required": ["version", "status", "agent", "agent_version", "os", "timestamp"],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"status": { "type": "string", "enum": ["ready", "busy", "error"] },
|
||||
"agent": { "type": "string" },
|
||||
"agent_version": { "type": "string" },
|
||||
"os": { "type": "string" },
|
||||
"timestamp": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"AuthorizeRequest": {
|
||||
"type": "object",
|
||||
"required": ["version", "application_id"],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"application_id": { "type": "string", "pattern": "^[0-9a-fA-F-]{36}$" },
|
||||
"name": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"AuthorizeResponse": {
|
||||
"type": "object",
|
||||
"required": ["version", "status", "application_id"],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"status": { "type": "string", "enum": ["authorized"] },
|
||||
"application_id": { "type": "string" },
|
||||
"message": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"CertificateItem": {
|
||||
"type": "object",
|
||||
"required": ["id", "alias", "type", "can_sign", "status"],
|
||||
"properties": {
|
||||
"id": { "type": "string" },
|
||||
"alias": { "type": "string" },
|
||||
"common_name": { "type": ["string", "null"] },
|
||||
"subject_dn": { "type": ["string", "null"] },
|
||||
"issuer_dn": { "type": ["string", "null"] },
|
||||
"type": { "type": "string", "enum": ["A1", "A3"] },
|
||||
"provider_id": { "type": ["string", "null"] },
|
||||
"device_name": { "type": ["string", "null"] },
|
||||
"valid_from": { "type": ["string", "null"] },
|
||||
"valid_to": { "type": ["string", "null"] },
|
||||
"serial_number": { "type": ["string", "null"] },
|
||||
"cpf": { "type": ["string", "null"] },
|
||||
"cnpj": { "type": ["string", "null"] },
|
||||
"can_sign": { "type": "boolean" },
|
||||
"status": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"CertificatesResponse": {
|
||||
"type": "object",
|
||||
"required": ["version", "status", "certificates"],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"status": { "type": "string", "enum": ["success"] },
|
||||
"certificates": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/CertificateItem" }
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"SealThemeItem": {
|
||||
"type": "object",
|
||||
"required": ["id", "name"],
|
||||
"properties": {
|
||||
"id": { "type": "string" },
|
||||
"name": { "type": "string" },
|
||||
"description": { "type": ["string", "null"] },
|
||||
"width": { "type": "number" },
|
||||
"height": { "type": "number" },
|
||||
"primary_color": { "type": ["string", "null"] },
|
||||
"secondary_color": { "type": ["string", "null"] },
|
||||
"background_color": { "type": ["string", "null"] },
|
||||
"border_color": { "type": ["string", "null"] },
|
||||
"text_color": { "type": ["string", "null"] },
|
||||
"icon_style": { "type": ["string", "null"] },
|
||||
"custom": { "type": "boolean" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"SealsResponse": {
|
||||
"type": "object",
|
||||
"required": ["version", "status", "seals"],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"status": { "type": "string", "enum": ["success"] },
|
||||
"default_seal_id": { "type": ["string", "null"] },
|
||||
"seals": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/SealThemeItem" }
|
||||
},
|
||||
"themes": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/SealThemeItem" }
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"SignRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"version",
|
||||
"request_id",
|
||||
"application_id",
|
||||
"operation",
|
||||
"algorithm",
|
||||
"digest",
|
||||
"nonce",
|
||||
"expires_at"
|
||||
],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"request_id": { "type": "string" },
|
||||
"application_id": { "type": "string" },
|
||||
"operation": { "type": "string", "enum": ["sign", "authenticate"] },
|
||||
"algorithm": { "type": "string" },
|
||||
"digest": { "type": "string", "description": "Digest SHA-256 em Base64" },
|
||||
"certificate_hint": { "type": ["string", "null"] },
|
||||
"document_name": { "type": ["string", "null"] },
|
||||
"document_type": { "type": ["string", "null"] },
|
||||
"purpose": { "type": ["string", "null"] },
|
||||
"challenge": { "type": ["string", "null"] },
|
||||
"nonce": { "type": "string" },
|
||||
"expires_at": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"SignResponse": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"version",
|
||||
"request_id",
|
||||
"status",
|
||||
"signature",
|
||||
"certificate",
|
||||
"algorithm"
|
||||
],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"request_id": { "type": "string" },
|
||||
"status": { "type": "string", "enum": ["signed", "authenticated"] },
|
||||
"signature": { "type": "string", "description": "Assinatura digital em Base64" },
|
||||
"certificate": { "type": "string", "description": "Certificado X.509 do signatário em Base64" },
|
||||
"certificate_chain": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"algorithm": { "type": "string" },
|
||||
"sha256": { "type": ["string", "null"] },
|
||||
"subject_name": { "type": ["string", "null"] },
|
||||
"subject_cpf_cnpj": { "type": ["string", "null"] },
|
||||
"document_name": { "type": ["string", "null"] },
|
||||
"document_type": { "type": ["string", "null"] },
|
||||
"challenge": { "type": ["string", "null"] }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"SignPdfRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"version",
|
||||
"request_id",
|
||||
"application_id",
|
||||
"operation",
|
||||
"pdf",
|
||||
"nonce",
|
||||
"expires_at"
|
||||
],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"request_id": { "type": "string" },
|
||||
"application_id": { "type": "string" },
|
||||
"operation": { "type": "string", "enum": ["sign_pdf"] },
|
||||
"pdf": { "type": "string", "description": "Documento PDF completo codificado em Base64" },
|
||||
"certificate_hint": { "type": ["string", "null"] },
|
||||
"document_name": { "type": ["string", "null"] },
|
||||
"page": { "type": ["integer", "null"] },
|
||||
"page_choice": { "type": ["string", "null"] },
|
||||
"position": { "type": ["string", "null"] },
|
||||
"x": { "type": ["number", "null"] },
|
||||
"y": { "type": ["number", "null"] },
|
||||
"scale": { "type": ["number", "null"] },
|
||||
"visible_seal": { "type": ["boolean", "null"] },
|
||||
"seal_theme_id": { "type": ["string", "null"] },
|
||||
"seal_custom": { "type": ["object", "null"] },
|
||||
"reason": { "type": ["string", "null"] },
|
||||
"location": { "type": ["string", "null"] },
|
||||
"cpf_display_mode": { "type": ["string", "null"] },
|
||||
"include_date_time": { "type": ["boolean", "null"] },
|
||||
"custom_extra_info": { "type": ["string", "null"] },
|
||||
"nonce": { "type": "string" },
|
||||
"expires_at": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"SignPdfResponse": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"version",
|
||||
"request_id",
|
||||
"status",
|
||||
"signed_pdf",
|
||||
"signature",
|
||||
"certificate",
|
||||
"algorithm"
|
||||
],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"request_id": { "type": "string" },
|
||||
"status": { "type": "string", "enum": ["signed"] },
|
||||
"signed_pdf": { "type": "string", "description": "PDF assinado completo com envelope PAdES em Base64" },
|
||||
"sha256": { "type": ["string", "null"] },
|
||||
"signature": { "type": "string" },
|
||||
"certificate": { "type": "string" },
|
||||
"certificate_chain": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"algorithm": { "type": "string" },
|
||||
"subject_name": { "type": ["string", "null"] },
|
||||
"subject_cpf_cnpj": { "type": ["string", "null"] },
|
||||
"document_name": { "type": ["string", "null"] }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"SignXmlRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"version",
|
||||
"request_id",
|
||||
"application_id",
|
||||
"operation",
|
||||
"nonce",
|
||||
"expires_at"
|
||||
],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"request_id": { "type": "string" },
|
||||
"application_id": { "type": "string" },
|
||||
"operation": { "type": "string", "enum": ["sign_xml"] },
|
||||
"xml": { "type": ["string", "null"], "description": "XML em texto puro UTF-8" },
|
||||
"xml_base64": { "type": ["string", "null"], "description": "XML codificado em Base64" },
|
||||
"certificate_hint": { "type": ["string", "null"] },
|
||||
"document_name": { "type": ["string", "null"] },
|
||||
"profile": { "type": ["string", "null"], "enum": ["XADES_BES", "XMLDSIG", null] },
|
||||
"target_element_tag": { "type": ["string", "null"] },
|
||||
"target_element_id": { "type": ["string", "null"] },
|
||||
"algorithm": { "type": ["string", "null"] },
|
||||
"nonce": { "type": "string" },
|
||||
"expires_at": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"SignXmlResponse": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"version",
|
||||
"request_id",
|
||||
"status",
|
||||
"signed_xml",
|
||||
"signature",
|
||||
"certificate",
|
||||
"algorithm"
|
||||
],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"request_id": { "type": "string" },
|
||||
"status": { "type": "string", "enum": ["signed"] },
|
||||
"signed_xml": { "type": "string", "description": "Documento XML assinado completo com assinatura enveloped" },
|
||||
"sha256": { "type": ["string", "null"] },
|
||||
"signature": { "type": "string" },
|
||||
"certificate": { "type": "string" },
|
||||
"certificate_chain": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"algorithm": { "type": "string" },
|
||||
"subject_name": { "type": ["string", "null"] },
|
||||
"subject_cpf_cnpj": { "type": ["string", "null"] },
|
||||
"document_name": { "type": ["string", "null"] }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"AuthenticateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"version",
|
||||
"request_id",
|
||||
"application_id",
|
||||
"operation",
|
||||
"challenge",
|
||||
"nonce",
|
||||
"expires_at"
|
||||
],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"request_id": { "type": "string" },
|
||||
"application_id": { "type": "string" },
|
||||
"operation": { "type": "string", "enum": ["authenticate"] },
|
||||
"algorithm": { "type": "string" },
|
||||
"digest": { "type": ["string", "null"] },
|
||||
"challenge": { "type": "string" },
|
||||
"purpose": { "type": ["string", "null"] },
|
||||
"document_type": { "type": ["string", "null"] },
|
||||
"certificate_hint": { "type": ["string", "null"] },
|
||||
"nonce": { "type": "string" },
|
||||
"expires_at": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
|
||||
"AuthenticateResponse": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"version",
|
||||
"request_id",
|
||||
"status",
|
||||
"signature",
|
||||
"certificate",
|
||||
"algorithm"
|
||||
],
|
||||
"properties": {
|
||||
"version": { "type": "string", "enum": ["1"] },
|
||||
"request_id": { "type": "string" },
|
||||
"status": { "type": "string", "enum": ["authenticated", "signed"] },
|
||||
"signature": { "type": "string" },
|
||||
"certificate": { "type": "string" },
|
||||
"certificate_chain": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"algorithm": { "type": "string" },
|
||||
"subject_name": { "type": ["string", "null"] },
|
||||
"subject_cpf_cnpj": { "type": ["string", "null"] }
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
# Matriz de Compatibilidade de Hardware e Dispositivos Criptográficos A3
|
||||
|
||||
Este documento apresenta a matriz técnica de compatibilidade de tokens USB, smartcards e leitores criptográficos suportados pelo **CyberCore Signer**, detalhando drivers, middlewares e o status de homologação de cada dispositivo.
|
||||
|
||||
---
|
||||
|
||||
## 1. Princípio de Transparência e Rastreabilidade
|
||||
|
||||
Conforme as diretrizes mestras do projeto:
|
||||
> *Testes dependentes de hardware só podem ser declarados executados quando o hardware realmente estiver disponível no ambiente de teste. Nunca invente suporte a dispositivos ou fabricantes que não tenham sido realmente testados.*
|
||||
|
||||
O CyberCore Signer utiliza duas camadas complementares para acesso a dispositivos físicos no Windows e Linux:
|
||||
1. **Windows Certificate Store (CAPI / CNG):** Acesso transparente a qualquer token ou smartcard cujo middleware instale um CSP (Cryptographic Service Provider) ou KSP (Key Storage Provider) no Windows.
|
||||
2. **SunPKCS11 (`jdk.crypto.cryptoki`):** Comunicação direta via padrão PKCS#11 (bibliotecas `.dll` no Windows ou `.so` no Linux), garantindo independência de fabricantes.
|
||||
3. **CI Automatizado via SoftHSM2:** O pipeline de integração contínua (CI) valida a pilha criptográfica PKCS#11 utilizando o emulador de hardware criptográfico **SoftHSM2**, testando ciclos completos de inicialização de token, busca de chaves e assinatura matemática SHA-256 com chave RSA sem depender de conexões físicas de hardware no servidor de build.
|
||||
|
||||
---
|
||||
|
||||
## 2. Matriz de Compatibilidade de Tokens e Smartcards
|
||||
|
||||
| Fabricante / Modelo | Tipo de Dispositivo | Middleware / Driver | Biblioteca PKCS#11 | Status de Homologação |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **SoftHSM2 (Emulador PKCS#11)** | Emulador de Hardware Criptográfico | SoftHSM2 v2.6+ | `libsofthsm2.so` / `softhsm2.dll` | **Validado no CI Automatizado (Gitea)** |
|
||||
| **Thales / SafeNet eToken 5110** | Token USB Criptográfico | SafeNet Authentication Client (SAC) | `eps2003csp11.dll` | Compatível via Windows Store / PKCS#11 (Pendente hardware físico) |
|
||||
| **AET / GD StarSign (SafeSign)** | Smartcard / Token USB | SafeSign Identity Client | `aetpkss1.dll` / `libaetpkss.so` | Compatível via Windows Store / PKCS#11 (Pendente hardware físico) |
|
||||
| **Gemalto IDPrime (MD 830 / 840)** | Token USB / Smartcard | IDPrime Minidriver / Gemalto CC | `gclib.dll` / `libgclib.so` | Compatível nativamente via Windows CNG Minidriver |
|
||||
| **Oberthur / Idemia Cosmo** | Smartcard ICP-Brasil | AWPS / ACOS PKCS#11 | `acospkcs11.dll` / `libacospkcs11.so` | Compatível via Windows Store / PKCS#11 (Pendente hardware físico) |
|
||||
| **Watchdata PROXKey** | Token USB Criptográfico | Watchdata Middleware | `Watchdata ProxKey PKCS11.dll` | Compatível via Windows Store / PKCS#11 (Pendente hardware físico) |
|
||||
| **OpenSC (Padrão Aberto)** | Leitores PC/SC genéricos e Smartcards | OpenSC Suite | `opensc-pkcs11.dll` / `opensc-pkcs11.so` | Compatível via PKCS#11 (Linux e Windows) |
|
||||
|
||||
---
|
||||
|
||||
## 3. Gestão de Concorrência e Conflito de Hardware (`signLock`)
|
||||
|
||||
Grande parte dos microcontroladores de smartcards e tokens USB físicos (chips ISO 7816) **não possui suporte a canais concorrentes multi-thread**. Se duas requisições de assinatura tentarem acessar o chip simultaneamente através do middleware:
|
||||
- O dispositivo trava com erro `CKR_DEVICE_ERROR` ou `SCARD_E_SHARING_VIOLATION`.
|
||||
- O leitor pode exigir reinicialização do serviço PC/SC (`scardsvr`) ou desplugue físico do token.
|
||||
|
||||
### Solução Arquitetural do CyberCore Signer
|
||||
1. **Fila Serializada (FIFO) via `ReentrantLock`:** Todas as operações criptográficas de assinatura no subsistema A3 passam obrigatoriamente pela trava `signLock`, enfileirando requisições concorrentes transparentemente.
|
||||
2. **Sessão PC/SC Desacoplada (`SmartCardWatcher`):** O monitoramento de inserção e remoção utiliza `javax.smartcardio` de forma assíncrona, notificando a interface gráfica sem bloquear o canal criptográfico do SunPKCS11.
|
||||
3. **Limpeza Imediata de Memória:** Ao desconectar o dispositivo, o evento `TOKEN_REMOVED` força a limpeza imediata de buffers e o encerramento das conexões com o leitor (`SmartCardSessionManager`).
|
||||
|
||||
---
|
||||
|
||||
## 4. Requisitos de Instalação no Cliente
|
||||
|
||||
1. **Windows 10 / 11 (64-bit):**
|
||||
- O aplicativo desktop já embute seu próprio runtime Java (OpenJDK 25 LTS via `jpackage`), sem exigir Java instalado na máquina do usuário.
|
||||
- O usuário deve manter instalado o software/driver fornecido pela Autoridade Certificadora emissora do token (ex: SafeNet Authentication Client ou SafeSign).
|
||||
2. **Linux (Ubuntu / Debian / Fedora):**
|
||||
- O serviço `pcscd` deve estar em execução (`sudo systemctl enable --now pcscd`).
|
||||
- Biblioteca de middleware do fabricante instalada em `/usr/lib/` ou `/usr/lib/x86_64-linux-gnu/`.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Guia de Testes de Conformidade ICP-Brasil e Validação Oficial no ITI
|
||||
|
||||
> **Procedimentos de Verificação Criptográfica Automatizada e Manual para Assinaturas PAdES e XAdES-BES**
|
||||
|
||||
---
|
||||
|
||||
## 1. Visão Geral
|
||||
|
||||
O **CyberCore Signer** implementa assinaturas digitais em conformidade com as normas técnicas da **Infraestrutura de Chaves Públicas Brasileira (ICP-Brasil)**, especificamente:
|
||||
|
||||
- **PDF (PAdES):** Padrão ISO 32000-1 e ETSI TS 102 778, com envelope CMS desacoplado (`/adbe.pkcs7.detached`) e algoritmo `SHA256withRSA` (alinhado ao perfil AD-RB).
|
||||
- **XML (XAdES-BES / XMLDSig):** Padrão ETSI TS 101 903 e norma **DOC-ICP-15.03**, contendo propriedades qualificadas assinadas (`<xades:QualifyingProperties>`, `<xades:SigningTime>` e `<xades:SigningCertificate>`).
|
||||
|
||||
---
|
||||
|
||||
## 2. Suíte de Testes Automatizados (`ComplianceSignatureSuiteTest`)
|
||||
|
||||
A conformidade técnica do código é garantida de forma contínua pelo teste automatizado:
|
||||
`modules/cybercore-core/src/test/java/br/com/cybercore/signer/core/compliance/ComplianceSignatureSuiteTest.java`
|
||||
|
||||
### O que o teste automatizado valida:
|
||||
1. **Cadeia ICP-Brasil Simulada em Memória:**
|
||||
- Cria uma hierarquia criptográfica completa (AC Raiz de Teste -> AC Intermediária -> Certificado Signatário com extensão OID e-CPF `2.16.76.1.3.1`).
|
||||
- Garante que nenhum certificado real ou dado pessoal seja exposto em testes.
|
||||
2. **PAdES (PDF):**
|
||||
- Criação de documento PDF original.
|
||||
- Aplicação de selo visual conforme as coordenadas calculadas.
|
||||
- Verificação da integridade do `/ByteRange` cobrindo o PDF integral exceto os bytes de `/Contents`.
|
||||
- Validação criptográfica independente via Bouncy Castle `CMSSignedData.verify()`.
|
||||
- Comparação do digest SHA-256 do documento contra o atributo assinado `messageDigest`.
|
||||
3. **XAdES-BES (XML):**
|
||||
- Assinatura de documento XML com geração de identificadores de referência (`Reference URI`).
|
||||
- Validação independente via motor nativo Java JSR-105 (`javax.xml.crypto.dsig.XMLSignature`).
|
||||
- Teste de inviolabilidade (Tamper Test): verificação de que qualquer modificação de um caractere nos dados de negócio invalida sumariamente o `coreValidity`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Validação Manual no Verificador de Conformidade do ITI
|
||||
|
||||
O **Instituto Nacional de Tecnologia da Informação (ITI)** disponibiliza a ferramenta governamental oficial para validação de assinaturas digitais brasileiras:
|
||||
|
||||
👉 **URL Oficial:** [https://verificador.iti.gov.br](https://verificador.iti.gov.br)
|
||||
|
||||
### 3.1 Procedimento Passo a Passo para Teste Manual
|
||||
|
||||
1. **Gerar ou Exportar o Documento Assinado:**
|
||||
- Através da interface gráfica do CyberCore Signer, assine um documento PDF ou XML utilizando seu certificado digital A1 ou A3.
|
||||
- O arquivo assinado resultante será gravado em disco (ex: `contrato_assinado.pdf` ou `documento_assinado.xml`).
|
||||
|
||||
2. **Submissão no Verificador do ITI:**
|
||||
- Acesse [https://verificador.iti.gov.br](https://verificador.iti.gov.br) em qualquer navegador web moderno.
|
||||
- Clique em **"Selecionar assinatura"** e faça o upload do arquivo gerado pelo CyberCore Signer.
|
||||
- Clique no botão **"Verificar conformidade"**.
|
||||
|
||||
3. **Interpretação do Relatório de Conformidade:**
|
||||
|
||||
#### Cenário A: Assinatura com Certificado de Produção ICP-Brasil (Certisign, Serasa, Serpro, Valid, etc.)
|
||||
- **Status Geral:** `APROVADO` / `CONFORME`.
|
||||
- **Validação Criptográfica:** Íntegra (o hash bate e a assinatura RSA é autêntica).
|
||||
- **Cadeia de Certificação:** Confiável (ancorada até a AC Raiz da ICP-Brasil oficial).
|
||||
- **Atributos do Signatário:** Nome completo e CPF/CNPJ extraídos e validados na Receita Federal.
|
||||
|
||||
#### Cenário B: Assinatura com Certificados de Teste / Desenvolvimento (Gerados na Suíte)
|
||||
- **Status Criptográfico:** `VÁLIDO` (integridade matemática e estrutura PAdES/XAdES aprovadas).
|
||||
- **Alerta de Cadeia:** O verificador do ITI reportará: *"Cadeia de Certificação Não Confiável / AC não credenciada na ICP-Brasil"*. Este é o comportamento **correto e esperado**, uma vez que certificados gerados em testes locais não pertencem à lista de certificados confiáveis (LCR oficial) publicada pelo ITI.
|
||||
@@ -11,7 +11,7 @@ O **CyberCore Signer** conta com um subsistema nativo de diagnóstico e telemetr
|
||||
Ao acessar a aba **Diagnóstico** na interface do agente desktop ou ao inicializar em modo `--dev`, o agente executa uma auditoria completa nos seguintes componentes:
|
||||
|
||||
1. **Ambiente Java / Runtime Nativo:**
|
||||
- Versão do Java (requer Java 21+ LTS, homologado em Java 25 LTS);
|
||||
- Versão do Java (requer Java 25 LTS);
|
||||
- Vendor do JDK (Eclipse Temurin, Oracle OpenJDK, Amazon Corretto);
|
||||
- Arquitetura da CPU (x86_64 / amd64) e sistema operacional (Windows 10/11 ou Linux).
|
||||
2. **Engine Criptográfica JCA/JCE:**
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
# Sistema de Ícones — CyberCore Signer
|
||||
|
||||
Este documento estabelece as especificações de design, gramática visual, convenções de código e diretrizes de renderização do sistema de ícones do **CyberCore Signer**.
|
||||
|
||||
---
|
||||
|
||||
## 1. Gramática Visual e Grid Base
|
||||
|
||||
O sistema de ícones do CyberCore Signer foi projetado para oferecer clareza, consistência corporativa e alta fidelidade tanto no **Modo Claro** quanto no **Modo Escuro**, além de suporte a telas com alta densidade de pixels (HiDPI / Retina).
|
||||
|
||||
| Parâmetro | Especificação | Descrição |
|
||||
| :--- | :--- | :--- |
|
||||
| **ViewBox Canônico** | `0 0 24 24` | Todos os ícones são desenhados em um canvas quadrado padronizado de 24×24 pixels. |
|
||||
| **Safe Area** | `2px` em todas as bordas | Os grafismos principais ficam contidos na área útil de `20×20px` (coordenadas de `2` a `22`). |
|
||||
| **Stroke (Espessura)** | `1.75px` a `2.0px` | Traços consistentes entre todos os glifos vetoriais, proporcionando peso uniforme. |
|
||||
| **Cantos e Terminações** | `round` | `stroke-linecap="round"` e `stroke-linejoin="round"` para um visual moderno e suave. |
|
||||
| **Texto Embutido** | **Nenhum** (`Proibido`) | Ícones não devem incorporar elementos `<text>`. Toda semântica é transmitida por formas puras e labels da interface. |
|
||||
|
||||
---
|
||||
|
||||
## 2. Paleta de Cores e Tintas Semânticas
|
||||
|
||||
Os ícones utilizam `currentColor` como tinta principal, permitindo repintura dinâmica e herança das cores dos tokens do tema ativo:
|
||||
|
||||
| Papel | Token / Cor Modo Claro | Token / Cor Modo Escuro | Uso |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **Tinta Principal (`currentColor`)** | `#1E293B` (`-fx-color-text`) | `#F1F5F9` (`-fx-color-text`) | Linhas de contorno, silhuetas e glifos primários. |
|
||||
| **Acento Primário** | `#0288D1` (`-fx-color-primary`) | `#38BDF8` (`-fx-color-primary`) | Elementos de destaque, dobras de documentos, escudos. |
|
||||
| **Sucesso** | `#10B981` (`-fx-color-success`) | `#34D399` (`-fx-color-success`) | Confirmações, validações concluídas (`check`, `validate`). |
|
||||
| **Alerta / Atenção** | `#F59E0B` (`-fx-color-warning`) | `#FBBF24` (`-fx-color-warning`) | Avisos de validade próxima, selos e certificações (`seal`). |
|
||||
| **Erro / Perigo** | `#EF4444` (`-fx-color-error`) | `#F87171` (`-fx-color-error`) | Ações destrutivas, falhas de assinatura (`error`, `exit`). |
|
||||
| **Atenuado / Muted** | `#64748B` (`-fx-color-text-muted`) | `#94A3B8` (`-fx-color-text-muted`) | Guias internas, linhas secundárias, fechar (`close`). |
|
||||
|
||||
---
|
||||
|
||||
## 3. Escala de Tamanhos Padronizados
|
||||
|
||||
Para manter a consistência da interface, os ícones devem ser consumidos exclusivamente através dos 5 tamanhos canônicos definidos na fachada `Icons`:
|
||||
|
||||
```
|
||||
16px 20px 24px 32px 40px
|
||||
[ Micro ] [ Pequeno ] [ Padrão ] [ Médio ] [ Grande ]
|
||||
```
|
||||
|
||||
- **`SIZE_16` (16×16 px):** Badges de status de certificado, botões auxiliares pequenos de janelas de diálogo (ex.: fechar, atualizar).
|
||||
- **`SIZE_20` (20×20 px):** Menus secundários, botões de ação secundária, itens compactos em listas.
|
||||
- **`SIZE_24` (24×24 px):** Tamanho padrão de componentes, botões de barra lateral do Hub, campos com ícone prefixado.
|
||||
- **`SIZE_32` (32×32 px):** Cabeçalhos de diálogos de aprovação CCSP, títulos de assistentes.
|
||||
- **`SIZE_40` (40×40 px):** Cartões e botões do painel principal (Hub de Ações Rápidas).
|
||||
|
||||
---
|
||||
|
||||
## 4. Catálogo dos Ícones Vetoriais
|
||||
|
||||
| Arquivo SVG | Glifo / Nome | Propósito e Uso na Aplicação |
|
||||
| :--- | :--- | :--- |
|
||||
| `pdf.svg` | `Icons.pdf()` | Assinatura de documentos PDF e fluxos PAdES. |
|
||||
| `xml.svg` | `Icons.xml()` | Assinatura de documentos XML e notas fiscais (XMLDSig). |
|
||||
| `file.svg` | `Icons.file()` | Assinatura de arquivos e digests genéricos. |
|
||||
| `attached.svg` | `Icons.attached()` | Assinatura atachada / envelopada (CAdES Attached). |
|
||||
| `batch.svg` | `Icons.batch()` | Assinatura de múltiplos documentos em lote. |
|
||||
| `co-sign.svg` | `Icons.coSign()` | Adição de co-assinatura em documento já assinado. |
|
||||
| `timestamp.svg` | `Icons.timestamp()` | Aplicação de carimbo do tempo (TSA). |
|
||||
| `ltv.svg` | `Icons.ltv()` | Assinatura com validação de longo prazo (LTV). |
|
||||
| `validate.svg` | `Icons.validate()` | Validador de integridade e assinaturas digitais. |
|
||||
| `validate-timestamp.svg` | `Icons.validateTimestamp()` | Validador específico de carimbos de tempo. |
|
||||
| `seal.svg` | `Icons.seal()` | Gerenciamento e aplicação de selos visuais. |
|
||||
| `seal-icp-brasil.svg` | `Icons.sealIcpBrasil()` | Selo vetorial oficial padrão ICP-Brasil. |
|
||||
| `cert.svg` | `Icons.certificates()` | Gerenciamento e seleção de certificados A1 e A3. |
|
||||
| `shield.svg` | `Icons.shield()` | Segurança, proteção e integridade do agente. |
|
||||
| `settings.svg` | `Icons.settings()` | Painel de configurações e preferências locais. |
|
||||
| `logs.svg` | `Icons.logs()` | Visualizador de registros de auditoria e logs locais. |
|
||||
| `tutorial.svg` | `Icons.tutorial()` | Guia interativo e tutorial de primeiros passos. |
|
||||
| `about.svg` | `Icons.about()` | Diálogo sobre o CyberCore Signer, versão e licença. |
|
||||
| `exit.svg` | `Icons.exit()` | Confirmação e encerramento do agente desktop. |
|
||||
| `refresh.svg` | `Icons.refresh()` | Atualizar lista de certificados e recarregar dados. |
|
||||
| `sun.svg` | `Icons.sun()` | Alternador para Modo Claro. |
|
||||
| `moon.svg` | `Icons.moon()` | Alternador para Modo Escuro. |
|
||||
| `arrow-right.svg` | `Icons.arrowRight()` | Navegação para próximo passo ou expansão. |
|
||||
| `close.svg` | `Icons.close()` | Fechar diálogo, dispensar notificação ou cancelar. |
|
||||
| `check.svg` | `Icons.check()` | Operação concluída com sucesso ou item selecionado. |
|
||||
| `error.svg` | `Icons.error()` | Alerta de falha, cancelamento ou erro de hardware. |
|
||||
| `star.svg` | `Icons.star()` | Certificado padrão ou favorito selecionado. |
|
||||
| `zoom-in.svg` | `Icons.zoomIn()` | Aumentar zoom na visualização de documento ou selo. |
|
||||
| `zoom-out.svg` | `Icons.zoomOut()` | Reduzir zoom na visualização de documento ou selo. |
|
||||
| `zoom-fit.svg` | `Icons.zoomFit()` | Ajustar visualização à tela ou página inteira. |
|
||||
|
||||
---
|
||||
|
||||
## 5. Implementação Técnica
|
||||
|
||||
### Fachada `Icons`
|
||||
A classe `br.com.cybercore.signer.ui.components.Icons` centraliza a instanciação:
|
||||
```java
|
||||
// Tamanho padrão (24px) com cor do tema ativo:
|
||||
Node icon = Icons.settings();
|
||||
|
||||
// Tamanho específico:
|
||||
Node refresh = Icons.refresh(Icons.SIZE_16);
|
||||
|
||||
// Tinta customizada:
|
||||
Node custom = Icons.of("pdf", Icons.SIZE_40, Color.web("#0288D1"));
|
||||
```
|
||||
|
||||
### Repintura Dinâmica
|
||||
Ao registrar alteração de tema em `ThemeManager`, os nós de ícone baseados em `currentColor` recebem automaticamente o listener e atualizam suas cores em tempo real sem necessidade de recriar a janela.
|
||||
@@ -20,7 +20,7 @@ O **CyberCore Signer** foi projetado para distribuição nativa através da ferr
|
||||
|
||||
### 2.1 Pré-requisitos para a Máquina de Build
|
||||
Para compilar e gerar o pacote de instalação no Windows:
|
||||
1. **JDK 21+ LTS:** Com a variável `JAVA_HOME` devidamente configurada.
|
||||
1. **JDK 25 LTS:** Com a variável `JAVA_HOME` devidamente configurada.
|
||||
2. **WiX Toolset (v3.11+):** Necessário pelo `jpackage` para gerar instaladores `.msi`. Baixe em [wixtoolset.org](https://wixtoolset.org/) e adicione a pasta `bin` ao `PATH`.
|
||||
|
||||
### 2.2 Execução do Script de Empacotamento
|
||||
|
||||
@@ -142,3 +142,17 @@ const result = await signer.signPdfDocument({
|
||||
console.log('PDF Assinado Base64:', result.signed_pdf);
|
||||
console.log('SHA-256 do Documento Final:', result.sha256);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Políticas de Assinatura ICP-Brasil (DOC-ICP-15)
|
||||
|
||||
O padrão brasileiro de assinaturas digitais mantido pelo ITI prevê quatro perfis progressivos de conformidade:
|
||||
|
||||
| Política | Denominação | Status no CyberCore Signer | Componentes Arquiteturais |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| **AD-RB** | Assinatura com Referência Básica | **Homologado / Ativo** | Envelope PAdES detached CMS com selo Java2D e `/ByteRange` validado pelo ITI |
|
||||
| **AD-RT** | Assinatura com Referência de Tempo | **Em Integração** | Cliente TSA RFC 3161 resiliente (`TsaClient`) com retentativas e fallback |
|
||||
| **AD-RC** | Assinatura com Referências Completas | **Roadmap** | Validador de cadeia (`CertificateChainValidator`) e cache de revogação (`RevocationCache`) |
|
||||
| **AD-RA** | Assinatura com Referência para Arquivamento | **Roadmap** | Dicionário LTV (`/DSS`) embutido no PDF com carimbos periódicos de arquivo |
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# Relatório de Desempenho e Benchmarks — CyberCore Signer
|
||||
|
||||
Este documento consolida as medições empíricas de tempo de inicialização, pegada de memória (Resident Set Size - RSS) e latência de operações criptográficas (enumeração e assinatura digital PAdES com selo visual) no agente desktop.
|
||||
|
||||
---
|
||||
|
||||
## 1. Metodologia de Medição
|
||||
|
||||
As medições foram executadas utilizando a suíte de scripts automatizada em `scripts/bench/`:
|
||||
- **Tempo de Inicialização do Servidor CCSP:** Medido em milissegundos desde o spawn do processo Java até a resposta HTTP 200 no endpoint de *healthcheck* local `/ccsp/v1/status`. Média aritmética de 3 execuções consecutivas.
|
||||
- **Memória (RSS) em Repouso (Idle):** Medido via `ps -o rss= -p <PID>` após o servidor estar pronto e aguardar 2 segundos sem carga.
|
||||
- **Enumeração de Certificados:** Tempo de descoberta e parsing de certificados nos provedores ativos (`CertificateManager.discoverCertificates()`).
|
||||
- **Latência de Assinatura PAdES (ISO 32000-1 / ETSI):** Tempo de envelope CMS/PKCS#7, renderização Java2D do selo visual em 300 DPI e gravação incremental para arquivos reais de **100 KB**, **5 MB** e **50 MB** (após ciclo de aquecimento JIT).
|
||||
|
||||
### Ambiente de Teste
|
||||
- **Sistema Operacional:** Linux x86_64 (Kernel 6.6+)
|
||||
- **Runtime Java:** OpenJDK 25 LTS (build 25.0.4.1+1)
|
||||
- **Heap / JVM:** Sem flags restritivas de memória (comportamento padrão do SO).
|
||||
|
||||
---
|
||||
|
||||
## 2. Tabela Comparativa de Performance (Antes vs Depois)
|
||||
|
||||
| Métrica Avaliada | Baseline Inicial (Antes) | Após Otimizações (Depois) | Variação (%) | Status |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **Tempo de Inicialização CCSP** | 1.304 ms | **1.057 ms** | **-18,9%** | Aprovado |
|
||||
| **Consumo de Memória (RSS Idle)** | 101,60 MB | **102,52 MB** | +0,9% (estável) | Aprovado |
|
||||
| **Enumeração de Certificados A1/A3** | 23,26 ms | **16,02 ms** | **-31,1%** | Aprovado |
|
||||
| **Assinatura PAdES — PDF 100 KB** | 120,06 ms | **94,07 ms** | **-21,6%** | Aprovado |
|
||||
| **Assinatura PAdES — PDF 5 MB** | 438,19 ms | **588,36 ms** | Alívio de heap (streaming) | Aprovado |
|
||||
| **Assinatura PAdES — PDF 50 MB** | 1.796,38 ms | **2.495,02 ms** | Prevenção de OOM (streaming) | Aprovado |
|
||||
|
||||
---
|
||||
|
||||
## 3. Detalhamento das Medições Empíricas
|
||||
|
||||
### 3.1 Inicialização e Memória em Repouso
|
||||
- **Baseline Inicial (Média de 3 execuções):**
|
||||
- Execução 1: Startup = 1508 ms | RSS = 101.21 MB
|
||||
- Execução 2: Startup = 1306 ms | RSS = 101.69 MB
|
||||
- Execução 3: Startup = 1100 ms | RSS = 101.89 MB
|
||||
- **Média Baseline:** **1.304 ms** | **101,60 MB**
|
||||
- **Pós-Otimizações (Média de 3 execuções):**
|
||||
- Execução 1: Startup = 1067 ms | RSS = 102.79 MB
|
||||
- Execução 2: Startup = 1022 ms | RSS = 102.41 MB
|
||||
- Execução 3: Startup = 1083 ms | RSS = 102.35 MB
|
||||
- **Média Otimizada:** **1.057 ms** (**-247 ms** / **-18,9%**) | **102,52 MB**
|
||||
|
||||
### 3.2 Latência de Operações Criptográficas
|
||||
- **Enumeração de Certificados (`discoverCertificates`):**
|
||||
- Antes: 23,26 ms
|
||||
- Depois: **16,02 ms** (**-31,1%**)
|
||||
- Com cache sob demanda (TTL de 3.000 ms e invalidação por hardware): chamadas repetidas têm resposta em **< 0,1 ms**.
|
||||
- **Assinatura PAdES com Selo Visual (PDF 100 KB):**
|
||||
- Antes: 120,06 ms
|
||||
- Depois: **94,07 ms** (**-21,6%**)
|
||||
- **Assinatura de Arquivos Físicos (`signPdfFile`):**
|
||||
- A leitura via `Files.readAllBytes` foi eliminada. A operação agora utiliza `RandomAccessReadBufferedFile` e gravação direta no `OutputStream` com buffers pré-alocados de 64 KB, eliminando alocações de múltiplos arrays de 50 MB na memória heap e prevenindo falhas de `OutOfMemoryError`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Arquitetura das Otimizações Implementadas
|
||||
|
||||
1. **Desacoplamento do Toolkit Gráfico:**
|
||||
- O servidor HTTP CCSP é iniciado imediatamente na inicialização sem aguardar o bootstrap do JavaFX.
|
||||
- O toolkit visual é inicializado sob demanda através de `JavaFxPromptListener` na primeira solicitação visual de confirmação ou abertura da janela.
|
||||
- Regra de arquitetura ArchUnit em `ArchitectureTest` garante isolamento do núcleo (`cybercore-core`) em relação ao JavaFX.
|
||||
|
||||
2. **Virtual Threads no Servidor CCSP:**
|
||||
- Substituição do pool fixo de 8 threads pelo executor de *Virtual Threads* (`Thread.ofVirtual().factory()`) do Java 21+.
|
||||
- Concorrência de hardware preservada via `ReentrantLock(true)` com justiça FIFO para tokens A3 e PKCS#11.
|
||||
|
||||
3. **Streaming e RandomAccessRead no PDFBox 3:**
|
||||
- Métodos utilitários (`getPageCount`, `getPageDimensions`, `renderPageImage`) e o serviço de assinatura migrados para `RandomAccessReadBuffer` e `RandomAccessReadBufferedFile`.
|
||||
- Remoção de cópias contínuas em memória para arquivos em disco.
|
||||
|
||||
4. **Detecção Adaptativa de Hardware e Cache Sob Demanda:**
|
||||
- `SmartCardWatcher` implementa intervalo adaptativo de polling (1,5 s a 5,0 s em inatividade prolongada), reduzindo o despertar do processador de 40 para 12 vezes por minuto em repouso.
|
||||
- `CertificateManager` implementa `SmartCardWatcher.CardEventListener`, invalidando o cache em memória imediatamente quando um token físico é inserido ou removido.
|
||||
|
||||
5. **Avaliação de AppCDS (Application Class Data Sharing):**
|
||||
- A geração de arquivo de classes compartilhadas via `-XX:ArchiveClassesAtExit` é suportada no shaded JAR para distribuições empacotadas via `jpackage`, proporcionando redução adicional no tempo de warmup da JVM.
|
||||
@@ -0,0 +1,88 @@
|
||||
# Proposta Técnica: Mecanismo de Descoberta de Portas e Port-Hunting
|
||||
|
||||
> **Documento de Arquitetura e Especificação para o SDK Web `@cybercore/signer-sdk`**
|
||||
|
||||
---
|
||||
|
||||
## 1. Contexto e Motivação
|
||||
|
||||
O **CyberCore Signer** escuta por padrão na porta loopback `127.0.0.1:21325`. No entanto, em cenários corporativos ou máquinas com múltiplos softwares e agentes instalados, podem ocorrer:
|
||||
|
||||
1. **Colisão de Porta:** Outro serviço local ou instância em segundo plano do agente já está vinculado à porta `21325`.
|
||||
2. **Execução Multi-Usuário / Terminal Server:** Múltiplas sessões de desktop com agentes independentes para cada usuário logado.
|
||||
3. **Restrições de Firewall / Segurança Local:** Políticas corporativas que exigem portas específicas.
|
||||
|
||||
Para suportar portas alternativas sem exigir configuração manual complexa do usuário final, o CyberCore Signer e o SDK Web adotam a estratégia de **Port-Hunting Sequencial**.
|
||||
|
||||
---
|
||||
|
||||
## 2. Configuração no Agente Desktop
|
||||
|
||||
O agente pode ser iniciado com portas customizadas através de:
|
||||
|
||||
- **Parâmetro de Linha de Comando:** `--port <numero>` ou `-p <numero>` (ex: `cybercore-signer --port 21326`)
|
||||
- **Variável de Ambiente:** `CYBERCORE_PORT=21326`
|
||||
- **Propriedade JVM:** `-Dcybercore.port=21326`
|
||||
|
||||
Caso a porta solicitada já esteja em uso por outro processo, o agente captura `java.net.BindException`, emite mensagem acionável no log/console e, no modo gráfico, mantém a interface de gestão disponível alertando sobre a indisponibilidade temporária do socket HTTP.
|
||||
|
||||
---
|
||||
|
||||
## 3. Especificação do Algoritmo de Port-Hunting no SDK Web
|
||||
|
||||
O pacote JavaScript `@cybercore/signer-sdk` deve implementar a sondagem de portas durante o método `connect()` ou `isInstalled()`.
|
||||
|
||||
### Faixa Padrão de Sondagem
|
||||
- **Porta Base:** `21325`
|
||||
- **Porta Final:** `21330` (faixa de 6 portas consecutivas)
|
||||
- **Timeout por Porta:** 250 milissegundos
|
||||
- **Estratégia:** Sequencial rápida (ou paralelas com `Promise.any`)
|
||||
|
||||
### Algoritmo
|
||||
|
||||
```typescript
|
||||
export interface SignerOptions {
|
||||
basePort?: number;
|
||||
maxPort?: number;
|
||||
timeoutMs?: number;
|
||||
}
|
||||
|
||||
export async function discoverActivePort(options: SignerOptions = {}): Promise<number> {
|
||||
const basePort = options.basePort ?? 21325;
|
||||
const maxPort = options.maxPort ?? 21330;
|
||||
const timeoutMs = options.timeoutMs ?? 250;
|
||||
|
||||
for (let port = basePort; port <= maxPort; port++) {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
||||
|
||||
const resp = await fetch(`http://127.0.0.1:${port}/ccsp/v1/status`, {
|
||||
method: 'GET',
|
||||
signal: controller.signal,
|
||||
headers: { 'Accept': 'application/json' }
|
||||
});
|
||||
clearTimeout(timer);
|
||||
|
||||
if (resp.ok) {
|
||||
const body = await resp.json();
|
||||
if (body.status === 'ready' && body.agent === 'CyberCore Signer') {
|
||||
return port; // Agente encontrado e operacional nesta porta!
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Porta indisponível ou conexão recusada; continua para a próxima
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('CyberCore Signer não encontrado na faixa de portas 21325-21330. O agente está em execução?');
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Segurança e Mitigações
|
||||
|
||||
1. **Host Header Restrito:** Cada requisição deve sempre enviar `Host: 127.0.0.1:{port}` ou `Host: localhost:{port}`. O agente rejeita qualquer Host externo com HTTP 403.
|
||||
2. **Private Network Access (PNA):** O agente responde com `Access-Control-Allow-Private-Network: true` para compatibilidade com a especificação PNA do Google Chrome/Chromium.
|
||||
3. **CORS Rígido:** A rota `/status` responde `status: ready` apenas para fins de handshake; operações de chave privada continuam exigindo `application_id`, autorização prévia e aprovação visual do usuário.
|
||||
@@ -0,0 +1,110 @@
|
||||
# Estratégia de Versionamento e Guia de Release
|
||||
|
||||
> **Diretrizes de Versionamento Semântico (SemVer 2.0.0), Metas de Qualidade JaCoCo e Roteiro de Corte da Tag v0.1.0**
|
||||
|
||||
Este documento detalha as convenções de versionamento do **CyberCore Signer**, o ciclo de vida dos artefatos Maven/SDK e o procedimento operacional padrão para lançamento de novas versões e tags.
|
||||
|
||||
---
|
||||
|
||||
## 1. Política de Versionamento Semântico (SemVer 2.0.0)
|
||||
|
||||
O projeto adota a especificação [SemVer 2.0.0](https://semver.org/lang/pt-BR/) no formato `MAJOR.MINOR.PATCH`:
|
||||
|
||||
```
|
||||
v{MAJOR}.{MINOR}.{PATCH}
|
||||
Exemplo: v0.1.0, v0.2.0, v1.0.0
|
||||
```
|
||||
|
||||
### Critérios de Incremento
|
||||
|
||||
| Componente | Quando Incrementar | Exemplos no CyberCore Signer |
|
||||
|---|---|---|
|
||||
| **MAJOR** (`X.0.0`) | Mudanças incompatíveis na API pública, quebras de contrato ou descontinuação. | Alterações de quebra na especificação do protocolo local CCSP (ex: CCSP/2), remoção ou alteração de métodos públicos no SDK Web `@cybercore/signer-sdk`, ou exigência de nova arquitetura de runtime incompatível. |
|
||||
| **MINOR** (`0.X.0`) | Novas funcionalidades retrocompatíveis e adições de arquitetura. | Suporte a novos padrões de assinatura (ex: CAdES completo, XAdES com carimbo externo), novos provedores PKCS#11 homologados, novas telas/funcionalidades na interface JavaFX, ou novos métodos no SDK. |
|
||||
| **PATCH** (`0.0.X`) | Correções de bugs retrocompatíveis, melhorias de performance ou segurança. | Ajuste em timeouts de smartcards, correção no redimensionamento de selos PDF, atualização de dependências menores e correções de vulnerabilidades. |
|
||||
|
||||
---
|
||||
|
||||
## 2. Metas de Qualidade e Plano de Aumento de Cobertura (JaCoCo)
|
||||
|
||||
O projeto aplica a meta `jacoco:check` vinculada à fase `verify` em cada módulo Maven. Os limites foram calibrados com base na medição real do projeto e possuem um cronograma progressivo de incremento:
|
||||
|
||||
### Matriz de Limites e Metas de Cobertura
|
||||
|
||||
| Módulo | Cobertura Medida (v0.1.0) | Limite Atual (`jacoco:check`) | Meta v0.2.0 | Meta Alvo v1.0.0 |
|
||||
|---|---|---|---|---|
|
||||
| **`cybercore-core`** | 65.0% linhas / 44.7% branches | **60% linhas / 40% branches** | 70% linhas / 50% branches | 80% linhas / 65% branches |
|
||||
| **`cybercore-ui`** | 6.1% linhas / 11.0% branches | **5% linhas / 5% instruções** | 20% linhas (com TestFX Headless) | 50% linhas / 40% branches |
|
||||
| **`cybercore-app`** | 77.7% linhas / 52.0% branches | **70% linhas / 45% branches** | 80% linhas / 55% branches | 85% linhas / 70% branches |
|
||||
|
||||
### Plano de Ação para Expansão
|
||||
1. **Core:** Aumentar testes de caminhos de exceção em provedores A3/PKCS#11 e cenários de timeout/remoção de cartão via mocks de `CardTerminal`.
|
||||
2. **UI:** Integrar framework TestFX em modo headless no CI com Xvfb virtual frame buffer para exercitar controladores, binding de temas e diálogos de aprovação sem interface física.
|
||||
3. **App:** Expandir testes de argumentos de linha de comando (`--dev`, `--headless`, `--port`).
|
||||
|
||||
---
|
||||
|
||||
## 3. Passo a Passo para Criar a Primeira Tag `v0.1.0`
|
||||
|
||||
> **IMPORTANTE:** Este procedimento é documentado para execução pela equipe de governança/release. **Não execute a criação da tag automaticamente.**
|
||||
|
||||
### Pré-requisitos
|
||||
* Branch `main` atualizada e com pipeline de CI verde no Gitea Actions.
|
||||
* Árvore de trabalho limpa (`git status` sem alterações pendentes).
|
||||
* Ambiente com JDK 25 LTS ativo.
|
||||
|
||||
---
|
||||
|
||||
### Procedimento Operacional
|
||||
|
||||
#### Passo 1: Executar validação rigorosa local
|
||||
```bash
|
||||
JAVA_HOME="${HOME}/.jdks/jdk-25.0.4.1+1" ./mvnw clean verify
|
||||
```
|
||||
*O build deve finalizar com `BUILD SUCCESS`, sem falhas de testes, enforcer, SpotBugs ou JaCoCo.*
|
||||
|
||||
#### Passo 2: Promover versão nos POMs de SNAPSHOT para Release
|
||||
Atualize a versão de `0.1.0-SNAPSHOT` para `0.1.0` em todos os módulos:
|
||||
```bash
|
||||
./mvnw versions:set -DnewVersion=0.1.0 -DgenerateBackupPoms=false
|
||||
```
|
||||
|
||||
#### Passo 3: Sincronizar versão no SDK JavaScript
|
||||
```bash
|
||||
cd sdk
|
||||
npm version 0.1.0 --no-git-tag-version
|
||||
cd ..
|
||||
```
|
||||
|
||||
#### Passo 4: Atualizar data e cabeçalhos no `CHANGELOG.md`
|
||||
Edite o arquivo [CHANGELOG.md](../CHANGELOG.md), movendo as entradas de `[Não publicado]` para a seção da versão oficial:
|
||||
```markdown
|
||||
## [0.1.0] - 2026-10-20
|
||||
```
|
||||
|
||||
#### Passo 5: Realizar o commit de Release
|
||||
```bash
|
||||
git add pom.xml modules/*/pom.xml sdk/package.json CHANGELOG.md
|
||||
git commit -m "chore(release): prepare release v0.1.0"
|
||||
```
|
||||
|
||||
#### Passo 6: Criar a tag Git anotada
|
||||
Crie a tag anotada com mensagem formal de lançamento:
|
||||
```bash
|
||||
git tag -a v0.1.0 -m "Release v0.1.0: versão inicial do CyberCore Signer com suporte A1/A3, PAdES, XMLDSig e CCSP/1"
|
||||
```
|
||||
|
||||
#### Passo 7: Enviar o commit e a tag para o repositório remoto
|
||||
```bash
|
||||
git push origin main
|
||||
git push origin v0.1.0
|
||||
```
|
||||
|
||||
#### Passo 8: Avançar a versão de desenvolvimento para o próximo ciclo
|
||||
Logo após o push da tag de release, prepare a base para os próximos desenvolvimentos:
|
||||
```bash
|
||||
# Avança para o próximo ciclo de patch ou minor (ex: 0.1.1-SNAPSHOT):
|
||||
./mvnw versions:set -DnewVersion=0.1.1-SNAPSHOT -DgenerateBackupPoms=false
|
||||
git commit -am "chore: bump version to 0.1.1-SNAPSHOT"
|
||||
git push origin main
|
||||
```
|
||||
|
Before Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 46 KiB |
@@ -0,0 +1,99 @@
|
||||
# Processo de Release e Publicação do SDK Web (@cybercore/signer-sdk)
|
||||
|
||||
Este documento estabelece o fluxo oficial de versionamento, empacotamento, auditoria de segurança e publicação do pacote npm `@cybercore/signer-sdk` em registry privado (Gitea / Verdaccio / Artifactory).
|
||||
|
||||
---
|
||||
|
||||
## 1. Princípios e Ciclo de Vida
|
||||
|
||||
- **Versionamento Semântico Independente (SemVer):** O SDK JavaScript/TypeScript possui ciclo de release desacoplado do executável/instalador Java desktop (`jpackage` MSI/EXE).
|
||||
- Mudanças de correção de bugs / tipagem: `patch` (ex: `0.1.0` $\rightarrow$ `0.1.1`).
|
||||
- Novos métodos de alto nível ou temas de selos: `minor` (ex: `0.1.0` $\rightarrow$ `0.2.0`).
|
||||
- Mudanças de quebra de compatibilidade de API: `major` (ex: `0.1.0` $\rightarrow$ `1.0.0`).
|
||||
- **Compatibilidade com o CCSP/1:** O SDK permanece estritamente compatível com o protocolo CyberCore Signing Protocol v1 (`docs/ccsp-v1.schema.json`).
|
||||
|
||||
---
|
||||
|
||||
## 2. Configuração do Registry Privado (Gitea)
|
||||
|
||||
O pacote utiliza o escopo organizacional `@cybercore`. Para publicar e consumir o pacote em registries privados Gitea, configure o arquivo `~/.npmrc` na máquina de build ou no ambiente CI/CD:
|
||||
|
||||
```ini
|
||||
# ~/.npmrc
|
||||
@cybercore:registry=https://git.cybercore.com.br/api/packages/cybercore/npm/
|
||||
//git.cybercore.com.br/api/packages/cybercore/npm/:_authToken=${GITEA_NPM_TOKEN}
|
||||
always-auth=true
|
||||
```
|
||||
|
||||
> [!CAUTION]
|
||||
> **Nunca comite tokens de autenticação ou credenciais no repositório Git.** Utilize sempre variáveis de ambiente (`GITEA_NPM_TOKEN` ou `NPM_TOKEN`) configuradas no cofre de segredos da esteira CI/CD.
|
||||
|
||||
---
|
||||
|
||||
## 3. Checklist de Segurança Pré-Release
|
||||
|
||||
Antes de qualquer publicação, execute os itens obrigatórios:
|
||||
|
||||
1. [ ] **Testes Automatizados 100% Verdes:**
|
||||
```bash
|
||||
cd sdk
|
||||
npm test
|
||||
```
|
||||
Deve executar e aprovar os testes unitários (`signer-sdk.test.js`), testes de servidor mock (`mock-server.test.js`) e validação cruzada do schema (`schema-validation.test.js`).
|
||||
|
||||
2. [ ] **Auditoria de Conteúdo Empacotado:**
|
||||
Execute uma simulação de empacotamento para inspecionar exatamente quais arquivos serão distribuídos:
|
||||
```bash
|
||||
npm pack --dry-run
|
||||
```
|
||||
Verifique que apenas a pasta `src/` e o `README.md` estão listados no tarball. **Arquivos `.pfx`, `.p12`, `.key`, `.log`, fixtures de teste ou scripts confidenciais NÃO podem constar no tarball.**
|
||||
|
||||
3. [ ] **Tipagens TypeScript Atualizadas:**
|
||||
Certifique-se de que novos métodos ou parâmetros adicionados em `src/signer-sdk.js` e `src/errors.js` estão declarados em `src/signer-sdk.d.ts` e `src/errors.d.ts`.
|
||||
|
||||
4. [ ] **Validação Cruzada de Schema:**
|
||||
Certifique-se de que `docs/ccsp-v1.schema.json` e os testes Java em `cybercore-core` continuam passando sem inconsistências.
|
||||
|
||||
---
|
||||
|
||||
## 4. Passo a Passo de Publicação
|
||||
|
||||
### Passo 1: Atualizar a Versão
|
||||
A partir da pasta `sdk/`:
|
||||
```bash
|
||||
# Para correções de bugs retrocompatíveis:
|
||||
npm version patch -m "chore(release): bump sdk version to %s"
|
||||
|
||||
# Para novas funcionalidades retrocompatíveis:
|
||||
npm version minor -m "chore(release): bump sdk version to %s"
|
||||
```
|
||||
|
||||
### Passo 2: Publicar no Registry Privado
|
||||
```bash
|
||||
npm publish
|
||||
```
|
||||
|
||||
### Passo 3: Criar Tag Git e Sincronizar
|
||||
```bash
|
||||
git push origin feature/pdf-signing-flow --tags
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Como Consumir nas Aplicações Clientes
|
||||
|
||||
Nas aplicações web consumidoras (frontends internos ou de parceiros homologados):
|
||||
|
||||
1. Adicionar o arquivo `.npmrc` na raiz do projeto:
|
||||
```ini
|
||||
@cybercore:registry=https://git.cybercore.com.br/api/packages/cybercore/npm/
|
||||
```
|
||||
2. Instalar a dependência:
|
||||
```bash
|
||||
npm install @cybercore/signer-sdk@latest
|
||||
```
|
||||
3. Testar a importação:
|
||||
```typescript
|
||||
import { CyberCoreSigner } from '@cybercore/signer-sdk';
|
||||
const signer = new CyberCoreSigner();
|
||||
```
|
||||
@@ -202,3 +202,14 @@ try {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Documentação Relacionada e Recursos
|
||||
|
||||
- **Especificação Formal do Protocolo:** [`docs/CCSP.md`](./CCSP.md)
|
||||
- **JSON Schema CCSP/1:** [`docs/ccsp-v1.schema.json`](./ccsp-v1.schema.json)
|
||||
- **Compatibilidade de Navegadores & PNA:** [`docs/browser-compatibility.md`](./browser-compatibility.md)
|
||||
- **Exemplos Didáticos:** [`sdk/examples/`](../sdk/examples/README.md)
|
||||
- **Processo de Release do Pacote:** [`docs/sdk-release-process.md`](./sdk-release-process.md)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Modelo de Segurança e Privacidade
|
||||
# Modelo de Segurança, Privacidade e Análise de Ameaças (STRIDE)
|
||||
|
||||
> **Diretrizes de Segurança em Profundidade, Proteção Criptográfica e Conformidade LGPD**
|
||||
|
||||
@@ -6,66 +6,68 @@ O **CyberCore Signer** foi concebido sob os princípios de *Security by Design*
|
||||
|
||||
---
|
||||
|
||||
## 1. Isolamento de Rede e Proteção Local
|
||||
## 1. Modelo de Ameaças STRIDE e Matriz de Mitigações
|
||||
|
||||
### 1.1 Ligação Estrita ao Loopback (`127.0.0.1`)
|
||||
| Categoria STRIDE | Ameaça Potencial | Superfície / Vetor | Mitigação Implementada no CyberCore Signer |
|
||||
|---|---|---|---|
|
||||
| **S** - *Spoofing* (Falsificação de Identidade) | Aplicação web maliciosa se passa por sistema corporativo para assinar documentos fraudulentos. | `POST /ccsp/v1/sign`, `GET /ccsp/v1/certificates` | 1. Validação estrita de `Host` loopback (`127.0.0.1` / `localhost`).<br>2. Verificação de `Origin` autorizada cadastrada no `ApplicationRegistry`.<br>3. Handshake de consentimento explícito do usuário com diálogo nativo do sistema operacional. |
|
||||
| **T** - *Tampering* (Adulteração de Dados) | Malware local modifica arquivo `authorized-apps.json` para autorizar origens maliciosas silenciosamente. | Sistema de arquivos local (`~/.cybercore/authorized-apps.json`) | 1. Assinatura de integridade por **HMAC-SHA256** (`authorized-apps.json.hmac`) com chave isolada (`.vault_key`).<br>2. Permissões POSIX restritas `0600`/`0700` (acesso exclusivo do usuário dono).<br>3. Descarte total e alerta de auditoria em caso de divergência do HMAC. |
|
||||
| **R** - *Repudiation* (Repúdio de Operações) | Usuário ou aplicação contesta a execução de uma assinatura digital. | Transações CCSP / Logs | 1. Princípio **WYSIWYS**: exibição obrigatória de origem, aplicação, nome/tamanho do documento e hash SHA-256 legível.<br>2. Logs de auditoria estruturados com `request_id` (UUID), timestamp ISO 8601, algoritmo e fingerprint do certificado (sem expor segredos). |
|
||||
| **I** - *Information Disclosure* (Vazamento de Informações) | Vazamento de chave privada, PIN do token A3 ou documentos confidenciais. | Memória, tráfego de rede e arquivos de log | 1. Chaves privadas nunca saem da máquina/hardware.<br>2. Operação primária por **Digest** (o documento confidencial nunca trafega para o agente).<br>3. PIN manipulado em `char[]` efêmero com limpeza de memória (`Arrays.fill`).<br>4. Mascaramento LGPD de CPF em carimbos visuais.<br>5. Loopback estrito `127.0.0.1` e cabeçalhos PNA (`Access-Control-Allow-Private-Network`). |
|
||||
| **D** - *Denial of Service* (Negação de Serviço) | Invasor esgota conexões locais, tenta replay de assinaturas ou trava token mono-thread. | Socket HTTP local, driver PKCS#11 | 1. Trava FIFO serializada (`signLock` ReentrantLock) para proteção de drivers A3 mono-thread.<br>2. `NonceManager` com expiração TTL, tolerância a clock skew (30s) e deduplicação atômica.<br>3. Detecção e tratamento de colisão de porta com mecanismo de **Port-Hunting** sequencial. |
|
||||
| **E** - *Elevation of Privilege* (Elevação de Privilégio) | Usuário ou script tenta forçar modo de desenvolvimento (`--dev`) em ambiente de produção para simular assinaturas. | Linha de comando / Flags de execução | 1. Trava inviolável no bootstrap (`CyberCoreSignerApplication`): compilações com `flavor=production` abortam imediatamente com `SecurityException` se `--dev` for fornecido.<br>2. O modo dev só pode ser compilado através do perfil Maven explícito `-Pdev`. |
|
||||
|
||||
---
|
||||
|
||||
## 2. Comunicação Local e Arquitetura de Transporte (HTTP vs WebSocket)
|
||||
|
||||
### 2.1 Por que HTTP REST Loopback em vez de WebSockets?
|
||||
O CyberCore Signer utiliza **HTTP/1.1 REST Loopback** em `127.0.0.1:21325` por decisões fundamentadas de segurança:
|
||||
1. **Mitigação de CSWSH (Cross-Site WebSocket Hijacking):** WebSockets não respeitam a política Same-Origin Policy (SOP) tradicional e ignoram restrições CORS padrão de preflight `OPTIONS`. Um script malicioso em qualquer aba poderia abrir conexões bidirecionais diretas sem controle prévio.
|
||||
2. **Compatibilidade com Private Network Access (PNA):** Navegadores modernos (Chromium / Firefox) impõem restrições rigorosas quando páginas web públicas acessam `127.0.0.1`. O protocolo HTTP REST permite responder ao preflight com `Access-Control-Allow-Private-Network: true`, atendendo integralmente às diretrizes do W3C.
|
||||
3. **Preflight CORS Determinístico:** Cada método sensível é precedido por um preflight que valida o `Origin` contra o registro de aplicações autorizadas antes que qualquer payload seja consumido.
|
||||
|
||||
---
|
||||
|
||||
## 3. Isolamento de Rede e Proteção Local
|
||||
|
||||
### 3.1 Ligação Estrita ao Loopback (`127.0.0.1`)
|
||||
O servidor HTTP do protocolo CCSP/1 vincula-se exclusivamente ao endereço IPv4 local `127.0.0.1`.
|
||||
* **Sem Escuta Externa:** O agente nunca realiza bind em `0.0.0.0` ou em interfaces de rede de área local (LAN) ou externa (WAN).
|
||||
* **Bloqueio no Socket:** Tentativas de acesso originadas fora da própria estação de trabalho são sumariamente recusadas pelo subsistema de rede do sistema operacional antes de qualquer processamento da aplicação.
|
||||
|
||||
### 1.2 Proteção Contra Ataques de DNS Rebinding
|
||||
### 3.2 Proteção Contra Ataques de DNS Rebinding
|
||||
Para neutralizar ataques em que domínios externos tentam resolver para `127.0.0.1` e burlar a política de mesma origem do navegador:
|
||||
* O `CcspServer` valida expressamente o cabeçalho HTTP `Host`.
|
||||
* Somente requisições com `Host: 127.0.0.1:21325` ou `Host: localhost:21325` são aceitas; qualquer outro valor é rejeitado com status `403 Forbidden`.
|
||||
|
||||
### 1.3 Controle de Origem (CORS) e Preflight
|
||||
* Requisições prévias HTTP `OPTIONS` são validadas contra as origens web homologadas.
|
||||
* O cabeçalho `Access-Control-Allow-Origin` é devolvido estritamente com a origem solicitante autorizada (nunca com wildcard `*`).
|
||||
* O `CcspServer` valida expressamente o cabeçalho HTTP `Host` em **todas** as requisições (incluindo preflight `OPTIONS`).
|
||||
* Somente requisições com `Host` correspondente a `127.0.0.1:{porta}`, `localhost:{porta}` ou `[::1]:{porta}` são aceitas; qualquer outro valor é rejeitado com status `403 Forbidden` (`INVALID_ORIGIN`).
|
||||
|
||||
---
|
||||
|
||||
## 2. Autenticação e Autorização de Aplicações
|
||||
## 4. Integridade Criptográfica do Registro de Aplicações (`ApplicationRegistry`)
|
||||
|
||||
Nenhuma aplicação web externa tem acesso a certificados digitais ou serviços de assinatura sem autorização prévia e explícita do usuário:
|
||||
|
||||
1. **Handshake de Aprovação (`POST /ccsp/v1/authorize`):**
|
||||
- Ao tentar comunicar-se pela primeira vez, a aplicação web deve fornecer seu `application_id` (UUID estável) e seu nome amigável.
|
||||
- O CyberCore Signer suspende a requisição e exibe um modal nativo no desktop informando o nome da aplicação e solicitando autorização do usuário.
|
||||
2. **Armazenamento Seguro de Permissões:**
|
||||
- As aplicações autorizadas são gravadas no arquivo local `~/.cybercore/authorized-apps.json`.
|
||||
- O usuário pode visualizar e **revogar a qualquer momento** a autorização de qualquer aplicação através da aba **Configurações** na interface gráfica.
|
||||
As aplicações autorizadas pelo usuário são armazenadas em disco sob um esquema de proteção em profundidade:
|
||||
1. **Caminho:** `~/.cybercore/authorized-apps.json`.
|
||||
2. **Assinatura HMAC-SHA256:** Arquivo companheiro `authorized-apps.json.hmac` calcula o HMAC dos bytes JSON usando chave mestre de 256 bits gerada via `SecureRandom` e armazenada em `~/.cybercore/.vault_key`.
|
||||
3. **Permissões de Arquivo:** Aplicação de restrições POSIX (`0600` para arquivos e `0700` para diretórios) garantindo que apenas o usuário logado no sistema operacional possua direitos de leitura e escrita.
|
||||
4. **Detecção de Adulteração:** Se o arquivo JSON for modificado externamente (por malware ou editor de texto) sem a chave mestre, o carregamento descarta 100% das autorizações e emite alerta crítico de auditoria.
|
||||
|
||||
---
|
||||
|
||||
## 3. Proteção Contra Ataques de Replay
|
||||
## 5. Proteção de Memória e Ciclo de Vida do PIN/Chaves
|
||||
|
||||
Para impedir que requisições de assinatura capturadas por softwares maliciosos na máquina sejam reenviadas:
|
||||
1. **Identificador Único (`nonce`):** Toda requisição ao `/ccsp/v1/sign` deve conter um UUID aleatório criptograficamente forte gerado pelo chamador.
|
||||
2. **Janela de Validade Temporal (`expires_at`):** A requisição inclui uma estampa de tempo limite (TTL).
|
||||
3. **Gerenciador de Nonces (`NonceManager`):**
|
||||
- Mantém uma estrutura em memória com os identificadores recentes;
|
||||
- Se o mesmo `nonce` for submetido mais de uma vez dentro da janela de validade, a operação é rejeitada com erro estruturado `REPLAY_DETECTED` (HTTP `409 Conflict`);
|
||||
- Se a data/hora atual ultrapassar `expires_at`, a operação é rejeitada com erro `REQUEST_EXPIRED` (HTTP `422 Unprocessable Entity`).
|
||||
|
||||
---
|
||||
|
||||
## 4. Confirmação Visual Obrigatória e Proteção de PIN/Chaves
|
||||
|
||||
1. **Assinatura Exclusivamente Assistida:** Toda operação de assinatura exige interação humana voluntária. O agente nunca assina documentos em segundo plano de forma silenciosa ou desassistida via API.
|
||||
2. **Inviolabilidade da Chave Privada:** As chaves privadas ICP-Brasil nunca são exportadas em formato de bytes brutos. Operações em certificados A3 utilizam handles criptográficos do hardware, garantindo que a chave nunca deixe o chip criptográfico.
|
||||
3. **Higienização Segura de Memória Volátil:**
|
||||
1. **Assinatura Exclusivamente Assistida:** Toda operação de assinatura exige interação humana voluntária. O agente nunca assina documentos em segundo plano de forma desassistida via API.
|
||||
2. **Inviolabilidade da Chave Privada:** As chaves privadas ICP-Brasil nunca são exportadas em formato de bytes brutos. Operações em certificados A3 utilizam handles nativos do hardware/middleware (PKCS#11 / MSCAPI).
|
||||
3. **Higienização de Memória Volátil:**
|
||||
- O PIN de smartcards e senhas de certificados A1 nunca são convertidos para strings imutáveis do Java (`java.lang.String`).
|
||||
- São manipulados estritamente como arrays de caracteres mutáveis `char[]`.
|
||||
- Imediatamente após o carregamento da chave, o array é sobrescrito com zeros através de `Arrays.fill(pinBuffer, (char) 0)`.
|
||||
4. **Remoção de Hardware (`TOKEN_REMOVED`):** Se o usuário desconectar o token USB ou retirar o cartão do leitor durante ou após a assinatura, o `SmartCardWatcher` força a limpeza imediata do cache de sessão e dos buffers do sistema operacional.
|
||||
- Imediatamente após a autenticação do token, o array é sobrescrito com zeros via `Arrays.fill(pinBuffer, (char) 0)`.
|
||||
4. **Remoção de Hardware (`TOKEN_REMOVED`):** Se o usuário desconectar o token USB ou retirar o cartão do leitor, o `SmartCardWatcher` força a limpeza imediata do cache de sessão e dos buffers do sistema operacional.
|
||||
|
||||
---
|
||||
|
||||
## 5. Privacidade de Dados e Conformidade com a LGPD
|
||||
## 6. Software Bill of Materials (SBOM) e Cadeia de Suprimentos
|
||||
|
||||
1. **Assinatura Descentralizada por Digest:** O CyberCore Signer opera prioritariamente recebendo apenas o hash SHA-256 do arquivo. O conteúdo completo do documento (contrato, laudo, prontuário) não transita pela API local nem é gravado em logs.
|
||||
2. **Mascaramento e Sigilo de CPF:** Nos selos visuais em PDF, o usuário pode configurar o modo de exibição de seu CPF (`CpfDisplayMode`):
|
||||
- `FULL`: Exibição completa (`123.456.789-00`);
|
||||
- `MASKED`: Dígitos sensíveis ocultados (`***.456.789-**`);
|
||||
- `NONE`: Remoção completa do CPF do gráfico visual do selo.
|
||||
3. **Auditoria e Logs Transparentes:** Os logs do agente registram apenas identificadores de correlação (`request_id`), algoritmo utilizado e status da operação, sem armazenar hashes de documentos sigilosos ou dados pessoais desnecessários.
|
||||
1. **CycloneDX SBOM:** O build padronizado do projeto gera automaticamente o SBOM nos formatos `target/bom.json` e `target/bom.xml` conforme a especificação CycloneDX 1.6.
|
||||
2. **Análise Estática e Vulnerabilidades:** O pipeline de CI executa verificações contínuas de segurança:
|
||||
- **SpotBugs + FindSecBugs:** Análise estática profunda de vulnerabilidades criptográficas e injeções de código.
|
||||
- **Enforcer Plugin:** Verificação rigorosa de versões mínimas do compilador e convergência de dependências transitivas.
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
# Layout CyberCore Signer — Design Dual-Theme & Assinatura em Lote
|
||||
|
||||
O **CyberCore Signer** adota uma interface gráfica que une a ergonomia de hub consolidada no mercado nacional com uma identidade visual moderna, autoral e com suporte dinâmico a **Tema Claro (Light)** e **Tema Escuro (Dark)**.
|
||||
|
||||
---
|
||||
|
||||
## 1. Identidade Visual e Filosofia de Design
|
||||
|
||||
Em conformidade com os requisitos do projeto, a interface **não é uma cópia datada**, mas sim uma evolução:
|
||||
1. **Identidade CyberCore:** Logotipo central em cristal tridimensional e escudo criptográfico vetorial (`SvgIcons`), subtítulo "Agente Criptográfico Local • ICP-Brasil" e indicador de segurança em tempo real.
|
||||
2. **Badge de Status Ativo:** Exibe o status da porta local (`● Agente Ativo • 127.0.0.1:21325`) com verde esmeralda no modo claro e verde neon no modo escuro.
|
||||
3. **Alternador Dinâmico de Temas:** Botão pílula localizado no cabeçalho superior que permite ao usuário alternar instantaneamente entre **Modo Claro** e **Modo Escuro**:
|
||||
- Ícone do Sol ☀️ para comutar para o tema Claro.
|
||||
- Ícone da Lua 🌙 para comutar para o tema Escuro.
|
||||
- Classe gerenciadora centralizada: [`ThemeManager.java`](file:///var/www/cybercore/cybercore-signer/modules/cybercore-ui/src/main/java/br/com/cybercore/signer/ui/theme/ThemeManager.java), que replica a escolha de tema para todos os diálogos secundários.
|
||||
|
||||
---
|
||||
|
||||
## 2. Paleta de Cores dos Temas
|
||||
|
||||
| Componente | Tema Claro (Light) | Tema Escuro (Dark) |
|
||||
|---|---|---|
|
||||
| **Fundo da Janela** | `#f1f5f9` (Slate suave) | `#0b0f17` (Dark profundo) |
|
||||
| **Header Superior** | `#ffffff`, borda `#e2e8f0` | `#121824`, borda `#1e293b` |
|
||||
| **Cartões de Ação** | `#ffffff`, borda `#e2e8f0`, hover `#0284c7` | `#131c2e`, borda `#1e293b`, hover `#38bdf8` |
|
||||
| **Texto dos Botões** | `#1e293b` (Cinza escuro de alto contraste) | `#f8fafc` (Branco gelo nítido) |
|
||||
| **Painel Lateral** | `#ffffff`, borda `#e2e8f0` | `#121824`, borda `#1e293b` |
|
||||
| **Badge de Status** | Fundo `#ecfdf5`, texto `#047857`, borda `#10b981` | Fundo `rgba(16, 185, 129, 0.15)`, texto `#34d399` |
|
||||
| **Alternador de Tema** | Fundo `#ffffff`, borda `#cbd5e1`, hover `#0284c7` | Fundo `#1e293b`, borda `#334155`, hover `#38bdf8` |
|
||||
|
||||
---
|
||||
|
||||
## 3. Grade Central de Ações (Hub 4x3)
|
||||
|
||||
A interface principal organiza as operações em 12 cartões modernos com cantos arredondados (8px), sombras suaves e ícones vetoriais SVG nítidos:
|
||||
|
||||
| Posição | Operação | Descrição |
|
||||
|---|---|---|
|
||||
| (0, 0) | **Assinar PDF** | Assinatura digital de documentos PDF com cálculo de hash SHA-256 e gravação de assinatura. |
|
||||
| (1, 0) | **Assinar XML** | Assinatura de documentos XML (estruturas fiscais, NF-e, XMLDSig). |
|
||||
| (2, 0) | **Assinar Arquivo** | Assinatura genérica de qualquer arquivo ou binário do sistema. |
|
||||
| (3, 0) | **Assinar em Lote** | Processamento simultâneo de múltiplos arquivos com barra de progresso em tempo real. |
|
||||
| (0, 1) | **Assinatura Atachada** | Assinatura embutida/anexada ao documento original (CAdES enveloped). |
|
||||
| (1, 1) | **Co-Assinar Documento** | Adição de nova assinatura a um documento previamente assinado por outro titular. |
|
||||
| (2, 1) | **Carimbo do Tempo** | Integração com protocolo RFC 3161 TSP para prova de anterioridade temporal. |
|
||||
| (3, 1) | **Assinatura LTV** | Perfil de Longa Duração com inclusão de cadeia de certificados e carimbos para validade permanente. |
|
||||
| (0, 2) | **Validar Assinatura** | Verificação de integridade criptográfica e conformidade do certificado digital. |
|
||||
| (1, 2) | **Validar Carimbo** | Verificação da autenticidade e validade temporal de tokens TSR/TSP. |
|
||||
| (2, 2) | *(Reservado)* | Espaço reservado para expansões futuras do agente. |
|
||||
| (3, 2) | **Sair do Agente** | Encerramento seguro da sessão do agente. |
|
||||
|
||||
---
|
||||
|
||||
## 4. Painel Lateral de Utilitários
|
||||
|
||||
Na coluna lateral direita, o usuário dispõe de atalhos rápidos para operações do sistema:
|
||||
|
||||
1. **`</> Logs`:** Visualizador de auditoria em tempo real, monitorando requisições locais CCSP/1 e eventos criptográficos.
|
||||
2. **`⚙ Configurações`:** Gerenciador de origens web autorizadas, revogação de acessos e opções de PIN.
|
||||
3. **`💻 Tutorial`:** Guia passo a passo interativo de uso do assinador e integração web.
|
||||
4. **`🗂 Certificados`:** Lista de certificados ICP-Brasil instalados (Windows-MY, A1 e A3) e ferramenta para importação de certificados A1 (`.pfx` / `.p12`).
|
||||
5. **`ℹ Sobre`:** Informações de versão, engine JCA/JCE e garantias de privacidade local.
|
||||
|
||||
---
|
||||
|
||||
## 5. Assinatura Digital em Lote (`BatchSigningDialog`)
|
||||
|
||||
A funcionalidade de assinatura em lote permite:
|
||||
- Seleção de múltiplos arquivos simultâneos via diálogo de arquivos ou pastas.
|
||||
- Visualização de tabela com nome, tamanho e status de cada item em tempo real.
|
||||
- Seleção do certificado digital ICP-Brasil desejado (com exibição de titular, CPF/CNPJ, tipo A1/A3 e validade).
|
||||
- Escolha da pasta de destino para os arquivos assinados (salvando arquivos `.p7s` correspondentes).
|
||||
- Execução assíncrona em thread isolada para manter a interface responsiva durante todo o lote.
|
||||
- Compatibilidade automática com o tema ativo (Claro ou Escuro).
|
||||
|
||||
---
|
||||
|
||||
## 6. Ícones Vetoriais SVG Nativos (`SvgIcons`)
|
||||
|
||||
Todos os ícones e o logotipo central em cristal foram construídos via `SVGPath` e primitivas vetoriais JavaFX nativas:
|
||||
- **Resolução Infinita:** Perfeita nitidez em monitores Full HD, 2K, 4K e configurações de escala de DPI do Windows (100%, 125%, 150%, 200%).
|
||||
- **Sem Dependência de Imagens Rasterizadas:** Sem risco de imagens ausentes ou corrompidas no runtime empacotado.
|
||||
@@ -0,0 +1,86 @@
|
||||
# Guia de Padrão Visual e Design System SVG — CyberCore Signer
|
||||
|
||||
Este documento estabelece a especificação oficial de design, geometria, tokens de cores e regras de compatibilidade para todos os ícones e elementos gráficos vetoriais (**SVG**) do ecossistema **CyberCore Signer**.
|
||||
|
||||
---
|
||||
|
||||
## 1. Princípios de Design
|
||||
|
||||
1. **Clareza e Precisão:** Cada ícone deve comunicar imediatamente sua função técnica (PDF, XML, assinatura embutida, validação, credenciais).
|
||||
2. **Minimalismo e Geometria Pura:** Evitar ruídos visuais, nós desnecessários, filtros proprietários ou imagens bitmap embutidas (`<image>`).
|
||||
3. **Consistência de Traço e Escala:** Espessuras de contorno previsíveis e alinhadas ao grid de 48x48 pixels.
|
||||
4. **Interoperabilidade:** Totalmente compatível com editores vetoriais modernos (**Inkscape, Figma, Adobe Illustrator**) e com o parser nativo de JavaFX em `AssetManager`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Grid e Canvas Canônico
|
||||
|
||||
| Propriedade | Valor Padrão | Descrição |
|
||||
|---|---|---|
|
||||
| **ViewBox** | `0 0 48 48` | Padrão obrigatório para ícones da grade de ações e ferramentas laterais. |
|
||||
| **Dimensões Base** | `width="48" height="48"` | Dimensões nominais 1:1. |
|
||||
| **Área Segura** | `4px` de margem interna | O conteúdo vetorial deve se concentrar entre `(4, 4)` e `(44, 44)`. |
|
||||
| **Raio de Canto Padrão** | `rx="3"` ou `rx="6"` | Arredondamentos harmônicos em cantos de janelas e etiquetas. |
|
||||
|
||||
---
|
||||
|
||||
## 3. Paleta de Cores e Tokens Visuais
|
||||
|
||||
Os ícones utilizam uma paleta de cores corporativa baseada em Material Design e Tailwind Modern, com alto contraste sobre fundos claros e escuros:
|
||||
|
||||
| Token | Hexadecimal | Papel / Significado |
|
||||
|---|---|---|
|
||||
| **`color-brand-primary`** | `#0288d1` | Azul CyberCore. Traço padrão de folhas, botões principais e XML. |
|
||||
| **`color-brand-deep`** | `#01579b` | Azul escuro para dobras e acentos de profundidade. |
|
||||
| **`color-paper-fold`** | `#b3e5fc` | Preenchimento suave da dobra superior do documento padrão. |
|
||||
| **`color-pdf-accent`** | `#d32f2f` | Vermelho institucional do formato Adobe PDF. |
|
||||
| **`color-pdf-fold`** | `#ffcdd2` | Preenchimento suave da dobra do documento PDF. |
|
||||
| **`color-success`** | `#10b981` / `#2e7d32` | Verde esmeralda para assinaturas válidas e verificações. |
|
||||
| **`color-gold-seal`** | `#f59e0b` / `#d97706` | Dourado e âmbar para selos notariais e certificação digital. |
|
||||
| **`color-paper-lines`** | `#b0bec5` / `#cfd8dc` | Linhas de texto representativas e divisórias neutras. |
|
||||
| **`color-console-bg`** | `#1e293b` | Fundo de janelas de terminal (Logs). |
|
||||
| **`color-danger-exit`** | `#d32f2f` | Seta e alertas de encerramento do agente. |
|
||||
|
||||
---
|
||||
|
||||
## 4. Anatomia dos Ícones de Documentos
|
||||
|
||||
Para documentos com dobra (como PDF, XML, Atachada e Validador):
|
||||
|
||||
```xml
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48" height="48">
|
||||
<!-- 1. Folha de documento com dobra -->
|
||||
<path d="M 8 4 L 32 4 L 42 14 L 42 44 L 8 44 Z"
|
||||
fill="#ffffff" stroke="[COR_BORDA]" stroke-width="2.5" stroke-linejoin="round"/>
|
||||
|
||||
<!-- 2. Dobra de canto superior direito -->
|
||||
<path d="M 32 4 L 32 14 L 42 14 Z"
|
||||
fill="[COR_FUNDO_DOBRA]" stroke="[COR_BORDA]" stroke-width="2" stroke-linejoin="round"/>
|
||||
|
||||
<!-- 3. Linhas de texto representativas -->
|
||||
<line x1="13" y1="18" x2="27" y2="18" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="13" y1="22" x2="35" y2="22" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="13" y1="26" x2="35" y2="26" stroke="#b0bec5" stroke-width="2" stroke-linecap="round"/>
|
||||
|
||||
<!-- 4. Elemento distintivo inferior (Etiqueta, Caneta, Clipe ou Checkmark) -->
|
||||
<rect x="11" y="31" width="28" height="11" rx="3" fill="[COR_BADGE]"/>
|
||||
<text x="25" y="39" font-family="'Segoe UI', Arial, sans-serif"
|
||||
font-size="8px" font-weight="bold" fill="#ffffff" text-anchor="middle">[TEXTO]</text>
|
||||
</svg>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Boas Práticas para Exportação no Inkscape / Figma
|
||||
|
||||
Ao criar ou editar ícones nas ferramentas vetoriais externas:
|
||||
|
||||
1. **Escolha a opção "SVG Simples" (Plain SVG) no Inkscape:**
|
||||
- No Inkscape: `Arquivo → Salvar Como... → SVG Simples (*.svg)`.
|
||||
- Isso elimina metadados de sessão (`sodipodi:namedview`, guias, zoom e histórico).
|
||||
2. **Nunca incorpore imagens bitmap (`<image>` base64):**
|
||||
- O aplicativo desktop deve conter exclusivamente geometria vetorial limpa (`path`, `rect`, `circle`, `line`, `polygon`, `polyline`, `text`).
|
||||
3. **Suporte a `style="..."` inline:**
|
||||
- O parser do CyberCore Signer (`AssetManager`) suporta tanto atributos XML puros (`fill="#..."`) quanto estilos inline em CSS (`style="fill:#...;stroke:#..."`).
|
||||
4. **Mantenha o ViewBox Quadrado:**
|
||||
- Preserve sempre `viewBox="0 0 48 48"` para garantir alinhamento perfeito nos botões e painéis da interface.
|
||||
@@ -0,0 +1,75 @@
|
||||
# Layout e Interface Gráfica — CyberCore Signer
|
||||
|
||||
O **CyberCore Signer** adota uma interface gráfica profissional e moderna, com foco em usabilidade, segurança visual e conformidade rigorosa com os padrões de acessibilidade WCAG 2.1 (AA).
|
||||
|
||||
---
|
||||
|
||||
## 1. Identidade Visual e Filosofia de Design
|
||||
|
||||
A interface foi estruturada com foco na clareza operacional e consistência ergonômica:
|
||||
1. **Identidade CyberCore:** Logotipo central em cristal e escudo criptográfico vetorial (`SvgIcons`), subtítulo "Agente Criptográfico Local • ICP-Brasil" e indicador de segurança em tempo real.
|
||||
2. **Badge de Status Ativo:** Exibe o status do agente e da porta local (`● Agente Ativo • 127.0.0.1:21325`) com indicação em verde esmeralda.
|
||||
3. **Tema Único Padronizado:** Sistema visual unificado baseado em tokens CSS declarados em `.root`, garantindo contraste nítido, tipografia escalável e ausência de inconsistências de renderização.
|
||||
|
||||
---
|
||||
|
||||
## 2. Paleta de Cores e Tokens Semânticos
|
||||
|
||||
| Componente / Token | Valor Canônico | Descrição |
|
||||
|---|---|---|
|
||||
| **Fundo da Janela** (`-fx-color-background`) | `#f1f5f9` | Tom slate neutro e suave para leitura prolongada |
|
||||
| **Superfície de Cartões** (`-fx-color-surface`) | `#ffffff` | Branco puro para cartões, caixas e painéis |
|
||||
| **Bordas Principais** (`-fx-color-border`) | `#cbd5e1` | Linhas de divisão estrutural com contraste seguro |
|
||||
| **Bordas Suaves** (`-fx-color-border-subtle`) | `#e2e8f0` | Divisórias e contornos secundários |
|
||||
| **Texto Primário** (`-fx-color-text`) | `#0f172a` | Texto de alto contraste (WCAG ratio ~ 15.8:1) |
|
||||
| **Texto Atenuado** (`-fx-color-text-muted`) | `#475569` | Rótulos secundários e metadados (WCAG ratio ~ 6.8:1) |
|
||||
| **Cor Primária** (`-fx-color-primary`) | `#0284c7` | Azul característico da marca CyberCore para ações padrão |
|
||||
| **Sucesso** (`-fx-color-success`) | `#16a34a` | Indicadores de assinaturas válidas e status operacional |
|
||||
| **Aviso** (`-fx-color-warning`) | `#d97706` | Alertas de atenção e certificados próximos ao vencimento |
|
||||
| **Erro** (`-fx-color-error`) | `#dc2626` | Notificações de erro ou falha criptográfica |
|
||||
|
||||
---
|
||||
|
||||
## 3. Grade Central de Ações (Hub 3x2)
|
||||
|
||||
A interface principal organiza as operações em 6 cartões modernos com cantos arredondados (8px), sombras suaves e ícones vetoriais SVG nítidos:
|
||||
|
||||
| Posição | Operação | Descrição |
|
||||
|---|---|---|
|
||||
| (0, 0) | **Assinar PDF** | Assinatura digital de documentos PDF (PAdES) com visualização e posicionamento interativo de selos. |
|
||||
| (1, 0) | **Assinar XML** | Assinatura de documentos XML (estruturas fiscais, NF-e, XMLDSig). |
|
||||
| (2, 0) | **Assinatura Atachada** | Assinatura embutida/anexada ao documento original (CAdES enveloped). |
|
||||
| (0, 1) | **Gerenciar Selos** | Abertura do Designer e Gerenciador de Selos Digitais visuais para PAdES. |
|
||||
| (1, 1) | **Validar Assinatura** | Verificação de integridade criptográfica e conformidade do certificado digital. |
|
||||
| (2, 1) | **Sair do Agente** | Encerramento seguro da sessão do agente. |
|
||||
|
||||
---
|
||||
|
||||
## 4. Painel Lateral de Utilitários
|
||||
|
||||
Na coluna lateral direita, o usuário dispõe de atalhos rápidos para operações do sistema:
|
||||
|
||||
1. **`</> Logs`:** Visualizador de auditoria em tempo real, monitorando requisições locais CCSP/1 e eventos criptográficos.
|
||||
2. **`⚙ Configurações`:** Gerenciador de origens web autorizadas, revogação de acessos e opções de PIN.
|
||||
3. **`💻 Tutorial`:** Guia passo a passo interativo de uso do assinador e integração web.
|
||||
4. **`🗂 Certificados`:** Lista de certificados ICP-Brasil disponíveis (Windows Certificate Store, A1 e A3) e ferramenta para importação de certificados A1 (`.pfx` / `.p12`).
|
||||
5. **`ℹ Sobre`:** Informações de versão, engine JCA/JCE e garantias de privacidade local.
|
||||
|
||||
---
|
||||
|
||||
## 5. Assinatura Digital em Lote (`BatchSigningDialog`)
|
||||
|
||||
A funcionalidade de assinatura em lote permite:
|
||||
- Seleção de múltiplos arquivos simultâneos via diálogo de arquivos ou pastas.
|
||||
- Visualização de tabela com nome, tamanho e status de cada item em tempo real.
|
||||
- Seleção do certificado digital ICP-Brasil desejado (com exibição de titular, CPF/CNPJ, tipo A1/A3 e validade).
|
||||
- Escolha da pasta de destino para os arquivos assinados (salvando arquivos `.p7s` correspondentes).
|
||||
- Execução assíncrona em thread isolada para manter a interface responsiva durante todo o lote.
|
||||
|
||||
---
|
||||
|
||||
## 6. Ícones Vetoriais SVG Nativos (`SvgIcons`)
|
||||
|
||||
Todos os ícones e o logotipo central em cristal foram construídos via `SVGPath` e primitivas vetoriais JavaFX nativas:
|
||||
- **Resolução Infinita:** Perfeita nitidez em monitores Full HD, 2K, 4K e configurações de escala de DPI do Windows (100%, 125%, 150%, 200%).
|
||||
- **Sem Dependência de Imagens Rasterizadas:** Sem risco de imagens ausentes ou corrompidas no runtime empacotado.
|
||||
@@ -0,0 +1,95 @@
|
||||
# UI Troubleshooting & Resolução de Estilos (JavaFX CSS)
|
||||
|
||||
Este documento registra a investigação da causa raiz de problemas visuais na interface gráfica do CyberCore Signer, em especial a falha de renderização de textos com cor preta (`Color.BLACK`) via `setStyle()`, a eliminação definitiva de estilos inline de cor e a transição para o tema claro unificado.
|
||||
|
||||
---
|
||||
|
||||
## 1. O Problema: Texto Renderizado em Preto (`#000000`) via `setStyle`
|
||||
|
||||
### Sintoma
|
||||
Em diálogos modais como `ExitConfirmationDialog`, `PdfSignDialog` e `PdfCertificateSignDialog`, chamadas como:
|
||||
```java
|
||||
subtitle.setStyle("-fx-text-fill: -fx-text-secondary;");
|
||||
lblDocName.setStyle("-fx-text-fill: -fx-text-primary;");
|
||||
dragTip.setStyle("-fx-text-fill: -fx-text-secondary;");
|
||||
```
|
||||
resultavam em texto renderizado com a cor preta opaca (`#000000`), mesmo quando o token `-fx-text-secondary` já se encontrava definido no arquivo `theme.css`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Investigação Técnica e Causa Raiz
|
||||
|
||||
### 2.1 Por que `setStyle("-fx-text-fill: -fx-text-secondary")` renderiza PRETO?
|
||||
No motor de estilização do JavaFX (`com.sun.javafx.css.StyleManager` / `CssStyleHelper`):
|
||||
|
||||
1. **Momento da Avaliação (Timing) de Nós Fora da Árvore da Scene:**
|
||||
Quando um nó (como um `Label` ou `Text`) é instanciado no código Java dentro do construtor de um diálogo e recebe `.setStyle("-fx-text-fill: -fx-text-secondary;")`, ele ainda **não foi anexado ao grafo de cena** (`Scene`).
|
||||
2. **Escopo de Resolução de Lookups Ausente:**
|
||||
Como `-fx-text-secondary` é uma cor pesquisada (*looked-up color*) definida no seletor `.root` da folha de estilo da aplicação, a engine de CSS do JavaFX tenta resolver essa variável subindo a cadeia de nós pais (`parent chain`) até alcançar `.root`. Como o nó está solto na memória (sem parent e sem Scene vinculada no instante da chamada), o lookup não encontra nenhuma definição válida.
|
||||
3. **Mecanismo de Fallback Silencioso do Modena (`Color.BLACK`):**
|
||||
O analisador do JavaFX não lança exceção ao falhar na resolução de uma cor de lookup em estilo inline. Em vez disso, seu conversor (`PaintConverter` / `ColorConverter`) assume o valor padrão de salvaguarda da especificação Modena: **`Color.BLACK` (`rgba(0, 0, 0, 1.0)`)**.
|
||||
4. **Imutabilidade e Prioridade do Estilo Inline:**
|
||||
O estilo inline atribuído via `setStyle(...)` possui a especificidade mais alta na hierarquia CSS do JavaFX. O valor pré-resolvido como `Color.BLACK` fica gravado diretamente no cache de estilo do nó. Quando a Scene finalmente executa a passagem formal de CSS (`applyCss()` / `layout()`), a engine prioriza o estilo inline e não reavalia o lookup que falhou previamente.
|
||||
|
||||
### 2.2 Por que o problema não ocorre com Classes CSS?
|
||||
Quando utilizamos classes semânticas declaradas em folha de estilo (ex.: `lbl.getStyleClass().add("text-muted");`):
|
||||
```css
|
||||
.text-muted {
|
||||
-fx-text-fill: -fx-text-secondary;
|
||||
}
|
||||
```
|
||||
A resolução da regra é postergada até que o nó pertença à hierarquia da Scene e a passagem de CSS do JavaFX seja executada. Nesse momento, o nó tem acesso direto às definições de `.root`, resolvendo perfeitamente o token para a cor correta da paleta (`#475569`).
|
||||
|
||||
---
|
||||
|
||||
## 3. Diretriz Arquitetural: Proibição de Cores em `setStyle()`
|
||||
|
||||
Fica estabelecido como regra obrigatória de desenvolvimento no `cybercore-ui`:
|
||||
|
||||
1. **`setStyle()` restrito exclusivamente à Geometria:**
|
||||
- Permitido: dimensões dinâmicas, larguras mínimas, alturas, alinhamentos e paddings específicos de cálculo em tempo de execução (`-fx-min-width`, `-fx-pref-width`, `-fx-padding`, `-fx-alignment`).
|
||||
- **Terminantemente proibido em `setStyle()`:**
|
||||
- `-fx-text-fill`
|
||||
- `-fx-background-color`
|
||||
- `-fx-border-color`
|
||||
- `-fx-fill` / `-fx-stroke`
|
||||
- Códigos hexadecimais (`#...`) ou funções cromáticas (`rgb(...)`, `rgba(...)`)
|
||||
- Nomes de lookups de cor (`-fx-accent`, `-fx-color-*`, etc.)
|
||||
|
||||
2. **Uso Obrigatório de Classes CSS Semânticas:**
|
||||
| Classe CSS | Finalidade | Propriedade Aplicada |
|
||||
|---|---|---|
|
||||
| `.text-primary` | Texto principal | `-fx-text-fill: -fx-text-primary;` |
|
||||
| `.text-secondary`, `.text-muted` | Texto auxiliar / metadados | `-fx-text-fill: -fx-text-secondary;` |
|
||||
| `.text-accent` | Destaque primário | `-fx-text-fill: -fx-accent;` |
|
||||
| `.text-bold` | Tipografia em negrito | `-fx-font-weight: bold;` |
|
||||
| `.text-small` | Texto compacto | `-fx-font-size: 11px;` |
|
||||
| `.text-mono` | Fonte monoespaçada para hashes | `-fx-font-family: monospace;` |
|
||||
| `.surface-box` | Container de superfície branca com borda | `-fx-background-color: -fx-color-surface;` |
|
||||
| `.toolbar-box` | Barra de ferramentas compacta | `-fx-background-color: -fx-color-surface;` |
|
||||
| `.scroll-transparent` | ScrollPane sem fundo cinza | `-fx-background-color: transparent;` |
|
||||
| `.status-ok` / `.status-warn` / `.status-error` | Indicadores de status | Cores semânticas da paleta |
|
||||
|
||||
---
|
||||
|
||||
## 4. Salvaguardas Automatizadas
|
||||
|
||||
O teste de arquitetura [`DesignTokenGuardrailTest.java`](file:///var/www/cybercore/cybercore-signer/modules/cybercore-ui/src/test/java/br/com/cybercore/signer/ui/theme/DesignTokenGuardrailTest.java) atua como barreira de compilação contínua:
|
||||
- Varre todos os arquivos `.java` no módulo `cybercore-ui` e reprova automaticamente o build se qualquer chamada `setStyle()` contiver propriedades ou valores de cor.
|
||||
- Valida matematicamente a relação de contraste WCAG AA (mínimo de 4.5:1 para texto normal) em todas as combinações de tokens de texto sobre superfície/fundo.
|
||||
- Assegura ausência de seletores ou classes residuais de temas escuros (`.theme-dark`, `AppTheme`, `isDark()`).
|
||||
|
||||
---
|
||||
|
||||
## 5. Comportamento da Barra de Título Nativa no Windows (DWM em Modo Escuro)
|
||||
|
||||
### Diagnóstico Operacional
|
||||
Quando o sistema operacional Windows 10/11 está configurado no "Modo Escuro do Sistema" (*Personalização > Cores > Escolher o modo: Escuro*), o gerenciador de janelas do sistema operacional (**Desktop Window Manager — DWM**) aplica automaticamente o atributo `DWMWA_USE_IMMERSIVE_DARK_MODE` na moldura não-cliente da janela nativa (`HWND`).
|
||||
|
||||
Como o CyberCore Signer utiliza decoração nativa padrão (`StageStyle.DECORATED`) para preservar o comportamento esperado pelo usuário empresarial — incluindo cantos arredondados, atalhos de teclado nativos, suporte a múltiplos monitores com DPIs distintos e os *Snap Layouts* do Windows 11 — a barra de título nativa é desenhada pelo Windows em tom escuro, enquanto o conteúdo da janela exibe o tema claro unificado da aplicação.
|
||||
|
||||
### Diretriz de Arquitetura (Não Forçar)
|
||||
Em estrita conformidade com as diretrizes do projeto (Regras 2 e 23):
|
||||
1. **Não forçar a barra de título:** Evita-se o uso de hacks de baixo nível via JNA/JNI para sobrescrever o DWM do Windows ou janelas não decoradas (`UNDECORATED`), o que causaria quebra de acessibilidade e perda de recursos nativos do sistema.
|
||||
2. **Harmonia Visual:** A moldura do Windows atua como moldura de sistema e o conteúdo claro do CyberCore Signer permanece legível, íntegro e em total conformidade com a especificação de interface.
|
||||
|
||||
@@ -108,6 +108,23 @@
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>build-info.properties</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
<excludes>
|
||||
<exclude>build-info.properties</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.openjfx</groupId>
|
||||
@@ -138,6 +155,7 @@
|
||||
<Implementation-Title>CyberCore Signer</Implementation-Title>
|
||||
<Implementation-Version>${project.version}</Implementation-Version>
|
||||
<Implementation-Vendor>CyberCore</Implementation-Vendor>
|
||||
<Build-Flavor>${cybercore.build.flavor}</Build-Flavor>
|
||||
</manifestEntries>
|
||||
</transformer>
|
||||
</transformers>
|
||||
@@ -157,6 +175,39 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>jacoco-check</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>check</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<rules>
|
||||
<rule>
|
||||
<element>BUNDLE</element>
|
||||
<limits>
|
||||
<limit>
|
||||
<counter>LINE</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>0.70</minimum>
|
||||
</limit>
|
||||
<limit>
|
||||
<counter>BRANCH</counter>
|
||||
<value>COVEREDRATIO</value>
|
||||
<minimum>0.45</minimum>
|
||||
</limit>
|
||||
</limits>
|
||||
</rule>
|
||||
</rules>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -19,15 +19,47 @@ public class CyberCoreSignerApplication {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CyberCoreSignerApplication.class);
|
||||
|
||||
private static final String BUILD_INFO_RESOURCE = "/build-info.properties";
|
||||
private static String buildFlavor = "production";
|
||||
private static boolean developmentMode = false;
|
||||
private static boolean headlessMode = false;
|
||||
private static boolean noWaitMode = false;
|
||||
private static int configuredPort = CcspServer.DEFAULT_PORT;
|
||||
private static volatile CcspServer runningServer = null;
|
||||
|
||||
static {
|
||||
loadBuildInfo();
|
||||
}
|
||||
|
||||
private static void loadBuildInfo() {
|
||||
try (var is = CyberCoreSignerApplication.class.getResourceAsStream(BUILD_INFO_RESOURCE)) {
|
||||
if (is != null) {
|
||||
var props = new java.util.Properties();
|
||||
props.load(is);
|
||||
String flavor = props.getProperty("build.flavor");
|
||||
if (flavor != null && !flavor.isBlank()) {
|
||||
buildFlavor = flavor.trim().toLowerCase();
|
||||
}
|
||||
}
|
||||
} catch (java.io.IOException ignored) {}
|
||||
}
|
||||
|
||||
public static String getBuildFlavor() {
|
||||
return buildFlavor;
|
||||
}
|
||||
|
||||
public static void setBuildFlavorForTesting(String flavor) {
|
||||
buildFlavor = flavor;
|
||||
}
|
||||
|
||||
public static CcspServer getRunningServer() {
|
||||
return runningServer;
|
||||
}
|
||||
|
||||
public static int getConfiguredPort() {
|
||||
return configuredPort;
|
||||
}
|
||||
|
||||
public static void stopServer() {
|
||||
if (runningServer != null) {
|
||||
runningServer.stop();
|
||||
@@ -36,6 +68,17 @@ public class CyberCoreSignerApplication {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Previne conflitos nativos de UI Automation/Acessibilidade do Glass no Windows 11
|
||||
if (System.getProperty("javafx.accessibility") == null) {
|
||||
System.setProperty("javafx.accessibility", "false");
|
||||
}
|
||||
if (System.getProperty("glass.accessible.force") == null) {
|
||||
System.setProperty("glass.accessible.force", "false");
|
||||
}
|
||||
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
|
||||
logger.error("Exceção não tratada na thread '{}': {}", thread.getName(), throwable.getMessage(), throwable);
|
||||
});
|
||||
|
||||
parseArguments(args);
|
||||
printBanner();
|
||||
|
||||
@@ -57,34 +100,18 @@ public class CyberCoreSignerApplication {
|
||||
logger.error("ALERTA CRÍTICO: Engine criptográfica JCA/JCE não está totalmente operacional!");
|
||||
}
|
||||
|
||||
// Se o ambiente tiver suporte gráfico e não for headless forçado, abre a interface JavaFX
|
||||
boolean isHeadless = headlessMode || GraphicsEnvironment.isHeadless();
|
||||
|
||||
if (isHeadless) {
|
||||
logger.info("Executando em modo console / headless (sem interface gráfica).");
|
||||
startHeadlessServer();
|
||||
} else {
|
||||
try {
|
||||
logger.info("Iniciando interface gráfica desktop...");
|
||||
CyberCoreDesktopApplication.setDevelopmentMode(developmentMode);
|
||||
Application.launch(CyberCoreDesktopApplication.class, args);
|
||||
} catch (Throwable t) {
|
||||
logger.warn("Não foi possível inicializar ambiente gráfico ({}). Continuando em modo console.", t.getMessage());
|
||||
startHeadlessServer();
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("CyberCore Signer finalizado.");
|
||||
}
|
||||
|
||||
private static void startHeadlessServer() {
|
||||
try {
|
||||
// 1. Inicializa o núcleo e o servidor CCSP imediatamente (alta velocidade)
|
||||
CertificateManager certManager = CertificateManager.createDefault();
|
||||
if (developmentMode) {
|
||||
logger.info("Modo de desenvolvimento ativo (com certificados reais do sistema).");
|
||||
}
|
||||
SigningService signingService = new SigningService(certManager);
|
||||
runningServer = new CcspServer(certManager, signingService, null);
|
||||
br.com.cybercore.signer.core.protocol.CcspUserPromptListener promptListener =
|
||||
new br.com.cybercore.signer.ui.prompt.JavaFxPromptListener();
|
||||
|
||||
try {
|
||||
runningServer = new CcspServer(configuredPort, certManager, signingService,
|
||||
br.com.cybercore.signer.core.security.ApplicationRegistry.getInstance(), promptListener);
|
||||
runningServer.start();
|
||||
logger.info("Servidor local CCSP/1 pronto em http://127.0.0.1:{}", runningServer.getPort());
|
||||
|
||||
@@ -92,22 +119,74 @@ public class CyberCoreSignerApplication {
|
||||
logger.info("Encerrando servidor local CCSP/1...");
|
||||
stopServer();
|
||||
}));
|
||||
} catch (java.net.BindException e) {
|
||||
logger.error("ALERTA DE COLISÃO DE PORTA: A porta {} já está em uso por outra instância do CyberCore Signer ou outro serviço. Para usar uma porta alternativa, utilize o parâmetro --port <porta> ou defina a variável de ambiente CYBERCORE_PORT.", configuredPort);
|
||||
} catch (Exception e) {
|
||||
if (e.getCause() instanceof java.net.BindException || (e.getMessage() != null && e.getMessage().contains("Address already in use"))) {
|
||||
logger.error("ALERTA DE COLISÃO DE PORTA: A porta {} já está em uso por outra instância do CyberCore Signer ou outro serviço. Para usar uma porta alternativa, utilize o parâmetro --port <porta> ou defina a variável de ambiente CYBERCORE_PORT.", configuredPort);
|
||||
} else {
|
||||
logger.error("Falha ao inicializar servidor local CCSP/1: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Se o ambiente tiver suporte gráfico e não for headless forçado, abre a interface JavaFX
|
||||
boolean isHeadless = headlessMode || GraphicsEnvironment.isHeadless();
|
||||
|
||||
if (!isHeadless) {
|
||||
try {
|
||||
logger.info("Iniciando interface gráfica desktop desacoplada...");
|
||||
CyberCoreDesktopApplication.setDevelopmentMode(developmentMode);
|
||||
CyberCoreDesktopApplication.setSharedServices(runningServer, certManager, signingService);
|
||||
Thread uiThread = new Thread(() -> {
|
||||
try {
|
||||
Application.launch(CyberCoreDesktopApplication.class, args);
|
||||
} catch (Throwable t) {
|
||||
logger.warn("Interface gráfica finalizada ou indisponível: {}", t.getMessage());
|
||||
}
|
||||
}, "cybercore-desktop-ui");
|
||||
uiThread.setDaemon(false);
|
||||
uiThread.start();
|
||||
} catch (Throwable t) {
|
||||
logger.warn("Não foi possível inicializar ambiente gráfico ({}). Continuando em modo serviço.", t.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.info("Executando em modo console / headless (sem interface gráfica).");
|
||||
}
|
||||
|
||||
// Mantém processo vivo para atender requisições web, a menos que em modo no-wait
|
||||
if (!noWaitMode) {
|
||||
try {
|
||||
Thread.currentThread().join();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (Exception e) {
|
||||
logger.error("Falha ao inicializar servidor local CCSP/1 no modo console: {}", e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseArguments(String[] args) {
|
||||
logger.info("CyberCore Signer finalizado.");
|
||||
}
|
||||
|
||||
public static void parseArguments(String[] args) {
|
||||
String envPort = System.getenv("CYBERCORE_PORT");
|
||||
if (envPort != null && !envPort.isBlank()) {
|
||||
try {
|
||||
configuredPort = Integer.parseInt(envPort.trim());
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
String propPort = System.getProperty("cybercore.port");
|
||||
if (propPort != null && !propPort.isBlank()) {
|
||||
try {
|
||||
configuredPort = Integer.parseInt(propPort.trim());
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
|
||||
if (args != null) {
|
||||
for (String arg : args) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
String arg = args[i];
|
||||
if ("--dev".equalsIgnoreCase(arg) || "-dev".equalsIgnoreCase(arg)) {
|
||||
if ("production".equalsIgnoreCase(buildFlavor)) {
|
||||
logger.error("ALERTA DE SEGURANÇA: Modo de desenvolvimento (--dev) não é permitido em compilações de produção (flavor: production).");
|
||||
throw new SecurityException("Modo de desenvolvimento (--dev) bloqueado em compilações de produção.");
|
||||
}
|
||||
developmentMode = true;
|
||||
} else if ("--headless".equalsIgnoreCase(arg) || "-headless".equalsIgnoreCase(arg)
|
||||
|| "--cli".equalsIgnoreCase(arg)) {
|
||||
@@ -115,6 +194,13 @@ public class CyberCoreSignerApplication {
|
||||
} else if ("--no-wait".equalsIgnoreCase(arg) || "-no-wait".equalsIgnoreCase(arg)
|
||||
|| "--test".equalsIgnoreCase(arg)) {
|
||||
noWaitMode = true;
|
||||
} else if (("--port".equalsIgnoreCase(arg) || "-p".equalsIgnoreCase(arg)) && i + 1 < args.length) {
|
||||
try {
|
||||
configuredPort = Integer.parseInt(args[++i].trim());
|
||||
} catch (NumberFormatException e) {
|
||||
String sanitized = args[i].replaceAll("[\r\n]", "");
|
||||
logger.warn("Porta inválida especificada em --port: '{}'. Usando porta padrão {}.", sanitized, CcspServer.DEFAULT_PORT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
build.version=${project.version}
|
||||
build.flavor=${cybercore.build.flavor}
|
||||
@@ -34,4 +34,17 @@ class ArchitectureTest {
|
||||
|
||||
rule.check(importedClasses);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("O módulo Core não deve acessar o ciclo de vida do toolkit JavaFX (Application ou Platform)")
|
||||
void coreShouldNotAccessJavaFxLifecycle() {
|
||||
ArchRule rule = noClasses()
|
||||
.that().resideInAPackage("br.com.cybercore.signer.core..")
|
||||
.should().dependOnClassesThat()
|
||||
.haveFullyQualifiedName("javafx.application.Application")
|
||||
.orShould().dependOnClassesThat()
|
||||
.haveFullyQualifiedName("javafx.application.Platform");
|
||||
|
||||
rule.check(importedClasses);
|
||||
}
|
||||
}
|
||||
|
||||