From 44c63c0f1000e92351fa6c5f0207f77366a6f0b4 Mon Sep 17 00:00:00 2001 From: Mathias Dollenbacher Date: Mon, 15 Jun 2026 15:17:04 +0200 Subject: [PATCH] fix: put filters under routes and add route logging to startup --- .../dev/webhookproxy/config/ProxyConfig.java | 42 ++++++++++++++++--- .../controller/WebhookController.java | 9 ---- .../service/DiscordForwardingService.java | 29 +++++++++---- src/main/resources/application.yml | 8 ++-- 4 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/main/java/dev/webhookproxy/config/ProxyConfig.java b/src/main/java/dev/webhookproxy/config/ProxyConfig.java index a1356e9..d10a1de 100644 --- a/src/main/java/dev/webhookproxy/config/ProxyConfig.java +++ b/src/main/java/dev/webhookproxy/config/ProxyConfig.java @@ -1,24 +1,56 @@ package dev.webhookproxy.config; +import jakarta.annotation.PostConstruct; import lombok.*; +import lombok.extern.slf4j.Slf4j; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.List; +@Slf4j @Data @Component @ConfigurationProperties(prefix = "proxy") public class ProxyConfig { - private List routes = List.of(); - private Filters filters; + private List routes = List.of(); - @Getter - @Setter + @PostConstruct + public void logConfig() { + log.info("Loaded {} route(s):", routes.size()); + for (int i = 0; i < routes.size(); i++) { + Route route = routes.get(i); + log.info(" [{}] {}", i + 1, maskUrl(route.getUrl())); + List usernames = route.getFilters().getUsernameFilter(); + if (usernames.isEmpty()) { + log.info(" usernameFilter: (none)"); + } else { + log.info(" usernameFilter: {}", usernames); + } + } + } + + private String maskUrl(String url) { + if (url == null) return "(null)"; + int lastSlash = url.lastIndexOf('/'); + if (lastSlash < 0 || lastSlash >= url.length() - 1) return url; + String token = url.substring(lastSlash + 1); + return url.substring(0, lastSlash + 1) + token.substring(0, Math.min(2, token.length())) + "***"; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class Route { + private String url; + private Filters filters = new Filters(); + } + + @Data @NoArgsConstructor @AllArgsConstructor public static class Filters { - private List usernameFilter; + private List usernameFilter = List.of(); } } diff --git a/src/main/java/dev/webhookproxy/controller/WebhookController.java b/src/main/java/dev/webhookproxy/controller/WebhookController.java index 8beef2b..d0c40a0 100644 --- a/src/main/java/dev/webhookproxy/controller/WebhookController.java +++ b/src/main/java/dev/webhookproxy/controller/WebhookController.java @@ -32,15 +32,6 @@ public class WebhookController { log.info("Incoming notification type: {}", payload.getNotificationType()); - if (payload.getRequest() != null) { - if (proxyConfig.getFilters().getUsernameFilter().contains(payload.getRequest().getRequestedByUsername())) { - String user = payload.getRequest().getRequestedByUsername(); - String movie = payload.getSubject(); - log.info("Blocked notifications for user {} and movie {}", user, movie); - return ResponseEntity.ok("OK"); - } - } - forwardingService.forward(payload, rawBody); return ResponseEntity.ok("OK"); diff --git a/src/main/java/dev/webhookproxy/service/DiscordForwardingService.java b/src/main/java/dev/webhookproxy/service/DiscordForwardingService.java index 63e5b1e..2eb11fe 100644 --- a/src/main/java/dev/webhookproxy/service/DiscordForwardingService.java +++ b/src/main/java/dev/webhookproxy/service/DiscordForwardingService.java @@ -32,23 +32,38 @@ public class DiscordForwardingService { public void forward(SeerrPayload payload, String rawBody) { String mediaName = payload.getSubject(); - List targets = proxyConfig.getRoutes(); + List routes = proxyConfig.getRoutes(); - if (targets.isEmpty()) { + if (routes.isEmpty()) { log.warn("No Discord webhooks configured — skipping."); return; } - log.info("Forwarding notification for media {} to {} Discord webhook(s).", mediaName, targets.size()); - String discordBody = buildDiscordPayload(payload); List> futures = new ArrayList<>(); - for (String webhookUrl : targets) { - futures.add(sendAsync(webhookUrl, discordBody, mediaName)); + for (ProxyConfig.Route route : routes) { + if (isBlocked(route, payload)) { + log.info("Route {} blocked notification for user {} and media {}", + maskUrl(route.getUrl()), + payload.getRequest() != null ? payload.getRequest().getRequestedByUsername() : "unknown", + mediaName); + continue; + } + futures.add(sendAsync(route.getUrl(), discordBody, mediaName)); } - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + if (!futures.isEmpty()) { + log.info("Forwarding notification for media {} to {} Discord webhook(s).", mediaName, futures.size()); + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + } + } + + private boolean isBlocked(ProxyConfig.Route route, SeerrPayload payload) { + List usernameFilter = route.getFilters().getUsernameFilter(); + if (usernameFilter.isEmpty()) return false; + if (payload.getRequest() == null) return false; + return usernameFilter.contains(payload.getRequest().getRequestedByUsername()); } private CompletableFuture sendAsync(String webhookUrl, String body, String notificationType) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index b8a91d4..58cc272 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -2,11 +2,11 @@ server: port: 8080 proxy: - filters: - usernameFilter: - - private routes: - - https://discord.com/api/webhooks/1498794785475920022/bwoytZA_iDvza86fbR9aOFXNOcv9_Fl5P5taoOaMHjey_X3YLRt5FGbDjt9uPiKHJ8yi + - url: https://discord.com/api/webhooks/1498794785475920022/bwoytZA_iDvza86fbR9aOFXNOcv9_Fl5P5taoOaMHjey_X3YLRt5FGbDjt9uPiKHJ8yi + filters: + usernameFilter: + - private # Spring Boot Actuator — exposes /actuator/health endpoint management: