refactor: update PDF seal text, improve CCSP logging, and add signed PDF response aliases

This commit is contained in:
Claudecio Martins
2026-10-11 20:11:45 -03:00
parent 994a27886e
commit 2a50704a7f
6 changed files with 36 additions and 6 deletions
@@ -162,7 +162,7 @@ public final class PdfSealThemeRegistry {
<text x="56" y="32" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="12" font-weight="bold" fill="${THEME_TEXT}">${SIGNER_NAME}</text> <text x="56" y="32" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="12" font-weight="bold" fill="${THEME_TEXT}">${SIGNER_NAME}</text>
<text x="56" y="46" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="8.5" fill="#065f46">Doc: ${SIGNER_DOC} • AC: ${CERT_ISSUER}</text> <text x="56" y="46" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="8.5" fill="#065f46">Doc: ${SIGNER_DOC} • AC: ${CERT_ISSUER}</text>
<text x="56" y="59" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="8.5" fill="#475569">Data/Hora: ${SIGNING_DATE}</text> <text x="56" y="59" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="8.5" fill="#475569">Data/Hora: ${SIGNING_DATE}</text>
<text x="56" y="72" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="7.5" fill="#047857">Validade jurídica assegurada pela MP nº 2.200-2/2001</text> <text x="56" y="72" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif" font-size="7.5" fill="#047857">Verifique a autenticidade da assinatura eletrônica em https://validar.iti.gov.br</text>
</svg> </svg>
""" """
)); ));
@@ -328,10 +328,14 @@ public class CcspServer {
try (InputStream is = exchange.getRequestBody()) { try (InputStream is = exchange.getRequestBody()) {
request = objectMapper.readValue(is, CcspRequest.class); request = objectMapper.readValue(is, CcspRequest.class);
} catch (Exception e) { } catch (Exception e) {
logger.warn("[CCSP REQ INVÁLIDO] POST /ccsp/v1/sign de Origin: {} | Erro parsing: {}", origin, e.getMessage());
sendCcspError(exchange, 400, null, CcspErrorCode.SIGNATURE_FAILED, "Payload de requisição inválido."); sendCcspError(exchange, 400, null, CcspErrorCode.SIGNATURE_FAILED, "Payload de requisição inválido.");
return; return;
} }
logger.info("[CCSP REQ] POST /ccsp/v1/sign | Origin: {} | ReqId: {} | App: {} | Op: {} | Algoritmo: {} | CertHint: {}",
origin, request.requestId(), request.applicationId(), request.operation(), request.algorithm(), request.certificateHint());
// 1. Validação de versão // 1. Validação de versão
if (!request.isVersionSupported()) { if (!request.isVersionSupported()) {
sendCcspError(exchange, 400, request.requestId(), CcspErrorCode.COMMUNICATION_ERROR, sendCcspError(exchange, 400, request.requestId(), CcspErrorCode.COMMUNICATION_ERROR,
@@ -495,10 +499,15 @@ public class CcspServer {
try (InputStream is = exchange.getRequestBody()) { try (InputStream is = exchange.getRequestBody()) {
request = objectMapper.readValue(is, CcspRequest.class); request = objectMapper.readValue(is, CcspRequest.class);
} catch (Exception e) { } catch (Exception e) {
logger.warn("[CCSP REQ INVÁLIDO] POST /ccsp/v1/sign-pdf de Origin: {} | Erro parsing: {}", origin, e.getMessage());
sendCcspError(exchange, 400, null, CcspErrorCode.SIGNATURE_FAILED, "Payload de requisição inválido."); sendCcspError(exchange, 400, null, CcspErrorCode.SIGNATURE_FAILED, "Payload de requisição inválido.");
return; return;
} }
int pdfLength = request.pdf() != null ? request.pdf().length() : 0;
logger.info("[CCSP REQ] POST /ccsp/v1/sign-pdf | Origin: {} | ReqId: {} | App: {} | Doc: '{}' | Base64: {} chars | CertHint: {}",
origin, request.requestId(), request.applicationId(), request.documentName(), pdfLength, request.certificateHint());
if (!request.isVersionSupported()) { if (!request.isVersionSupported()) {
sendCcspError(exchange, 400, request.requestId(), CcspErrorCode.COMMUNICATION_ERROR, sendCcspError(exchange, 400, request.requestId(), CcspErrorCode.COMMUNICATION_ERROR,
"Versão do protocolo não suportada: " + request.version()); "Versão do protocolo não suportada: " + request.version());
@@ -1028,6 +1037,22 @@ public class CcspServer {
try (OutputStream os = exchange.getResponseBody()) { try (OutputStream os = exchange.getResponseBody()) {
os.write(bytes); os.write(bytes);
} }
String path = exchange.getRequestURI().getPath();
if (data instanceof CcspResponse resp) {
if ("signed".equalsIgnoreCase(resp.status())) {
logger.info("[CCSP RESP] {} -> HTTP {} | ReqId: {} | Status: signed | Resposta: {} bytes | SHA-256: {}",
path, statusCode, resp.requestId(), bytes.length, resp.sha256() != null ? resp.sha256() : "n/a");
} else if ("error".equalsIgnoreCase(resp.status())) {
logger.warn("[CCSP RESP ERROR] {} -> HTTP {} | ReqId: {} | Code: {} | Msg: {}",
path, statusCode, resp.requestId(), resp.errorCode(), resp.message());
} else {
logger.info("[CCSP RESP] {} -> HTTP {} | ReqId: {} | Status: {} | Resposta: {} bytes",
path, statusCode, resp.requestId(), resp.status(), bytes.length);
}
} else {
logger.info("[CCSP RESP] {} -> HTTP {} | Resposta: {} bytes", path, statusCode, bytes.length);
}
} }
private void sendErrorResponse(HttpExchange exchange, int httpStatus, String code, String message) throws IOException { private void sendErrorResponse(HttpExchange exchange, int httpStatus, String code, String message) throws IOException {
@@ -425,6 +425,9 @@ public class CyberCoreDesktopApplication extends Application {
byte[] digestBytes; byte[] digestBytes;
if (request.digest() != null && !request.digest().isBlank()) { if (request.digest() != null && !request.digest().isBlank()) {
digestBytes = Base64.getDecoder().decode(request.digest()); digestBytes = Base64.getDecoder().decode(request.digest());
} else if (request.pdf() != null && !request.pdf().isBlank()) {
byte[] rawPdf = Base64.getDecoder().decode(request.pdf());
digestBytes = MessageDigest.getInstance("SHA-256").digest(rawPdf);
} else if (request.challenge() != null && !request.challenge().isBlank()) { } else if (request.challenge() != null && !request.challenge().isBlank()) {
digestBytes = MessageDigest.getInstance("SHA-256") digestBytes = MessageDigest.getInstance("SHA-256")
.digest(request.challenge().getBytes(StandardCharsets.UTF_8)); .digest(request.challenge().getBytes(StandardCharsets.UTF_8));
+4 -3
View File
@@ -1250,11 +1250,12 @@
pdfAlert.className = 'alert alert-success'; pdfAlert.className = 'alert alert-success';
pdfAlert.textContent = '✓ Documento PDF assinado com sucesso via PAdES (ISO 32000)!'; pdfAlert.textContent = '✓ Documento PDF assinado com sucesso via PAdES (ISO 32000)!';
currentSignedPdfBase64 = result.signed_pdf; const signedPdfBase64 = result.signedPdf || result.signed_pdf || '';
currentSignedPdfBase64 = signedPdfBase64;
pdfResultCard.style.display = 'block'; pdfResultCard.style.display = 'block';
pdfResultSize.textContent = (result.signed_pdf.length * 0.75 / 1024).toFixed(1) + ' KB'; pdfResultSize.textContent = (signedPdfBase64.length * 0.75 / 1024).toFixed(1) + ' KB';
pdfResultSha256.textContent = result.sha256 || 'Calculado com sucesso'; pdfResultSha256.textContent = result.sha256 || 'Calculado com sucesso';
pdfResultBase64.textContent = result.signed_pdf; pdfResultBase64.textContent = signedPdfBase64;
pdfResultCard.scrollIntoView({ behavior: 'smooth' }); pdfResultCard.scrollIntoView({ behavior: 'smooth' });
} catch (err) { } catch (err) {
pdfAlert.className = 'alert alert-error'; pdfAlert.className = 'alert alert-error';
+2 -2
View File
@@ -35,8 +35,8 @@ export class PdfSealDesigner {
textColor: '#0f172a', textColor: '#0f172a',
iconStyle: 'shield', iconStyle: 'shield',
customLogoBase64: null, customLogoBase64: null,
customHeader: 'CYBERCORE • ICP-BRASIL', customHeader: 'DOCUMENTO ASSINADO DIGITALMENTE',
customFooter: 'Validade jurídica assegurada pela MP nº 2.200-2/2001', customFooter: 'Verifique a autenticidade da assinatura eletrônica em https://validar.iti.gov.br',
customFieldLabel: 'Cargo', customFieldLabel: 'Cargo',
customFieldValue: 'Diretor Responsável', customFieldValue: 'Diretor Responsável',
defaultCpfMode: 'MASKED', defaultCpfMode: 'MASKED',
+1
View File
@@ -392,6 +392,7 @@ export class CyberCoreSigner {
requestId: resp.request_id, requestId: resp.request_id,
status: resp.status, status: resp.status,
signedPdf: signedPdfBase64, signedPdf: signedPdfBase64,
signed_pdf: signedPdfBase64,
sha256: resp.sha256, sha256: resp.sha256,
signature: resp.signature, signature: resp.signature,
certificate: resp.certificate, certificate: resp.certificate,