feat: update PDF stamp picker and server CORS settings for enhanced UI rendering

This commit is contained in:
Claudecio Martins
2026-10-11 19:45:30 -03:00
parent b46d8b665f
commit 994a27886e
9 changed files with 440 additions and 123 deletions
@@ -131,12 +131,12 @@ public class CyberCoreSignerApplication {
private static void printBanner() {
System.out.println("""
============================================================
____ _ ____
/ ___| _ _ __| | ___ _ __ / ___|___ _ __ ___
| | | | | |/ _` | / _ \\| '__| | | / _ \\ | '__|/ _ \\
| |___ | |_| | (_| || __/| | | |__| (_) || | | __/
\\____| \\__, |\\__,_| \\___||_| \\____\\___/ |_| \\___|
|___/
____ _ ____ \s
/ ___| _ _ | |__ ___ _ __ / ___|___ _ __ ___ \s
| | | | | | | '_ \\ / _ \\ '__| | | / _ \\| '__/ _ \\ \s
| |___ | |_| | | |_) | __/ | | |__| (_) | | | __/ \s
\\____| \\__, | |_.__/ \\___|_| \\____\\___/|_| \\___| \s
|___/ \s
SIGNER AGENT v0.1.0
============================================================
""");
@@ -990,7 +990,8 @@ public class CcspServer {
exchange.getResponseHeaders().set("Access-Control-Allow-Origin", origin);
exchange.getResponseHeaders().set("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
exchange.getResponseHeaders().set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-CyberCore-AppId, X-CyberCore-Nonce");
exchange.getResponseHeaders().set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-CyberCore-AppId, X-CyberCore-Nonce, Accept");
exchange.getResponseHeaders().set("Access-Control-Allow-Private-Network", "true");
exchange.getResponseHeaders().set("Access-Control-Max-Age", "86400");
if ("OPTIONS".equalsIgnoreCase(exchange.getRequestMethod())) {
@@ -96,6 +96,7 @@ public class CyberCoreDesktopApplication extends Application {
// Inicializa serviços centrais reais da plataforma
this.certificateManager = CertificateManager.createDefault();
this.signingService = new SigningService(this.certificateManager);
if (developmentMode) {
logger.info("Modo de desenvolvimento ativo (utilizando certificados reais da máquina).");
@@ -57,21 +57,27 @@ public class SignaturePromptDialog {
private void initLayout(String appName, String origin, ManagedCertificate cert, SigningContext context,
String documentName, String documentType, boolean isAuthentication) {
VBox root = new VBox(18);
VBox root = new VBox(16);
root.getStyleClass().add("dialog-container");
root.setPrefWidth(540);
root.setPadding(new Insets(20, 24, 20, 24));
root.setPrefWidth(560);
HBox headerBox = new HBox(12);
HBox headerBox = new HBox(14);
headerBox.setAlignment(Pos.CENTER_LEFT);
VBox titleBox = new VBox(2);
Label header = new Label(isAuthentication ? "SOLICITAÇÃO DE LOGIN DIGITAL" : "SOLICITAÇÃO DE ASSINATURA");
VBox titleBox = new VBox(3);
HBox.setHgrow(titleBox, Priority.ALWAYS);
titleBox.setMaxWidth(Double.MAX_VALUE);
Label header = new Label(isAuthentication ? "SOLICITAÇÃO DE LOGIN" : "SOLICITAÇÃO DE ASSINATURA");
header.getStyleClass().add("dialog-header");
Label desc = new Label(isAuthentication
? "Uma aplicação web está solicitando autenticação de identidade com seu Certificado Digital ICP-Brasil."
: "Uma aplicação web está solicitando a assinatura digital de um documento.");
desc.getStyleClass().add("brand-subtitle");
desc.setWrapText(true);
desc.setMaxWidth(480);
titleBox.getChildren().addAll(header, desc);
headerBox.getChildren().addAll(
@@ -145,7 +151,8 @@ public class SignaturePromptDialog {
"O PIN deste dispositivo é gerenciado diretamente pelo driver nativo (SafeSign / Windows Security). " +
"Caso o token ainda não esteja autenticado, a janela segura do driver será aberta automaticamente."
);
winDesc.setStyle("-fx-text-fill: -fx-text-secondary; -fx-font-size: 12px;");
winDesc.getStyleClass().add("dialog-subtitle");
winDesc.setStyle("-fx-font-size: 12px;");
winDesc.setWrapText(true);
winBox.getChildren().addAll(winTitle, winDesc);
@@ -177,6 +184,7 @@ public class SignaturePromptDialog {
if (nowVisible) {
cbSavePin.setSelected(true);
}
stage.sizeToScene();
});
rememberedBox.getChildren().addAll(rememberedBadge, btnChangePin);
@@ -184,25 +192,26 @@ public class SignaturePromptDialog {
} else {
VBox inputWrapper = new VBox(8);
Label pinPromptLabel = new Label("Informe o PIN do dispositivo para autorizar a chave privada:");
pinPromptLabel.setStyle("-fx-text-fill: -fx-text-secondary; -fx-font-size: 12px;");
pinPromptLabel.getStyleClass().add("dialog-subtitle");
pinPromptLabel.setStyle("-fx-font-size: 12px;");
cbSavePin.setSelected(false);
inputWrapper.getChildren().addAll(pinPromptLabel, pinField, cbSavePin);
pinContainer.getChildren().add(inputWrapper);
}
}
detailsBox.getChildren().add(pinContainer);
}
// Label de Alerta de Validação
Label validationLabel = new Label();
validationLabel.setStyle("-fx-text-fill: #f87171; -fx-font-size: 12px;");
validationLabel.setVisible(false);
validationLabel.setManaged(false);
// Botões de Ação
HBox actionsRow = new HBox(12);
actionsRow.setAlignment(Pos.CENTER_RIGHT);
actionsRow.setPadding(new Insets(4, 0, 0, 0));
Button btnCancel = new Button("Cancelar");
btnCancel.getStyleClass().add("btn-cancel");
@@ -222,6 +231,8 @@ public class SignaturePromptDialog {
if (!hasStoredPin && !pinProvided) {
validationLabel.setText("Atenção: O PIN do token é obrigatório para assinar via PKCS#11.");
validationLabel.setVisible(true);
validationLabel.setManaged(true);
stage.sizeToScene();
pinField.requestFocus();
return;
}
@@ -242,12 +253,18 @@ public class SignaturePromptDialog {
actionsRow.getChildren().addAll(btnCancel, btnConfirm);
root.getChildren().addAll(headerBox, detailsBox, validationLabel, actionsRow);
if (isA3) {
root.getChildren().addAll(headerBox, detailsBox, pinContainer, validationLabel, actionsRow);
} else {
root.getChildren().addAll(headerBox, detailsBox, validationLabel, actionsRow);
}
Scene scene = new Scene(root);
ThemeManager.applyTheme(scene);
stage.setScene(scene);
stage.sizeToScene();
stage.centerOnScreen();
stage.setOnCloseRequest(e -> approvalFuture.complete(false));
}
@@ -263,6 +280,8 @@ public class SignaturePromptDialog {
}
public CompletableFuture<Boolean> showAndAwait() {
stage.sizeToScene();
stage.centerOnScreen();
stage.show();
stage.toFront();
return approvalFuture;
@@ -6,6 +6,7 @@
.root {
-fx-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
-fx-font-size: 13px;
-fx-text-secondary: #64748b;
}
/* ==========================================================================
@@ -17,6 +18,7 @@
-fx-background: #f1f5f9;
-fx-control-inner-background: #ffffff;
-fx-text-fill: #0f172a;
-fx-text-secondary: #64748b;
}
.theme-light.cyber-root,
@@ -438,6 +440,7 @@
-fx-background: #0b0f17;
-fx-control-inner-background: #131c2e;
-fx-text-fill: #f1f5f9;
-fx-text-secondary: #94a3b8;
}
.theme-dark.cyber-root,
@@ -855,7 +858,7 @@
/* Botões Base e Proteção contra Truncamento com Reticências */
.button {
-fx-min-width: -fx-pref-size;
-fx-min-width: -1;
}
.btn-primary {
@@ -865,7 +868,6 @@
-fx-padding: 8px 18px;
-fx-background-radius: 6px;
-fx-cursor: hand;
-fx-min-width: -fx-pref-size;
-fx-alignment: center;
-fx-effect: dropshadow(three-pass-box, rgba(2, 132, 199, 0.25), 4, 0, 0, 1);
}
@@ -880,7 +882,6 @@
-fx-font-weight: bold;
-fx-padding: 8px 18px;
-fx-background-radius: 6px;
-fx-min-width: -fx-pref-size;
-fx-alignment: center;
-fx-cursor: hand;
}
@@ -910,7 +911,6 @@
-fx-text-fill: #475569;
-fx-font-weight: bold;
-fx-padding: 8px 18px;
-fx-min-width: -fx-pref-size;
-fx-alignment: center;
-fx-cursor: hand;
}
@@ -933,14 +933,12 @@
/* Botões Padronizados para Diálogos e Modais */
.btn-dialog {
-fx-min-width: 110px;
-fx-pref-width: -fx-pref-size;
-fx-pref-height: 34px;
-fx-alignment: center;
}
.btn-dialog-wide {
-fx-min-width: 220px;
-fx-pref-width: -fx-pref-size;
-fx-pref-height: 36px;
-fx-alignment: center;
}
@@ -949,13 +947,12 @@
.btn-compact {
-fx-padding: 5px 12px;
-fx-font-size: 11.5px;
-fx-min-width: -fx-pref-size;
-fx-alignment: center;
}
/* Botão de Perigo / Exclusão / Remoção */
.btn-danger {
-fx-background-color: #fee2e2;
-fx-background-color: #fee2e8;
-fx-text-fill: #b91c1c;
-fx-border-color: #fca5a5;
-fx-border-radius: 6px;
@@ -965,7 +962,6 @@
-fx-font-weight: bold;
-fx-padding: 6px 14px;
-fx-alignment: center;
-fx-min-width: -fx-pref-size;
-fx-cursor: hand;
}