feat: implement in-memory log buffer, add ICP-Brasil seal assets, and improve SDK parameter handling

This commit is contained in:
Claudecio Martins
2026-10-11 20:58:49 -03:00
parent 2a50704a7f
commit 5f4a212786
14 changed files with 399 additions and 213 deletions
@@ -38,17 +38,16 @@ public final class CertificateCardNode extends VBox {
HBox topRow = new HBox(10);
topRow.setAlignment(Pos.CENTER_LEFT);
Label titleLabel = new Label(certificate.commonName() != null ? certificate.commonName() : certificate.alias());
String rawName = certificate.commonName() != null ? certificate.commonName() : certificate.alias();
String cleanTitle = rawName != null && rawName.contains(":") ? rawName.split(":")[0].trim() : (rawName != null ? rawName.trim() : "Certificado Digital");
Label titleLabel = new Label(cleanTitle);
titleLabel.getStyleClass().add("cert-title");
HBox.setHgrow(titleLabel, Priority.ALWAYS);
Label badgeLabel = new Label();
Label badgeLabel = new Label("[" + certificate.type().getCode() + "]");
if (certificate.type() == CertificateType.A1) {
badgeLabel.setText("A1 • Certificado local");
badgeLabel.getStyleClass().add("cert-badge-a1");
} else {
String tokenDesc = certificate.hardwareDeviceName() != null ? certificate.hardwareDeviceName() : "Token USB";
badgeLabel.setText("A3 • " + tokenDesc);
badgeLabel.getStyleClass().add("cert-badge-a3");
}
@@ -57,24 +57,43 @@ public final class LogsViewerDialog {
txtLogs.getStyleClass().add("log-console-area");
VBox.setVgrow(txtLogs, Priority.ALWAYS);
loadInitialLogs();
loadLogs();
HBox footer = new HBox(10);
footer.setAlignment(Pos.CENTER_RIGHT);
Button btnCopy = new Button("Copiar");
btnCopy.getStyleClass().addAll("btn-secondary", "btn-dialog");
btnCopy.setPrefWidth(90);
btnCopy.setOnAction(e -> {
javafx.scene.input.ClipboardContent content = new javafx.scene.input.ClipboardContent();
content.putString(txtLogs.getText());
javafx.scene.input.Clipboard.getSystemClipboard().setContent(content);
btnCopy.setText("✓ Copiado");
javafx.animation.PauseTransition pause = new javafx.animation.PauseTransition(javafx.util.Duration.seconds(2));
pause.setOnFinished(ev -> btnCopy.setText("Copiar"));
pause.play();
});
Button btnClear = new Button("Limpar");
btnClear.getStyleClass().addAll("btn-secondary", "btn-dialog");
btnClear.setPrefWidth(90);
btnClear.setOnAction(e -> {
br.com.cybercore.signer.core.log.AppLogBuffer.clear();
loadLogs();
});
Button btnRefresh = new Button("Atualizar");
btnRefresh.getStyleClass().addAll("btn-secondary", "btn-dialog");
btnRefresh.setPrefWidth(110);
btnRefresh.setMinWidth(110);
btnRefresh.setOnAction(e -> loadInitialLogs());
btnRefresh.setPrefWidth(100);
btnRefresh.setOnAction(e -> loadLogs());
Button btnClose = new Button(" Fechar", SvgIcons.closeIcon(13));
btnClose.getStyleClass().addAll("btn-secondary", "btn-dialog");
btnClose.setPrefWidth(110);
btnClose.setMinWidth(110);
btnClose.setPrefWidth(100);
btnClose.setOnAction(e -> stage.close());
footer.getChildren().addAll(btnRefresh, btnClose);
footer.getChildren().addAll(btnCopy, btnClear, btnRefresh, btnClose);
root.getChildren().addAll(header, txtLogs, footer);
@@ -84,15 +103,15 @@ public final class LogsViewerDialog {
stage.setScene(scene);
}
private void loadInitialLogs() {
String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
String sb = "[" + now + "] [INFO] CyberCore Signer inicializado com sucesso.\n" +
"[" + now + "] [INFO] Servidor local CCSP/1 escutando em http://127.0.0.1:21325\n" +
"[" + now + "] [INFO] Provedores criptográficos registrados: Windows Certificate Store, PKCS#12, PKCS#11.\n" +
"[" + now + "] [INFO] SmartCardWatcher ativo (monitoramento de tokens USB e Smart Cards ICP-Brasil).\n" +
"[" + now + "] [INFO] Política anti-replay: nonces protegidos em memória.\n" +
"[" + now + "] [INFO] Registro de aplicações web ativo e pronto para autorização segura.\n";
txtLogs.setText(sb);
private void loadLogs() {
java.util.List<String> logs = br.com.cybercore.signer.core.log.AppLogBuffer.getLogs();
if (logs.isEmpty()) {
txtLogs.setText("[Aguardando eventos de log...]");
} else {
txtLogs.setText(String.join("\n", logs) + "\n");
}
txtLogs.positionCaret(txtLogs.getText().length());
txtLogs.setScrollTop(Double.MAX_VALUE);
}
private VBox createHeaderLabel(String title, String subtitle) {
@@ -106,9 +106,24 @@ public class SignaturePromptDialog {
}
addField(grid, row++, "Operação:", "Assinatura Digital (Digest)");
}
addField(grid, row++, "Certificado:", cert.commonName() != null ? cert.commonName() : cert.alias());
addField(grid, row++, "Tipo / Dispositivo:", cert.type().getCode() + " • " +
(cert.hardwareDeviceName() != null ? cert.hardwareDeviceName() : cert.type().getLabel()));
String rawCertName = cert.commonName() != null ? cert.commonName() : cert.alias();
String holderName = rawCertName.contains(":") ? rawCertName.split(":")[0].trim() : rawCertName.trim();
String docInfo = "";
if (cert.cnpj() != null && !cert.cnpj().isBlank()) {
docInfo = ", CNPJ " + cert.cnpj();
} else if (cert.cpf() != null && !cert.cpf().isBlank()) {
docInfo = ", CPF " + cert.cpf();
} else if (rawCertName.contains(":")) {
String candidate = rawCertName.split(":")[1].trim();
if (candidate.length() == 14) {
docInfo = ", CNPJ " + candidate;
} else if (candidate.length() == 11) {
docInfo = ", CPF " + candidate;
}
}
String certDesc = holderName + docInfo + " [" + cert.type().getCode() + "]";
addField(grid, row++, "Certificado:", certDesc);
addField(grid, row++, "Tipo:", cert.type().getCode() + " (" + cert.type().getLabel() + ")");
addField(grid, row++, "Algoritmo:", context.algorithm());
detailsBox.getChildren().add(grid);
@@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 54" width="36" height="54">
<!-- Escudo Criptográfico Vetorial ICP-Brasil -->
<path d="M18 4 L32 9 V24 C32 37 25 46 18 50 C11 46 4 37 4 24 V9 Z" fill="#0d47a1" opacity="0.14"/>
<path d="M18 4 L32 9 V24 C32 37 25 46 18 50 C11 46 4 37 4 24 V9 Z" fill="none" stroke="#0d47a1" stroke-width="2.2" stroke-linejoin="round"/>
<!-- Corpo do Cadeado de Segurança -->
<rect x="11" y="24" width="14" height="12" rx="2.5" fill="#0284c7"/>
<!-- Arco Superior do Cadeado -->
<path d="M13.5 24 V19 C13.5 16.5 15.5 14.5 18 14.5 C20.5 14.5 22.5 16.5 22.5 19 V24" fill="none" stroke="#0284c7" stroke-width="2.2" stroke-linecap="round"/>
<!-- Orifício da Chave -->
<circle cx="18" cy="29" r="1.6" fill="#ffffff"/>
<path d="M17.3 29.5 L18.7 29.5 L19.2 33 L16.8 33 Z" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 858 B