feat(ui): enhance signature confirmation dialog with wysiwys details and update ccsp spec
This commit is contained in:
+9
-2
@@ -116,7 +116,13 @@ public record CcspRequest(
|
||||
String targetElementTag,
|
||||
|
||||
@JsonProperty("target_element_id")
|
||||
String targetElementId
|
||||
String targetElementId,
|
||||
|
||||
@JsonProperty("document_size")
|
||||
Long documentSize,
|
||||
|
||||
@JsonProperty("origin")
|
||||
String origin
|
||||
) implements Serializable {
|
||||
|
||||
public static final String PROTOCOL_VERSION = "1";
|
||||
@@ -130,7 +136,8 @@ public record CcspRequest(
|
||||
certificateHint, expiresAt, timestamp, nonce, signatureType,
|
||||
null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null, null, null, null, null, null, null, null);
|
||||
null, null, null, null, null, null, null, null, null, null,
|
||||
null, null);
|
||||
}
|
||||
|
||||
public boolean isVersionSupported() {
|
||||
|
||||
+20
-2
@@ -472,9 +472,27 @@ public class CyberCoreDesktopApplication extends Application {
|
||||
.map(AuthorizedApplication::name)
|
||||
.orElse(request.applicationId());
|
||||
|
||||
Long docSize = request.documentSize();
|
||||
if (docSize == null && request.pdf() != null) {
|
||||
try {
|
||||
docSize = (long) Base64.getDecoder().decode(request.pdf()).length;
|
||||
} catch (Exception ignored) {}
|
||||
} else if (docSize == null && request.xmlBase64() != null) {
|
||||
try {
|
||||
docSize = (long) Base64.getDecoder().decode(request.xmlBase64()).length;
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
String requestOrigin = request.origin();
|
||||
if (requestOrigin == null || requestOrigin.isBlank()) {
|
||||
requestOrigin = ApplicationRegistry.getInstance().findById(request.applicationId())
|
||||
.map(a -> String.join(", ", a.allowedOrigins()))
|
||||
.orElse("Requisição Web Local");
|
||||
}
|
||||
|
||||
SignaturePromptDialog dialog = new SignaturePromptDialog(
|
||||
stage, appName, "Requisição Web CCSP", certificate, context,
|
||||
request.documentName(), request.documentType(), request.isAuthentication()
|
||||
stage, appName, requestOrigin, certificate, context,
|
||||
request.documentName(), request.documentType(), docSize, request.isAuthentication()
|
||||
);
|
||||
dialog.showAndAwait().whenComplete((approved, err) -> {
|
||||
if (err != null) {
|
||||
|
||||
+44
-7
@@ -36,12 +36,18 @@ public class SignaturePromptDialog {
|
||||
|
||||
public SignaturePromptDialog(Stage owner, String applicationName, String origin,
|
||||
ManagedCertificate certificate, SigningContext context) {
|
||||
this(owner, applicationName, origin, certificate, context, null, null, false);
|
||||
this(owner, applicationName, origin, certificate, context, null, null, null, false);
|
||||
}
|
||||
|
||||
public SignaturePromptDialog(Stage owner, String applicationName, String origin,
|
||||
ManagedCertificate certificate, SigningContext context,
|
||||
String documentName, String documentType, boolean isAuthentication) {
|
||||
this(owner, applicationName, origin, certificate, context, documentName, documentType, null, isAuthentication);
|
||||
}
|
||||
|
||||
public SignaturePromptDialog(Stage owner, String applicationName, String origin,
|
||||
ManagedCertificate certificate, SigningContext context,
|
||||
String documentName, String documentType, Long documentSize, boolean isAuthentication) {
|
||||
stage = new Stage();
|
||||
stage.initModality(Modality.APPLICATION_MODAL);
|
||||
if (owner != null) {
|
||||
@@ -52,11 +58,11 @@ public class SignaturePromptDialog {
|
||||
: "CyberCore Signer — Solicitação de Assinatura");
|
||||
stage.setResizable(false);
|
||||
|
||||
initLayout(applicationName, origin, certificate, context, documentName, documentType, isAuthentication);
|
||||
initLayout(applicationName, origin, certificate, context, documentName, documentType, documentSize, isAuthentication);
|
||||
}
|
||||
|
||||
private void initLayout(String appName, String origin, ManagedCertificate cert, SigningContext context,
|
||||
String documentName, String documentType, boolean isAuthentication) {
|
||||
String documentName, String documentType, Long documentSize, boolean isAuthentication) {
|
||||
VBox root = new VBox(16);
|
||||
root.getStyleClass().add("dialog-container");
|
||||
root.setPadding(new Insets(20, 24, 20, 24));
|
||||
@@ -94,7 +100,8 @@ public class SignaturePromptDialog {
|
||||
grid.setVgap(10);
|
||||
|
||||
int row = 0;
|
||||
addField(grid, row++, "Sistema:", appName + " (" + (origin != null ? origin : "Local") + ")");
|
||||
addField(grid, row++, "Aplicação Solicitante:", appName);
|
||||
addField(grid, row++, "Origem Web:", (origin != null && !origin.isBlank() ? origin : "Local"));
|
||||
if (isAuthentication) {
|
||||
addField(grid, row++, "Operação:", "Autenticação de Usuário (Challenge-Response)");
|
||||
} else {
|
||||
@@ -102,7 +109,12 @@ public class SignaturePromptDialog {
|
||||
String docLabel = (documentType != null && !documentType.isBlank())
|
||||
? "[" + documentType.toUpperCase() + "] " + documentName
|
||||
: documentName;
|
||||
if (documentSize != null && documentSize > 0) {
|
||||
docLabel += " (" + formatFileSize(documentSize) + ")";
|
||||
}
|
||||
addField(grid, row++, "Documento:", docLabel);
|
||||
} else if (documentSize != null && documentSize > 0) {
|
||||
addField(grid, row++, "Tamanho do Documento:", formatFileSize(documentSize));
|
||||
}
|
||||
addField(grid, row++, "Operação:", "Assinatura Digital (Digest)");
|
||||
}
|
||||
@@ -128,14 +140,16 @@ public class SignaturePromptDialog {
|
||||
|
||||
detailsBox.getChildren().add(grid);
|
||||
|
||||
// Caixa do Hash / Digest
|
||||
// Caixa do Hash / Digest formatado em blocos legíveis (WYSIWYS)
|
||||
VBox hashBox = new VBox(6);
|
||||
Label hashLabel = new Label("Hash do Documento (SHA-256 Digest):");
|
||||
Label hashLabel = new Label("Hash do Documento (SHA-256 Digest formatado):");
|
||||
hashLabel.getStyleClass().add("dialog-field-title");
|
||||
|
||||
String hashHex = HexFormat.of().formatHex(context.digest());
|
||||
Label hashValue = new Label(hashHex);
|
||||
String formattedHash = formatHashBlocks(hashHex);
|
||||
Label hashValue = new Label(formattedHash);
|
||||
hashValue.getStyleClass().add("dialog-hash-value");
|
||||
hashValue.setStyle("-fx-font-family: 'Liberation Mono', 'Courier New', monospace; -fx-font-size: 11px;");
|
||||
hashValue.setWrapText(true);
|
||||
|
||||
hashBox.getChildren().addAll(hashLabel, hashValue);
|
||||
@@ -301,4 +315,27 @@ public class SignaturePromptDialog {
|
||||
stage.toFront();
|
||||
return approvalFuture;
|
||||
}
|
||||
|
||||
private static String formatFileSize(long bytes) {
|
||||
if (bytes < 1024) {
|
||||
return bytes + " B";
|
||||
} else if (bytes < 1024 * 1024) {
|
||||
return String.format(java.util.Locale.ROOT, "%.1f KB", bytes / 1024.0);
|
||||
} else {
|
||||
return String.format(java.util.Locale.ROOT, "%.1f MB", bytes / (1024.0 * 1024.0));
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatHashBlocks(String hex) {
|
||||
if (hex == null || hex.isBlank()) return "";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String upper = hex.toUpperCase(java.util.Locale.ROOT);
|
||||
for (int i = 0; i < upper.length(); i++) {
|
||||
if (i > 0 && i % 4 == 0) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(upper.charAt(i));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user