diff --git a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java index a2e4a0b30..c128a1c1c 100644 --- a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java +++ b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java @@ -61,7 +61,10 @@ public class ApplicationProperties { private Mail mail = new Mail(); private Premium premium = new Premium(); + + @JsonIgnore // Deprecated - completely hidden from JSON serialization private EnterpriseEdition enterpriseEdition = new EnterpriseEdition(); + private AutoPipeline autoPipeline = new AutoPipeline(); private ProcessExecutor processExecutor = new ProcessExecutor(); diff --git a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/AdminSettingsController.java b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/AdminSettingsController.java index f1f2cabc5..8fb0e5e7f 100644 --- a/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/AdminSettingsController.java +++ b/app/proprietary/src/main/java/stirling/software/proprietary/security/controller/api/AdminSettingsController.java @@ -61,10 +61,11 @@ public class AdminSettingsController { "clientsecret", "apisecret", "secret", // API tokens "apikey", "accesstoken", "refreshtoken", "token", - // Specific secret keys (not all keys) + // Specific secret keys (not all keys, and excluding premium.key) "key", // automaticallyGenerated.key "enterprisekey", "licensekey" )); + @GetMapping @Operation( @@ -519,21 +520,27 @@ public class AdminSettingsController { } /** - * Recursively mask sensitive fields in a settings map. + * Recursively mask sensitive fields in settings map. * Sensitive fields are replaced with a status indicator showing if they're configured. */ @SuppressWarnings("unchecked") private Map maskSensitiveFields(Map settings) { + return maskSensitiveFieldsWithPath(settings, ""); + } + + @SuppressWarnings("unchecked") + private Map maskSensitiveFieldsWithPath(Map settings, String path) { Map masked = new HashMap<>(); for (Map.Entry entry : settings.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); + String currentPath = path.isEmpty() ? key : path + "." + key; if (value instanceof Map) { // Recursively mask nested objects - masked.put(key, maskSensitiveFields((Map) value)); - } else if (isSensitiveField(key)) { + masked.put(key, maskSensitiveFieldsWithPath((Map) value, currentPath)); + } else if (isSensitiveFieldWithPath(key, currentPath)) { // Mask sensitive fields with status indicator masked.put(key, createMaskedValue(value)); } else { @@ -546,27 +553,33 @@ public class AdminSettingsController { } /** - * Check if a field name indicates sensitive data (actual secrets, not identifiers) + * Check if a field name indicates sensitive data with full path context */ - private boolean isSensitiveField(String fieldName) { + private boolean isSensitiveFieldWithPath(String fieldName, String fullPath) { String lowerField = fieldName.toLowerCase(); + String lowerPath = fullPath.toLowerCase(); + + // Don't mask premium.key specifically + if (lowerField.equals("key") && lowerPath.equals("premium.key")) { + return false; + } // Direct match with sensitive field names if (SENSITIVE_FIELD_NAMES.contains(lowerField)) { return true; } - // Check for fields containing 'password' or 'secret' (but not 'key' as that's too broad) + // Check for fields containing 'password' or 'secret' return lowerField.contains("password") || lowerField.contains("secret"); } /** - * Create a masked representation showing if the field is configured + * Create a masked representation for sensitive fields */ private Object createMaskedValue(Object originalValue) { if (originalValue == null || (originalValue instanceof String && ((String) originalValue).trim().isEmpty())) { - return "[NOT_CONFIGURED]"; + return originalValue; // Keep empty/null values as-is } else { return "[CONFIGURED - " + originalValue.getClass().getSimpleName().toUpperCase() + "]"; }