mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-03 05:10:16 +03:00
refactor(api): replace deprecated APIs with their modern equivalents (#6434)
# Description of Changes This PR resolves deprecation warnings and addresses compiler errors resulting from the transition to Spring Security 7.x., as well Jackson 3 and general Java. * Replaced all usages of `asText()`/`isTextual()` with `asString()`/`isString()` in JSON parsing logic across `FormPayloadParser.java`, `ApiEndpoint.java`, and `KeygenLicenseVerifier.java` to ensure consistent and type-safe string * Updated `CustomSaml2AuthenticatedPrincipal` to implement `Saml2ResponseAssertionAccessor`, added a `responseValue` field, and provided additional getter methods and type-safe attribute accessors. * Switched from constructing `URL` objects directly from strings to using `URI.create(...).toURL()` in `UIDataTessdataController.java` for improved URL safety and parsing. <!-- Please provide a summary of the changes, including: - What was changed - Why the change was made - Any challenges encountered Closes #(issue_number) --> --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [x] I have performed a self-review of my own code - [x] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have run `task check` to verify linters, typechecks, and tests pass - [x] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details.
This commit is contained in:
+8
-8
@@ -117,8 +117,8 @@ final class FormPayloadParser {
|
||||
names.add(single);
|
||||
}
|
||||
}
|
||||
} else if (root.isTextual()) {
|
||||
final String single = trimToNull(root.asText(""));
|
||||
} else if (root.isString()) {
|
||||
final String single = trimToNull(root.asString(""));
|
||||
if (single != null) {
|
||||
names.add(single);
|
||||
}
|
||||
@@ -197,8 +197,8 @@ final class FormPayloadParser {
|
||||
if (node == null || node.isNull()) {
|
||||
return null;
|
||||
}
|
||||
if (node.isTextual()) {
|
||||
return trimToEmpty(node.asText(""));
|
||||
if (node.isString()) {
|
||||
return trimToEmpty(node.asString(""));
|
||||
}
|
||||
if (node.isNumber()) {
|
||||
return node.numberValue().toString();
|
||||
@@ -207,7 +207,7 @@ final class FormPayloadParser {
|
||||
return Boolean.toString(node.booleanValue());
|
||||
}
|
||||
// Fallback for other scalar-like nodes
|
||||
return trimToEmpty(node.asText(""));
|
||||
return trimToEmpty(node.asString(""));
|
||||
}
|
||||
|
||||
private static void collectNames(JsonNode arrayNode, Set<String> sink) {
|
||||
@@ -227,8 +227,8 @@ final class FormPayloadParser {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (node.isTextual()) {
|
||||
return trimToNull(node.asText(""));
|
||||
if (node.isString()) {
|
||||
return trimToNull(node.asString(""));
|
||||
}
|
||||
|
||||
if (node.isObject()) {
|
||||
@@ -269,7 +269,7 @@ final class FormPayloadParser {
|
||||
final JsonNode v = objectNode.get(key);
|
||||
if (v == null || v.isNull()) {
|
||||
result.put(key, null);
|
||||
} else if (v.isTextual() || v.isNumber() || v.isBoolean()) {
|
||||
} else if (v.isString() || v.isNumber() || v.isBoolean()) {
|
||||
result.put(key, coerceScalarToString(v));
|
||||
} else {
|
||||
result.put(key, v.toString());
|
||||
|
||||
@@ -18,10 +18,10 @@ public class ApiEndpoint {
|
||||
postNode.path("parameters")
|
||||
.forEach(
|
||||
paramNode -> {
|
||||
String paramName = paramNode.path("name").asText("");
|
||||
String paramName = paramNode.path("name").asString("");
|
||||
parameters.put(paramName, paramNode);
|
||||
});
|
||||
this.description = postNode.path("description").asText("");
|
||||
this.description = postNode.path("description").asString("");
|
||||
}
|
||||
|
||||
public boolean areParametersValid(Map<String, Object> providedParams) {
|
||||
|
||||
+21
-21
@@ -134,9 +134,9 @@ public class KeygenLicenseVerifier {
|
||||
|
||||
try {
|
||||
JsonNode attrs = objectMapper.readTree(payload);
|
||||
encryptedData = attrs.path("enc").asText("");
|
||||
encodedSignature = attrs.path("sig").asText("");
|
||||
algorithm = attrs.path("alg").asText("");
|
||||
encryptedData = attrs.path("enc").asString("");
|
||||
encodedSignature = attrs.path("sig").asString("");
|
||||
algorithm = attrs.path("alg").asString("");
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to parse license file: {}", e.getMessage());
|
||||
return false;
|
||||
@@ -219,11 +219,11 @@ public class KeygenLicenseVerifier {
|
||||
String issuedStr =
|
||||
metaObj.path("issued").isNull()
|
||||
? null
|
||||
: metaObj.path("issued").asText(null);
|
||||
: metaObj.path("issued").asString(null);
|
||||
String expiryStr =
|
||||
metaObj.path("expiry").isNull()
|
||||
? null
|
||||
: metaObj.path("expiry").asText(null);
|
||||
: metaObj.path("expiry").asString(null);
|
||||
|
||||
if (issuedStr != null && expiryStr != null) {
|
||||
java.time.Instant issued = java.time.Instant.parse(issuedStr);
|
||||
@@ -287,7 +287,7 @@ public class KeygenLicenseVerifier {
|
||||
}
|
||||
|
||||
// Check license status if available
|
||||
String status = attributesObj.path("status").asText(null);
|
||||
String status = attributesObj.path("status").asString(null);
|
||||
if (status != null
|
||||
&& !"ACTIVE".equals(status)
|
||||
&& !"EXPIRING".equals(status)) { // Accept "EXPIRING" status as valid
|
||||
@@ -381,7 +381,7 @@ public class KeygenLicenseVerifier {
|
||||
|
||||
JsonNode licenseObj = licenseData.path("license");
|
||||
if (licenseObj.isMissingNode() || !licenseObj.isObject()) {
|
||||
String id = licenseData.path("id").asText(null);
|
||||
String id = licenseData.path("id").asString(null);
|
||||
if (id != null) {
|
||||
log.info("Found license ID: {}", id);
|
||||
licenseObj = licenseData; // Use the root object as the license object
|
||||
@@ -391,7 +391,7 @@ public class KeygenLicenseVerifier {
|
||||
}
|
||||
}
|
||||
|
||||
String licenseId = licenseObj.path("id").asText("unknown");
|
||||
String licenseId = licenseObj.path("id").asString("unknown");
|
||||
log.info("Processing license with ID: {}", licenseId);
|
||||
|
||||
// Check for floating license in license object
|
||||
@@ -402,7 +402,7 @@ public class KeygenLicenseVerifier {
|
||||
}
|
||||
|
||||
// Check expiry date
|
||||
String expiryStr = licenseObj.path("expiry").asText(null);
|
||||
String expiryStr = licenseObj.path("expiry").asString(null);
|
||||
if (expiryStr != null && !"null".equals(expiryStr)) {
|
||||
java.time.Instant expiry = java.time.Instant.parse(expiryStr);
|
||||
java.time.Instant now = java.time.Instant.now();
|
||||
@@ -420,7 +420,7 @@ public class KeygenLicenseVerifier {
|
||||
// Extract account, product, policy info
|
||||
JsonNode accountObj = licenseData.path("account");
|
||||
if (!accountObj.isMissingNode() && accountObj.isObject()) {
|
||||
String accountId = accountObj.path("id").asText("unknown");
|
||||
String accountId = accountObj.path("id").asString("unknown");
|
||||
log.info("License belongs to account: {}", accountId);
|
||||
|
||||
// Verify this matches your expected account ID
|
||||
@@ -433,7 +433,7 @@ public class KeygenLicenseVerifier {
|
||||
// Extract policy information if available
|
||||
JsonNode policyObj = licenseData.path("policy");
|
||||
if (!policyObj.isMissingNode() && policyObj.isObject()) {
|
||||
String policyId = policyObj.path("id").asText("unknown");
|
||||
String policyId = policyObj.path("id").asString("unknown");
|
||||
log.info("License uses policy: {}", policyId);
|
||||
|
||||
// Check for floating license in policy
|
||||
@@ -503,9 +503,9 @@ public class KeygenLicenseVerifier {
|
||||
validateLicense(licenseKey, machineFingerprint, context);
|
||||
if (validationResponse != null) {
|
||||
boolean isValid = validationResponse.path("meta").path("valid").asBoolean();
|
||||
String licenseId = validationResponse.path("data").path("id").asText("");
|
||||
String licenseId = validationResponse.path("data").path("id").asString("");
|
||||
if (!isValid) {
|
||||
String code = validationResponse.path("meta").path("code").asText("");
|
||||
String code = validationResponse.path("meta").path("code").asString("");
|
||||
log.info(code);
|
||||
if ("NO_MACHINE".equals(code)
|
||||
|| "NO_MACHINES".equals(code)
|
||||
@@ -589,8 +589,8 @@ public class KeygenLicenseVerifier {
|
||||
JsonNode metaNode = jsonResponse.path("meta");
|
||||
boolean isValid = metaNode.path("valid").asBoolean();
|
||||
|
||||
String detail = metaNode.path("detail").asText("");
|
||||
String code = metaNode.path("code").asText("");
|
||||
String detail = metaNode.path("detail").asString("");
|
||||
String code = metaNode.path("code").asString("");
|
||||
|
||||
log.info("License validity: {}", isValid);
|
||||
log.info("Validation detail: {}", detail);
|
||||
@@ -614,7 +614,7 @@ public class KeygenLicenseVerifier {
|
||||
|
||||
if (includedNode.isArray()) {
|
||||
for (JsonNode node : includedNode) {
|
||||
if ("policies".equals(node.path("type").asText(""))) {
|
||||
if ("policies".equals(node.path("type").asString(""))) {
|
||||
policyNode = node;
|
||||
break;
|
||||
}
|
||||
@@ -700,9 +700,9 @@ public class KeygenLicenseVerifier {
|
||||
|
||||
for (JsonNode machine : machines) {
|
||||
if (machineFingerprint.equals(
|
||||
machine.path("attributes").path("fingerprint").asText(""))) {
|
||||
machine.path("attributes").path("fingerprint").asString(""))) {
|
||||
isCurrentMachineActivated = true;
|
||||
currentMachineId = machine.path("id").asText("");
|
||||
currentMachineId = machine.path("id").asString("");
|
||||
log.info(
|
||||
"Current machine is already activated with ID: {}",
|
||||
currentMachineId);
|
||||
@@ -729,14 +729,14 @@ public class KeygenLicenseVerifier {
|
||||
|
||||
for (JsonNode machine : machines) {
|
||||
String createdStr =
|
||||
machine.path("attributes").path("created").asText(null);
|
||||
machine.path("attributes").path("created").asString(null);
|
||||
if (createdStr != null && !createdStr.isEmpty()) {
|
||||
try {
|
||||
java.time.Instant createdTime =
|
||||
java.time.Instant.parse(createdStr);
|
||||
if (oldestTime == null || createdTime.isBefore(oldestTime)) {
|
||||
oldestTime = createdTime;
|
||||
oldestMachineId = machine.path("id").asText("");
|
||||
oldestMachineId = machine.path("id").asString("");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn(
|
||||
@@ -750,7 +750,7 @@ public class KeygenLicenseVerifier {
|
||||
if (oldestMachineId == null) {
|
||||
log.warn(
|
||||
"Could not determine oldest machine by timestamp, using first machine in list");
|
||||
oldestMachineId = machines.path(0).path("id").asText("");
|
||||
oldestMachineId = machines.path(0).path("id").asString("");
|
||||
}
|
||||
|
||||
log.info("Deregistering machine with ID: {}", oldestMachineId);
|
||||
|
||||
+3
-2
@@ -3,6 +3,7 @@ package stirling.software.proprietary.security.controller.api;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -150,7 +151,7 @@ public class UIDataTessdataController {
|
||||
protected boolean downloadLanguageFile(String safeLang, Path targetFile, String downloadUrl) {
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
URL url = new URL(downloadUrl);
|
||||
URL url = URI.create(downloadUrl).toURL();
|
||||
connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setRequestProperty("User-Agent", "Stirling-PDF-App");
|
||||
@@ -199,7 +200,7 @@ public class UIDataTessdataController {
|
||||
String apiUrl = "https://api.github.com/repos/tesseract-ocr/tessdata/contents";
|
||||
HttpURLConnection connection = null;
|
||||
try {
|
||||
URL url = new URL(apiUrl);
|
||||
URL url = URI.create(apiUrl).toURL();
|
||||
connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("GET");
|
||||
connection.setRequestProperty("User-Agent", "Stirling-PDF-App");
|
||||
|
||||
+34
-3
@@ -5,15 +5,17 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
|
||||
import org.springframework.security.core.AuthenticatedPrincipal;
|
||||
import org.springframework.security.saml2.provider.service.authentication.Saml2ResponseAssertionAccessor;
|
||||
|
||||
@ConditionalOnProperty(name = "security.saml2.enabled", havingValue = "true")
|
||||
public record CustomSaml2AuthenticatedPrincipal(
|
||||
String name,
|
||||
Map<String, List<Object>> attributes,
|
||||
String nameId,
|
||||
List<String> sessionIndexes)
|
||||
implements Saml2AuthenticatedPrincipal, Serializable {
|
||||
List<String> sessionIndexes,
|
||||
String responseValue)
|
||||
implements Saml2ResponseAssertionAccessor, AuthenticatedPrincipal, Serializable {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -24,4 +26,33 @@ public record CustomSaml2AuthenticatedPrincipal(
|
||||
public Map<String, List<Object>> getAttributes() {
|
||||
return this.attributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameId() {
|
||||
return this.nameId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSessionIndexes() {
|
||||
return this.sessionIndexes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResponseValue() {
|
||||
return this.responseValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A> List<A> getAttribute(String name) {
|
||||
List<Object> values = this.attributes.get(name);
|
||||
return values != null ? (List<A>) values : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <A> A getFirstAttribute(String name) {
|
||||
List<Object> values = this.attributes.get(name);
|
||||
return values != null && !values.isEmpty() ? (A) values.get(0) : null;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -99,7 +99,11 @@ public class CustomSaml2ResponseAuthenticationConverter
|
||||
|
||||
CustomSaml2AuthenticatedPrincipal principal =
|
||||
new CustomSaml2AuthenticatedPrincipal(
|
||||
userIdentifier, attributes, userIdentifier, sessionIndexes);
|
||||
userIdentifier,
|
||||
attributes,
|
||||
userIdentifier,
|
||||
sessionIndexes,
|
||||
responseToken.getToken().getSaml2Response());
|
||||
|
||||
return new Saml2Authentication(
|
||||
principal,
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ public final class AiToolInputValidator {
|
||||
}
|
||||
if (file.getSize() > MAX_INPUT_FILE_BYTES) {
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.PAYLOAD_TOO_LARGE,
|
||||
HttpStatus.CONTENT_TOO_LARGE,
|
||||
"PDF exceeds maximum size of "
|
||||
+ (MAX_INPUT_FILE_BYTES / (1024 * 1024))
|
||||
+ " MB for AI tools");
|
||||
|
||||
+2
-2
@@ -774,7 +774,7 @@ public class AiWorkflowService {
|
||||
String[] errorHolder) {
|
||||
try {
|
||||
JsonNode node = objectMapper.readTree(line);
|
||||
String event = node.path("event").asText();
|
||||
String event = node.path("event").asString();
|
||||
switch (event) {
|
||||
case "progress" -> {
|
||||
AiEngineProgressDetail detail =
|
||||
@@ -785,7 +785,7 @@ public class AiWorkflowService {
|
||||
JsonNode response = node.path("response");
|
||||
resultHolder[0] = objectMapper.treeToValue(response, AiWorkflowResponse.class);
|
||||
}
|
||||
case "error" -> errorHolder[0] = node.path("message").asText("unknown error");
|
||||
case "error" -> errorHolder[0] = node.path("message").asString("unknown error");
|
||||
case "heartbeat" -> listener.onHeartbeat();
|
||||
default -> log.warn("Ignoring unknown engine stream event: {}", event);
|
||||
}
|
||||
|
||||
+3
-3
@@ -943,7 +943,7 @@ public class FileStorageService {
|
||||
long maxFileBytes = toBytes(quotas.getMaxFileMb());
|
||||
if (maxFileBytes > 0 && newBytes > maxFileBytes) {
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.PAYLOAD_TOO_LARGE, "Stored file exceeds the maximum size");
|
||||
HttpStatus.CONTENT_TOO_LARGE, "Stored file exceeds the maximum size");
|
||||
}
|
||||
|
||||
long delta = newBytes - existingBytes;
|
||||
@@ -956,7 +956,7 @@ public class FileStorageService {
|
||||
long currentBytes = storedFileRepository.sumStorageBytesByOwner(owner);
|
||||
if (currentBytes + delta > maxUserBytes) {
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.PAYLOAD_TOO_LARGE, "User storage quota exceeded");
|
||||
HttpStatus.CONTENT_TOO_LARGE, "User storage quota exceeded");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -965,7 +965,7 @@ public class FileStorageService {
|
||||
long totalBytes = storedFileRepository.sumStorageBytesTotal();
|
||||
if (totalBytes + delta > maxTotalBytes) {
|
||||
throw new ResponseStatusException(
|
||||
HttpStatus.PAYLOAD_TOO_LARGE, "System storage quota exceeded");
|
||||
HttpStatus.CONTENT_TOO_LARGE, "System storage quota exceeded");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1045,12 +1045,12 @@ public class SigningFinalizationService {
|
||||
if (certNode.has("p12Keystore")) {
|
||||
submission.setP12Keystore(
|
||||
metadataEncryptionService.decryptBytes(
|
||||
certNode.get("p12Keystore").asText()));
|
||||
certNode.get("p12Keystore").asString()));
|
||||
}
|
||||
if (certNode.has("jksKeystore")) {
|
||||
submission.setJksKeystore(
|
||||
metadataEncryptionService.decryptBytes(
|
||||
certNode.get("jksKeystore").asText()));
|
||||
certNode.get("jksKeystore").asString()));
|
||||
}
|
||||
return submission;
|
||||
}
|
||||
|
||||
+1
-1
@@ -235,7 +235,7 @@ class ProprietaryUIDataControllerMoreTest {
|
||||
|
||||
CustomSaml2AuthenticatedPrincipal principal =
|
||||
new CustomSaml2AuthenticatedPrincipal(
|
||||
"samluser", Map.of(), "nameId", List.of());
|
||||
"samluser", Map.of(), "nameId", List.of(), "response");
|
||||
Authentication auth =
|
||||
new UsernamePasswordAuthenticationToken(principal, null, List.of());
|
||||
|
||||
|
||||
+1
-1
@@ -75,6 +75,6 @@ class AiToolInputValidatorTest {
|
||||
assertThrows(
|
||||
ResponseStatusException.class,
|
||||
() -> AiToolInputValidator.validatePdfUpload(file));
|
||||
assertEquals(HttpStatus.PAYLOAD_TOO_LARGE, ex.getStatusCode());
|
||||
assertEquals(HttpStatus.CONTENT_TOO_LARGE, ex.getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user