From ea10eec92678c68ce5e6fde30cffb16e14645dd5 Mon Sep 17 00:00:00 2001 From: CalDescent Date: Sun, 23 Jan 2022 12:38:19 +0000 Subject: [PATCH] Fixed bug in auto update process - use the API key when stopping the node. Luckily this code is included in the new JAR, not the old one, so we should be able to regain auto update ability by issuing a new update. --- src/main/java/org/qortal/ApplyUpdate.java | 61 +++++++++++++++++++++-- src/main/java/org/qortal/api/ApiKey.java | 9 ++++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/qortal/ApplyUpdate.java b/src/main/java/org/qortal/ApplyUpdate.java index edd6d924..ece44ba4 100644 --- a/src/main/java/org/qortal/ApplyUpdate.java +++ b/src/main/java/org/qortal/ApplyUpdate.java @@ -7,15 +7,15 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.security.Security; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; +import org.qortal.api.ApiKey; import org.qortal.api.ApiRequest; +import org.qortal.api.ApiService; import org.qortal.controller.AutoUpdate; import org.qortal.settings.Settings; @@ -70,14 +70,43 @@ public class ApplyUpdate { String baseUri = "http://localhost:" + Settings.getInstance().getApiPort() + "/"; LOGGER.info(() -> String.format("Shutting down node using API via %s", baseUri)); + // The /admin/stop endpoint requires an API key, which may or may not be already generated + boolean apiKeyNewlyGenerated = false; + ApiKey apiKey = null; + try { + apiKey = ApiService.getInstance().getApiKey(); + if (apiKey == null) { + apiKey = new ApiKey(); + if (!apiKey.generated()) { + apiKey.generate(); + apiKeyNewlyGenerated = true; + LOGGER.info("Generated API key"); + } + } + } catch (IOException e) { + LOGGER.info("Error loading API key: {}", e.getMessage()); + } + + // Create GET params + Map params = new HashMap<>(); + if (apiKey != null) { + params.put("apiKey", apiKey.toString()); + } + + // Attempt to stop the node int attempt; for (attempt = 0; attempt < MAX_ATTEMPTS; ++attempt) { final int attemptForLogging = attempt; LOGGER.info(() -> String.format("Attempt #%d out of %d to shutdown node", attemptForLogging + 1, MAX_ATTEMPTS)); - String response = ApiRequest.perform(baseUri + "admin/stop", null); - if (response == null) + String response = ApiRequest.perform(baseUri + "admin/stop", params); + if (response == null) { // No response - consider node shut down + if (apiKeyNewlyGenerated) { + // API key was newly generated for this auto update, so we need to remove it + ApplyUpdate.removeGeneratedApiKey(); + } return true; + } LOGGER.info(() -> String.format("Response from API: %s", response)); @@ -89,6 +118,11 @@ public class ApplyUpdate { } } + if (apiKeyNewlyGenerated) { + // API key was newly generated for this auto update, so we need to remove it + ApplyUpdate.removeGeneratedApiKey(); + } + if (attempt == MAX_ATTEMPTS) { LOGGER.error("Failed to shutdown node - giving up"); return false; @@ -97,6 +131,23 @@ public class ApplyUpdate { return true; } + private static void removeGeneratedApiKey() { + try { + LOGGER.info("Removing newly generated API key..."); + + ApiKey apiKey = ApiService.getInstance().getApiKey(); + if (apiKey == null) { + apiKey = new ApiKey(); + } + + // Delete the API key since it was only generated for this auto update + apiKey.delete(); + + } catch (IOException e) { + LOGGER.info("Error loading or deleting API key: {}", e.getMessage()); + } + } + private static void replaceJar() { // Assuming current working directory contains the JAR files Path realJar = Paths.get(JAR_FILENAME); diff --git a/src/main/java/org/qortal/api/ApiKey.java b/src/main/java/org/qortal/api/ApiKey.java index 6a79dd20..3f7cfe35 100644 --- a/src/main/java/org/qortal/api/ApiKey.java +++ b/src/main/java/org/qortal/api/ApiKey.java @@ -81,6 +81,15 @@ public class ApiKey { writer.close(); } + public void delete() throws IOException { + this.apiKey = null; + + Path filePath = this.getFilePath(); + if (Files.exists(filePath)) { + Files.delete(filePath); + } + } + public boolean generated() { return (this.apiKey != null);