From 51fd029e22eebdfd6bf451f03bd50b0cf97c25ee Mon Sep 17 00:00:00 2001 From: catbref Date: Wed, 24 Apr 2019 15:02:37 +0100 Subject: [PATCH] Access to log entries from API & checks for some transaction-based API calls. --- .../org/qora/api/resource/AdminResource.java | 70 ++++++++++++++++++- .../api/resource/TransactionsResource.java | 7 ++ 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/qora/api/resource/AdminResource.java b/src/main/java/org/qora/api/resource/AdminResource.java index 5d1a64cc..29be54dc 100644 --- a/src/main/java/org/qora/api/resource/AdminResource.java +++ b/src/main/java/org/qora/api/resource/AdminResource.java @@ -10,6 +10,9 @@ import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.time.LocalDate; import java.time.LocalTime; import java.time.OffsetDateTime; @@ -23,14 +26,12 @@ import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.logging.log4j.core.config.LoggerConfig; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.FileAppender; import org.apache.logging.log4j.core.appender.RollingFileAppender; import org.qora.account.PrivateKeyAccount; import org.qora.api.ApiError; @@ -46,11 +47,15 @@ import org.qora.data.account.ForgingAccountData; import org.qora.data.account.ProxyForgerData; import org.qora.utils.Base58; +import com.google.common.collect.Lists; + @Path("/admin") @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}) @Tag(name = "Admin") public class AdminResource { + private static final int MAX_LOG_LINES = 500; + @Context HttpServletRequest request; @@ -266,4 +271,63 @@ public class AdminResource { return "true"; } + @GET + @Path("/logs") + @Operation( + summary = "Return logs entries", + description = "Limit pegged to 500 max", + responses = { + @ApiResponse( + content = @Content(mediaType = MediaType.TEXT_PLAIN, schema = @Schema(type = "string")) + ) + } + ) + public String fetchLogs(@Parameter( + ref = "limit" + ) @QueryParam("limit") Integer limit, @Parameter( + ref = "offset" + ) @QueryParam("offset") Integer offset, @Parameter( + ref = "reverse" + ) @QueryParam("reverse") Boolean reverse) { + LoggerContext loggerContext = (LoggerContext) LogManager.getContext(); + RollingFileAppender fileAppender = (RollingFileAppender) loggerContext.getConfiguration().getAppenders().values().stream().filter(appender -> appender instanceof RollingFileAppender).findFirst().get(); + + String filename = fileAppender.getManager().getFileName(); + java.nio.file.Path logPath = Paths.get(filename); + + try { + List logLines = Files.readAllLines(logPath); + + // Slicing + if (reverse != null && reverse) + logLines = Lists.reverse(logLines); + + // offset out of bounds? + if (offset != null && (offset < 0 || offset >= logLines.size())) + return ""; + + if (offset != null) { + offset = Math.min(offset, logLines.size() - 1); + logLines.subList(0, offset).clear(); + } + + // invalid limit + if (limit != null && limit <= 0) + return ""; + + if (limit != null) + limit = Math.min(limit, MAX_LOG_LINES); + else + limit = MAX_LOG_LINES; + + limit = Math.min(limit, logLines.size()); + + logLines.subList(limit - 1, logLines.size()).clear(); + + return String.join("\n", logLines); + } catch (IOException e) { + return ""; + } + } + } diff --git a/src/main/java/org/qora/api/resource/TransactionsResource.java b/src/main/java/org/qora/api/resource/TransactionsResource.java index 8fcf131e..ed5deec5 100644 --- a/src/main/java/org/qora/api/resource/TransactionsResource.java +++ b/src/main/java/org/qora/api/resource/TransactionsResource.java @@ -366,6 +366,8 @@ public class TransactionsResource { byte[] rawBytes = Bytes.concat(signRequest.transactionBytes, new byte[TransactionTransformer.SIGNATURE_LENGTH]); TransactionData transactionData = TransactionTransformer.fromBytes(rawBytes); + if (transactionData == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); PrivateKeyAccount signer = new PrivateKeyAccount(null, signRequest.privateKey); @@ -417,6 +419,8 @@ public class TransactionsResource { try (final Repository repository = RepositoryManager.getRepository()) { byte[] rawBytes = Base58.decode(rawBytes58); TransactionData transactionData = TransactionTransformer.fromBytes(rawBytes); + if (transactionData == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); Transaction transaction = Transaction.fromData(repository, transactionData); if (!transaction.isSignatureValid()) @@ -489,6 +493,9 @@ public class TransactionsResource { transactionData = TransactionTransformer.fromBytes(rawBytes); } + if (transactionData == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); + Transaction transaction = Transaction.fromData(repository, transactionData); if (!ignoreValidityChecks) {