From a949019d5d063dcf12fde5445a2342527ce80f05 Mon Sep 17 00:00:00 2001 From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com.> Date: Tue, 16 Sep 2025 14:22:49 +0100 Subject: [PATCH] conditionalCert --- .../controller/api/misc/ConfigController.java | 19 ++++++++- .../api/ServerCertificateController.java | 26 ++++++------ .../CertificateTypeSettings.tsx | 40 ++++++++++++------- frontend/src/hooks/useAppConfig.ts | 1 + 4 files changed, 57 insertions(+), 29 deletions(-) diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java index bc9174476..150cbfaca 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java @@ -18,17 +18,30 @@ import lombok.RequiredArgsConstructor; import stirling.software.SPDF.config.EndpointConfiguration; import stirling.software.common.configuration.AppConfig; import stirling.software.common.model.ApplicationProperties; +import stirling.software.common.service.ServerCertificateServiceInterface; @RestController @Tag(name = "Config", description = "Configuration APIs") @RequestMapping("/api/v1/config") -@RequiredArgsConstructor @Hidden public class ConfigController { private final ApplicationProperties applicationProperties; private final ApplicationContext applicationContext; private final EndpointConfiguration endpointConfiguration; + private final ServerCertificateServiceInterface serverCertificateService; + + public ConfigController( + ApplicationProperties applicationProperties, + ApplicationContext applicationContext, + EndpointConfiguration endpointConfiguration, + @org.springframework.beans.factory.annotation.Autowired(required = false) + ServerCertificateServiceInterface serverCertificateService) { + this.applicationProperties = applicationProperties; + this.applicationContext = applicationContext; + this.endpointConfiguration = endpointConfiguration; + this.serverCertificateService = serverCertificateService; + } @GetMapping("/app-config") public ResponseEntity> getAppConfig() { @@ -62,6 +75,10 @@ public class ConfigController { // Premium/Enterprise settings configData.put("premiumEnabled", applicationProperties.getPremium().isEnabled()); + // Server certificate settings + configData.put("serverCertificateEnabled", + serverCertificateService != null && serverCertificateService.isEnabled()); + // Legal settings configData.put( "termsAndConditions", applicationProperties.getLegal().getTermsAndConditions()); diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/ServerCertificateController.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/ServerCertificateController.java index d2460a9b6..4aae955e2 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/ServerCertificateController.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/ServerCertificateController.java @@ -14,7 +14,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import stirling.software.common.service.ServerCertificateService; +import stirling.software.common.service.ServerCertificateServiceInterface; @RestController @RequestMapping("/api/v1/admin/server-certificate") @@ -26,16 +26,16 @@ import stirling.software.common.service.ServerCertificateService; @PreAuthorize("hasRole('ADMIN')") public class ServerCertificateController { - private final ServerCertificateService serverCertificateService; + private final ServerCertificateServiceInterface serverCertificateService; @GetMapping("/info") @Operation( summary = "Get server certificate information", description = "Returns information about the current server certificate") - public ResponseEntity + public ResponseEntity getServerCertificateInfo() { try { - ServerCertificateService.ServerCertificateInfo info = + ServerCertificateServiceInterface.ServerCertificateInfo info = serverCertificateService.getServerCertificateInfo(); return ResponseEntity.ok(info); } catch (Exception e) { @@ -109,27 +109,27 @@ public class ServerCertificateController { } } - @GetMapping("/public-key") + @GetMapping("/certificate") @Operation( - summary = "Download server certificate public key", + summary = "Download server certificate", description = - "Download the public key of the server certificate for validation purposes") - public ResponseEntity getServerCertificatePublicKey() { + "Download the server certificate in DER format for validation purposes") + public ResponseEntity getServerCertificate() { try { if (!serverCertificateService.hasServerCertificate()) { return ResponseEntity.notFound().build(); } - byte[] publicKey = serverCertificateService.getServerCertificatePublicKey(); + byte[] certificate = serverCertificateService.getServerCertificatePublicKey(); return ResponseEntity.ok() .header( HttpHeaders.CONTENT_DISPOSITION, - "attachment; filename=\"server-cert.crt\"") - .contentType(MediaType.APPLICATION_OCTET_STREAM) - .body(publicKey); + "attachment; filename=\"server-cert.cer\"") + .contentType(MediaType.valueOf("application/pkix-cert")) + .body(certificate); } catch (Exception e) { - log.error("Failed to get server certificate public key", e); + log.error("Failed to get server certificate", e); return ResponseEntity.internalServerError().build(); } } diff --git a/frontend/src/components/tools/manageSignatures/CertificateTypeSettings.tsx b/frontend/src/components/tools/manageSignatures/CertificateTypeSettings.tsx index 9d9efd2cb..887a7f528 100644 --- a/frontend/src/components/tools/manageSignatures/CertificateTypeSettings.tsx +++ b/frontend/src/components/tools/manageSignatures/CertificateTypeSettings.tsx @@ -1,5 +1,6 @@ import { Stack, Button } from "@mantine/core"; import { ManageSignaturesParameters } from "../../../hooks/tools/manageSignatures/useManageSignaturesParameters"; +import { useAppConfig } from "../../../hooks/useAppConfig"; interface CertificateTypeSettingsProps { parameters: ManageSignaturesParameters; @@ -8,6 +9,13 @@ interface CertificateTypeSettingsProps { } const CertificateTypeSettings = ({ parameters, onParameterChange, disabled = false }: CertificateTypeSettingsProps) => { + const { config } = useAppConfig(); + const isServerCertificateEnabled = config?.serverCertificateEnabled ?? false; + + // Reset to MANUAL if AUTO is selected but feature is disabled + if (parameters.signMode === 'AUTO' && !isServerCertificateEnabled) { + onParameterChange('signMode', 'MANUAL'); + } return ( @@ -29,21 +37,23 @@ const CertificateTypeSettings = ({ parameters, onParameterChange, disabled = fal Manual - + {isServerCertificateEnabled && ( + + )} ); diff --git a/frontend/src/hooks/useAppConfig.ts b/frontend/src/hooks/useAppConfig.ts index 899038f51..cb23cfb60 100644 --- a/frontend/src/hooks/useAppConfig.ts +++ b/frontend/src/hooks/useAppConfig.ts @@ -23,6 +23,7 @@ export interface AppConfig { license?: string; GoogleDriveEnabled?: boolean; SSOAutoLogin?: boolean; + serverCertificateEnabled?: boolean; error?: string; }