mirror of
				https://github.com/Frooodle/Stirling-PDF.git
				synced 2025-10-25 11:17:28 +02:00 
			
		
		
		
	Floating keys for pro users (#3535)
# Description of Changes Please provide a summary of the changes, including: - What was changed - Why the change was made - Any challenges encountered Closes #(issue_number) --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] 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/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] 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/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### 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 tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details.
This commit is contained in:
		
							parent
							
								
									b26ecbc3b7
								
							
						
					
					
						commit
						f94b8c3b22
					
				| @ -29,7 +29,7 @@ ext { | ||||
| } | ||||
| 
 | ||||
| group = "stirling.software" | ||||
| version = "0.46.1" | ||||
| version = "0.46.2" | ||||
| 
 | ||||
| java { | ||||
|     // 17 is lowest but we support and recommend 21 | ||||
|  | ||||
| @ -47,31 +47,47 @@ public class KeygenLicenseVerifier { | ||||
| 
 | ||||
|     private static final ObjectMapper objectMapper = new ObjectMapper(); | ||||
|     private final ApplicationProperties applicationProperties; | ||||
|      | ||||
|     // Shared HTTP client for connection pooling | ||||
|     private static final HttpClient httpClient = HttpClient.newBuilder() | ||||
|             .version(HttpClient.Version.HTTP_2) | ||||
|             .connectTimeout(java.time.Duration.ofSeconds(10)) | ||||
|             .build(); | ||||
|              | ||||
|     // License metadata context class to avoid shared mutable state | ||||
|     private static class LicenseContext { | ||||
|         private boolean isFloatingLicense = false; | ||||
|         private int maxMachines = 1; // Default to 1 if not specified | ||||
|         private boolean isEnterpriseLicense = false; | ||||
|          | ||||
|         public LicenseContext() {} | ||||
|     } | ||||
| 
 | ||||
|     public License verifyLicense(String licenseKeyOrCert) { | ||||
|         License license; | ||||
|         LicenseContext context = new LicenseContext(); | ||||
| 
 | ||||
|         if (isCertificateLicense(licenseKeyOrCert)) { | ||||
|             log.info("Detected certificate-based license. Processing..."); | ||||
|             boolean isValid = verifyCertificateLicense(licenseKeyOrCert); | ||||
|             boolean isValid = verifyCertificateLicense(licenseKeyOrCert, context); | ||||
|             if (isValid) { | ||||
|                 license = isEnterpriseLicense ? License.ENTERPRISE : License.PRO; | ||||
|                 license = context.isEnterpriseLicense ? License.ENTERPRISE : License.PRO; | ||||
|             } else { | ||||
|                 license = License.NORMAL; | ||||
|             } | ||||
|         } else if (isJWTLicense(licenseKeyOrCert)) { | ||||
|             log.info("Detected JWT-style license key. Processing..."); | ||||
|             boolean isValid = verifyJWTLicense(licenseKeyOrCert); | ||||
|             boolean isValid = verifyJWTLicense(licenseKeyOrCert, context); | ||||
|             if (isValid) { | ||||
|                 license = isEnterpriseLicense ? License.ENTERPRISE : License.PRO; | ||||
|                 license = context.isEnterpriseLicense ? License.ENTERPRISE : License.PRO; | ||||
|             } else { | ||||
|                 license = License.NORMAL; | ||||
|             } | ||||
|         } else { | ||||
|             log.info("Detected standard license key. Processing..."); | ||||
|             boolean isValid = verifyStandardLicense(licenseKeyOrCert); | ||||
|             boolean isValid = verifyStandardLicense(licenseKeyOrCert, context); | ||||
|             if (isValid) { | ||||
|                 license = isEnterpriseLicense ? License.ENTERPRISE : License.PRO; | ||||
|                 license = context.isEnterpriseLicense ? License.ENTERPRISE : License.PRO; | ||||
|             } else { | ||||
|                 license = License.NORMAL; | ||||
|             } | ||||
| @ -79,7 +95,7 @@ public class KeygenLicenseVerifier { | ||||
|         return license; | ||||
|     } | ||||
| 
 | ||||
|     private boolean isEnterpriseLicense = false; | ||||
|     // Removed instance field for isEnterpriseLicense, now using LicenseContext | ||||
| 
 | ||||
|     private boolean isCertificateLicense(String license) { | ||||
|         return license != null && license.trim().startsWith(CERT_PREFIX); | ||||
| @ -89,7 +105,7 @@ public class KeygenLicenseVerifier { | ||||
|         return license != null && license.trim().startsWith(JWT_PREFIX); | ||||
|     } | ||||
| 
 | ||||
|     private boolean verifyCertificateLicense(String licenseFile) { | ||||
|     private boolean verifyCertificateLicense(String licenseFile, LicenseContext context) { | ||||
|         try { | ||||
|             String encodedPayload = licenseFile; | ||||
|             // Remove the header | ||||
| @ -144,7 +160,7 @@ public class KeygenLicenseVerifier { | ||||
|             } | ||||
| 
 | ||||
|             // Process the certificate data | ||||
|             boolean isValid = processCertificateData(decodedData); | ||||
|             boolean isValid = processCertificateData(decodedData, context); | ||||
| 
 | ||||
|             return isValid; | ||||
|         } catch (Exception e) { | ||||
| @ -187,7 +203,7 @@ public class KeygenLicenseVerifier { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private boolean processCertificateData(String certData) { | ||||
|     private boolean processCertificateData(String certData, LicenseContext context) { | ||||
|         try { | ||||
|             JSONObject licenseData = new JSONObject(certData); | ||||
|             JSONObject metaObj = licenseData.optJSONObject("meta"); | ||||
| @ -229,15 +245,17 @@ public class KeygenLicenseVerifier { | ||||
|             if (attributesObj != null) { | ||||
|                 log.info("Found attributes in certificate data"); | ||||
| 
 | ||||
|                 // Check for floating license | ||||
|                 context.isFloatingLicense = attributesObj.optBoolean("floating", false); | ||||
|                 context.maxMachines = attributesObj.optInt("maxMachines", 1); | ||||
|                  | ||||
|                 // Extract metadata | ||||
|                 JSONObject metadataObj = attributesObj.optJSONObject("metadata"); | ||||
|                 if (metadataObj != null) { | ||||
|                     int users = metadataObj.optInt("users", 0); | ||||
|                     if (users > 0) { | ||||
|                         applicationProperties.getPremium().setMaxUsers(users); | ||||
|                         log.info("License allows for {} users", users); | ||||
|                     } | ||||
|                     isEnterpriseLicense = metadataObj.optBoolean("isEnterprise", false); | ||||
|                     int users = metadataObj.optInt("users", 1); | ||||
|                     applicationProperties.getPremium().setMaxUsers(users); | ||||
|                     log.info("License allows for {} users", users); | ||||
|                     context.isEnterpriseLicense = metadataObj.optBoolean("isEnterprise", false); | ||||
|                 } | ||||
| 
 | ||||
|                 // Check license status if available | ||||
| @ -257,7 +275,7 @@ public class KeygenLicenseVerifier { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private boolean verifyJWTLicense(String licenseKey) { | ||||
|     private boolean verifyJWTLicense(String licenseKey, LicenseContext context) { | ||||
|         try { | ||||
|             log.info("Verifying ED25519_SIGN format license key"); | ||||
| 
 | ||||
| @ -291,7 +309,7 @@ public class KeygenLicenseVerifier { | ||||
|             String payload = new String(payloadBytes); | ||||
| 
 | ||||
|             // Process the license payload | ||||
|             boolean isValid = processJWTLicensePayload(payload); | ||||
|             boolean isValid = processJWTLicensePayload(payload, context); | ||||
| 
 | ||||
|             return isValid; | ||||
|         } catch (Exception e) { | ||||
| @ -327,7 +345,7 @@ public class KeygenLicenseVerifier { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private boolean processJWTLicensePayload(String payload) { | ||||
|     private boolean processJWTLicensePayload(String payload, LicenseContext context) { | ||||
|         try { | ||||
|             log.info("Processing license payload: {}", payload); | ||||
| 
 | ||||
| @ -348,6 +366,13 @@ public class KeygenLicenseVerifier { | ||||
|             String licenseId = licenseObj.optString("id", "unknown"); | ||||
|             log.info("Processing license with ID: {}", licenseId); | ||||
| 
 | ||||
|             // Check for floating license in license object | ||||
|             context.isFloatingLicense = licenseObj.optBoolean("floating", false); | ||||
|             context.maxMachines = licenseObj.optInt("maxMachines", 1); | ||||
|             if (context.isFloatingLicense) { | ||||
|                 log.info("Detected floating license with max machines: {}", context.maxMachines); | ||||
|             } | ||||
| 
 | ||||
|             // Check expiry date | ||||
|             String expiryStr = licenseObj.optString("expiry", null); | ||||
|             if (expiryStr != null && !"null".equals(expiryStr)) { | ||||
| @ -383,9 +408,20 @@ public class KeygenLicenseVerifier { | ||||
|                 String policyId = policyObj.optString("id", "unknown"); | ||||
|                 log.info("License uses policy: {}", policyId); | ||||
| 
 | ||||
|                 // Check for floating license in policy | ||||
|                 boolean policyFloating = policyObj.optBoolean("floating", false); | ||||
|                 int policyMaxMachines = policyObj.optInt("maxMachines", 1); | ||||
|                  | ||||
|                 // Policy settings take precedence | ||||
|                 if (policyFloating) { | ||||
|                     context.isFloatingLicense = true; | ||||
|                     context.maxMachines = policyMaxMachines; | ||||
|                     log.info("Policy defines floating license with max machines: {}", context.maxMachines); | ||||
|                 } | ||||
|                  | ||||
|                 // Extract max users and isEnterprise from policy or metadata | ||||
|                 int users = policyObj.optInt("users", 0); | ||||
|                 isEnterpriseLicense = policyObj.optBoolean("isEnterprise", false); | ||||
|                 int users = policyObj.optInt("users", 1); | ||||
|                 context.isEnterpriseLicense = policyObj.optBoolean("isEnterprise", false); | ||||
| 
 | ||||
|                 if (users > 0) { | ||||
|                     applicationProperties.getPremium().setMaxUsers(users); | ||||
| @ -399,7 +435,7 @@ public class KeygenLicenseVerifier { | ||||
|                         log.info("License allows for {} users (from metadata)", users); | ||||
| 
 | ||||
|                         // Check for isEnterprise flag in metadata | ||||
|                         isEnterpriseLicense = metadata.optBoolean("isEnterprise", false); | ||||
|                         context.isEnterpriseLicense = metadata.optBoolean("isEnterprise", false); | ||||
|                     } else { | ||||
|                         // Default value | ||||
|                         applicationProperties.getPremium().setMaxUsers(1); | ||||
| @ -415,13 +451,13 @@ public class KeygenLicenseVerifier { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private boolean verifyStandardLicense(String licenseKey) { | ||||
|     private boolean verifyStandardLicense(String licenseKey, LicenseContext context) { | ||||
|         try { | ||||
|             log.info("Checking standard license key"); | ||||
|             String machineFingerprint = generateMachineFingerprint(); | ||||
| 
 | ||||
|             // First, try to validate the license | ||||
|             JsonNode validationResponse = validateLicense(licenseKey, machineFingerprint); | ||||
|             JsonNode validationResponse = validateLicense(licenseKey, machineFingerprint, context); | ||||
|             if (validationResponse != null) { | ||||
|                 boolean isValid = validationResponse.path("meta").path("valid").asBoolean(); | ||||
|                 String licenseId = validationResponse.path("data").path("id").asText(); | ||||
| @ -435,10 +471,10 @@ public class KeygenLicenseVerifier { | ||||
|                                 "License not activated for this machine. Attempting to" | ||||
|                                         + " activate..."); | ||||
|                         boolean activated = | ||||
|                                 activateMachine(licenseKey, licenseId, machineFingerprint); | ||||
|                                 activateMachine(licenseKey, licenseId, machineFingerprint, context); | ||||
|                         if (activated) { | ||||
|                             // Revalidate after activation | ||||
|                             validationResponse = validateLicense(licenseKey, machineFingerprint); | ||||
|                             validationResponse = validateLicense(licenseKey, machineFingerprint, context); | ||||
|                             isValid = | ||||
|                                     validationResponse != null | ||||
|                                             && validationResponse | ||||
| @ -458,9 +494,8 @@ public class KeygenLicenseVerifier { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private JsonNode validateLicense(String licenseKey, String machineFingerprint) | ||||
|     private JsonNode validateLicense(String licenseKey, String machineFingerprint, LicenseContext context) | ||||
|             throws Exception { | ||||
|         HttpClient client = HttpClient.newHttpClient(); | ||||
|         String requestBody = | ||||
|                 String.format( | ||||
|                         "{\"meta\":{\"key\":\"%s\",\"scope\":{\"fingerprint\":\"%s\"}}}", | ||||
| @ -479,7 +514,7 @@ public class KeygenLicenseVerifier { | ||||
|                         .POST(HttpRequest.BodyPublishers.ofString(requestBody)) | ||||
|                         .build(); | ||||
| 
 | ||||
|         HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | ||||
|         HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); | ||||
|         log.info("ValidateLicenseResponse body: {}", response.body()); | ||||
|         JsonNode jsonResponse = objectMapper.readTree(response.body()); | ||||
|         if (response.statusCode() == 200) { | ||||
| @ -492,19 +527,57 @@ public class KeygenLicenseVerifier { | ||||
|             log.info("License validity: " + isValid); | ||||
|             log.info("Validation detail: " + detail); | ||||
|             log.info("Validation code: " + code); | ||||
|              | ||||
|             // Check if the license itself has floating attribute | ||||
|             JsonNode licenseAttrs = jsonResponse.path("data").path("attributes"); | ||||
|             if (!licenseAttrs.isMissingNode()) { | ||||
|                 context.isFloatingLicense = licenseAttrs.path("floating").asBoolean(false); | ||||
|                 context.maxMachines = licenseAttrs.path("maxMachines").asInt(1); | ||||
|                  | ||||
|                 log.info("License floating (from license): {}, maxMachines: {}",  | ||||
|                         context.isFloatingLicense, context.maxMachines); | ||||
|             } | ||||
|              | ||||
|             // Also check the policy for floating license support if included | ||||
|             JsonNode includedNode = jsonResponse.path("included"); | ||||
|             JsonNode policyNode = null; | ||||
|              | ||||
|             if (includedNode.isArray()) { | ||||
|                 for (JsonNode node : includedNode) { | ||||
|                     if ("policies".equals(node.path("type").asText())) { | ||||
|                         policyNode = node; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             if (policyNode != null) { | ||||
|                 // Check if this is a floating license from policy | ||||
|                 boolean policyFloating = policyNode.path("attributes").path("floating").asBoolean(false); | ||||
|                 int policyMaxMachines = policyNode.path("attributes").path("maxMachines").asInt(1); | ||||
|                  | ||||
|                 // Policy takes precedence over license attributes | ||||
|                 if (policyFloating) { | ||||
|                     context.isFloatingLicense = true; | ||||
|                     context.maxMachines = policyMaxMachines; | ||||
|                 } | ||||
|                  | ||||
|                 log.info("License floating (from policy): {}, maxMachines: {}",  | ||||
|                         context.isFloatingLicense, context.maxMachines); | ||||
|             } | ||||
| 
 | ||||
|             // Extract user count | ||||
|             // Extract user count, default to 1 if not specified | ||||
|             int users = | ||||
|                     jsonResponse | ||||
|                             .path("data") | ||||
|                             .path("attributes") | ||||
|                             .path("metadata") | ||||
|                             .path("users") | ||||
|                             .asInt(0); | ||||
|                             .asInt(1); | ||||
|             applicationProperties.getPremium().setMaxUsers(users); | ||||
| 
 | ||||
|             // Extract isEnterprise flag | ||||
|             isEnterpriseLicense = | ||||
|             context.isEnterpriseLicense = | ||||
|                     jsonResponse | ||||
|                             .path("data") | ||||
|                             .path("attributes") | ||||
| @ -520,10 +593,87 @@ public class KeygenLicenseVerifier { | ||||
|         return jsonResponse; | ||||
|     } | ||||
| 
 | ||||
|     private boolean activateMachine(String licenseKey, String licenseId, String machineFingerprint) | ||||
|             throws Exception { | ||||
|         HttpClient client = HttpClient.newHttpClient(); | ||||
| 
 | ||||
|     private boolean activateMachine(String licenseKey, String licenseId, String machineFingerprint,  | ||||
|             LicenseContext context) throws Exception { | ||||
|         // For floating licenses, we first need to check if we need to deregister any machines | ||||
|         if (context.isFloatingLicense) { | ||||
|             log.info("Processing floating license activation. Max machines allowed: {}", context.maxMachines); | ||||
|              | ||||
|             // Get the current machines for this license | ||||
|             JsonNode machinesResponse = fetchMachinesForLicense(licenseKey, licenseId); | ||||
|             if (machinesResponse != null) { | ||||
|                 JsonNode machines = machinesResponse.path("data"); | ||||
|                 int currentMachines = machines.size(); | ||||
|                  | ||||
|                 log.info("Current machine count: {}, Max allowed: {}", currentMachines, context.maxMachines); | ||||
|                  | ||||
|                 // Check if the current fingerprint is already activated | ||||
|                 boolean isCurrentMachineActivated = false; | ||||
|                 String currentMachineId = null; | ||||
|                  | ||||
|                 for (JsonNode machine : machines) { | ||||
|                     if (machineFingerprint.equals(machine.path("attributes").path("fingerprint").asText())) { | ||||
|                         isCurrentMachineActivated = true; | ||||
|                         currentMachineId = machine.path("id").asText(); | ||||
|                         log.info("Current machine is already activated with ID: {}", currentMachineId); | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|                 // If the current machine is already activated, there's no need to do anything | ||||
|                 if (isCurrentMachineActivated) { | ||||
|                     log.info("Machine already activated. No action needed."); | ||||
|                     return true; | ||||
|                 } | ||||
|                  | ||||
|                 // If we've reached the max machines limit, we need to deregister the oldest machine | ||||
|                 if (currentMachines >= context.maxMachines) { | ||||
|                     log.info("Max machines reached. Deregistering oldest machine to make room for the new machine."); | ||||
|                      | ||||
|                     // Find the oldest machine based on creation timestamp | ||||
|                     if (machines.size() > 0) { | ||||
|                         // Find the machine with the oldest creation date | ||||
|                         String oldestMachineId = null; | ||||
|                         java.time.Instant oldestTime = null; | ||||
|                          | ||||
|                         for (JsonNode machine : machines) { | ||||
|                             String createdStr = machine.path("attributes").path("created").asText(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(); | ||||
|                                     } | ||||
|                                 } catch (Exception e) { | ||||
|                                     log.warn("Could not parse creation time for machine: {}", e.getMessage()); | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                          | ||||
|                         // If we couldn't determine the oldest by timestamp, use the first one | ||||
|                         if (oldestMachineId == null) { | ||||
|                             log.warn("Could not determine oldest machine by timestamp, using first machine in list"); | ||||
|                             oldestMachineId = machines.path(0).path("id").asText(); | ||||
|                         } | ||||
|                          | ||||
|                         log.info("Deregistering machine with ID: {}", oldestMachineId); | ||||
|                          | ||||
|                         boolean deregistered = deregisterMachine(licenseKey, oldestMachineId); | ||||
|                         if (!deregistered) { | ||||
|                             log.error("Failed to deregister machine. Cannot proceed with activation."); | ||||
|                             return false; | ||||
|                         } | ||||
|                         log.info("Machine deregistered successfully. Proceeding with activation of new machine."); | ||||
|                     } else { | ||||
|                         log.error("License has reached machine limit but no machines were found to deregister. This is unexpected."); | ||||
|                         // We'll still try to activate, but it might fail | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // Proceed with machine activation | ||||
|         String hostname; | ||||
|         try { | ||||
|             hostname = java.net.InetAddress.getLocalHost().getHostName(); | ||||
| @ -570,7 +720,7 @@ public class KeygenLicenseVerifier { | ||||
|                         .POST(HttpRequest.BodyPublishers.ofString(body.toString())) | ||||
|                         .build(); | ||||
| 
 | ||||
|         HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); | ||||
|         HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); | ||||
|         log.info("activateMachine Response body: " + response.body()); | ||||
|         if (response.statusCode() == 201) { | ||||
|             log.info("Machine activated successfully"); | ||||
| @ -588,4 +738,66 @@ public class KeygenLicenseVerifier { | ||||
|     private String generateMachineFingerprint() { | ||||
|         return GeneralUtils.generateMachineFingerprint(); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Fetches all machines associated with a specific license | ||||
|      *  | ||||
|      * @param licenseKey The license key to check | ||||
|      * @param licenseId The license ID  | ||||
|      * @return JsonNode containing the list of machines, or null if an error occurs | ||||
|      * @throws Exception if an error occurs during the HTTP request | ||||
|      */ | ||||
|     private JsonNode fetchMachinesForLicense(String licenseKey, String licenseId) throws Exception { | ||||
|         HttpRequest request = HttpRequest.newBuilder() | ||||
|                 .uri(URI.create(BASE_URL + "/" + ACCOUNT_ID + "/licenses/" + licenseId + "/machines")) | ||||
|                 .header("Content-Type", "application/vnd.api+json") | ||||
|                 .header("Accept", "application/vnd.api+json") | ||||
|                 .header("Authorization", "License " + licenseKey) | ||||
|                 .GET() | ||||
|                 .build(); | ||||
|                  | ||||
|         HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); | ||||
|         log.info("fetchMachinesForLicense Response body: {}", response.body()); | ||||
|          | ||||
|         if (response.statusCode() == 200) { | ||||
|             return objectMapper.readTree(response.body()); | ||||
|         } else { | ||||
|             log.error("Error fetching machines for license. Status code: {}, error: {}",  | ||||
|                     response.statusCode(), response.body()); | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Deregisters a machine from a license | ||||
|      *  | ||||
|      * @param licenseKey The license key | ||||
|      * @param machineId The ID of the machine to deregister | ||||
|      * @return true if deregistration was successful, false otherwise | ||||
|      */ | ||||
|     private boolean deregisterMachine(String licenseKey, String machineId) { | ||||
|         try { | ||||
|             HttpRequest request = HttpRequest.newBuilder() | ||||
|                     .uri(URI.create(BASE_URL + "/" + ACCOUNT_ID + "/machines/" + machineId)) | ||||
|                     .header("Content-Type", "application/vnd.api+json") | ||||
|                     .header("Accept", "application/vnd.api+json") | ||||
|                     .header("Authorization", "License " + licenseKey) | ||||
|                     .DELETE() | ||||
|                     .build(); | ||||
|              | ||||
|             HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); | ||||
|              | ||||
|             if (response.statusCode() == 204) { | ||||
|                 log.info("Machine {} successfully deregistered", machineId); | ||||
|                 return true; | ||||
|             } else { | ||||
|                 log.error("Error deregistering machine. Status code: {}, error: {}",  | ||||
|                         response.statusCode(), response.body()); | ||||
|                 return false; | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             log.error("Exception during machine deregistration: {}", e.getMessage(), e); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user