From 1351ca348bea4b9921a17f71f7702592e0748028 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Fri, 23 Aug 2024 18:31:16 +0200 Subject: [PATCH] Allow checking signatures in dev mode Fixes #619 --- .../deployment/OptionalConfigFileTest.java | 2 ++ .../quarkiverse/githubapp/runtime/Routes.java | 29 +++++++++++++++---- .../runtime/smee/SmeeIoForwarder.java | 6 ++-- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/deployment/src/test/java/io/quarkiverse/githubapp/deployment/OptionalConfigFileTest.java b/deployment/src/test/java/io/quarkiverse/githubapp/deployment/OptionalConfigFileTest.java index 84987dd6..e2c82549 100644 --- a/deployment/src/test/java/io/quarkiverse/githubapp/deployment/OptionalConfigFileTest.java +++ b/deployment/src/test/java/io/quarkiverse/githubapp/deployment/OptionalConfigFileTest.java @@ -1,6 +1,7 @@ package io.quarkiverse.githubapp.deployment; import java.util.Optional; +import java.util.UUID; import org.jboss.shrinkwrap.api.ShrinkWrap; import org.jboss.shrinkwrap.api.spec.JavaArchive; @@ -30,6 +31,7 @@ public void testOptionalConfigFile() { RestAssured .given() .header(Headers.X_GITHUB_EVENT, "label") + .header(Headers.X_GITHUB_DELIVERY, UUID.randomUUID()) .contentType("application/json") .body(Thread.currentThread().getContextClassLoader().getResourceAsStream(PAYLOAD)) .when().post("/") diff --git a/runtime/src/main/java/io/quarkiverse/githubapp/runtime/Routes.java b/runtime/src/main/java/io/quarkiverse/githubapp/runtime/Routes.java index 1152ebc1..946748d1 100644 --- a/runtime/src/main/java/io/quarkiverse/githubapp/runtime/Routes.java +++ b/runtime/src/main/java/io/quarkiverse/githubapp/runtime/Routes.java @@ -92,21 +92,39 @@ private void handleRequest(RoutingContext routingContext, String hubSignature, String deliveryId, String event, - String replayed) { + String replayedHeader) { - if (!launchMode.isDevOrTest() && (isBlank(deliveryId) || isBlank(hubSignature))) { + boolean replayed = "true".equals(replayedHeader) && LaunchMode.current().isDevOrTest(); + boolean checkSignatures = !replayed && LaunchMode.current() != LaunchMode.TEST; + + if (isBlank(deliveryId)) { + routingExchange.response().setStatusCode(400).end(); + LOG.debug("Request received without delivery id. It has been ignored."); + return; + } + + if (checkSignatures && isBlank(hubSignature)) { routingExchange.response().setStatusCode(400).end(); + + if (LaunchMode.current() == LaunchMode.DEVELOPMENT) { + LOG.warn( + "Request received without signature. This is only permitted for replayed events. It has been ignored."); + } + return; } if (routingContext.body().buffer() == null) { routingExchange.ok().end(); + LOG.debug("Request received without a body. It has been ignored."); return; } byte[] bodyBytes = routingContext.body().buffer().getBytes(); - if (checkedConfigProvider.webhookSecret().isPresent() && !launchMode.isDevOrTest()) { + if (checkSignatures && checkedConfigProvider.webhookSecret().isPresent()) { + System.out.println("Signature checked!"); + if (!payloadSignatureChecker.matches(bodyBytes, hubSignature)) { StringBuilder signatureError = new StringBuilder("Invalid signature for delivery: ").append(deliveryId) .append("\n"); @@ -120,6 +138,7 @@ private void handleRequest(RoutingContext routingContext, if (bodyBytes.length == 0) { routingExchange.ok().end(); + LOG.debug("Request received without a body. It has been ignored."); return; } @@ -128,7 +147,7 @@ private void handleRequest(RoutingContext routingContext, String action = payloadObject.getString("action"); - if (!isBlank(deliveryId) && checkedConfigProvider.debug().payloadDirectory().isPresent()) { + if (checkedConfigProvider.debug().payloadDirectory().isPresent()) { String fileName = DATE_TIME_FORMATTER.format(LocalDateTime.now()) + "-" + event + "-" + (!isBlank(action) ? action + "-" : "") + deliveryId + ".json"; Path path = checkedConfigProvider.debug().payloadDirectory().get().resolve(fileName); @@ -142,7 +161,7 @@ private void handleRequest(RoutingContext routingContext, Long installationId = extractInstallationId(payloadObject); String repository = extractRepository(payloadObject); GitHubEvent gitHubEvent = new GitHubEvent(installationId, checkedConfigProvider.appName().orElse(null), deliveryId, - repository, event, action, payload, payloadObject, "true".equals(replayed) ? true : false); + repository, event, action, payload, payloadObject, replayed); if (launchMode == LaunchMode.DEVELOPMENT && replayRouteInstance.isResolvable()) { replayRouteInstance.get().pushEvent(gitHubEvent); diff --git a/runtime/src/main/java/io/quarkiverse/githubapp/runtime/smee/SmeeIoForwarder.java b/runtime/src/main/java/io/quarkiverse/githubapp/runtime/smee/SmeeIoForwarder.java index acf4b264..f8d2162f 100644 --- a/runtime/src/main/java/io/quarkiverse/githubapp/runtime/smee/SmeeIoForwarder.java +++ b/runtime/src/main/java/io/quarkiverse/githubapp/runtime/smee/SmeeIoForwarder.java @@ -110,11 +110,11 @@ public void onEvent(HttpEventStreamClient client, Event event) { try { JsonNode rootNode = objectMapper.readTree(data); - JsonNode body = rootNode.get("body"); + JsonNode rawData = rootNode.get("rawdata"); - if (body != null) { + if (rawData != null) { HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(localUrl) - .POST(BodyPublishers.ofString(objectMapper.writeValueAsString(rootNode.get("body")))); + .POST(BodyPublishers.ofString(objectMapper.writeValueAsString(rootNode.get("rawdata")))); for (String forwardedHeader : FORWARDED_HEADERS) { JsonNode headerValue = rootNode.get(forwardedHeader.toLowerCase(Locale.ROOT));