fix: put filters under routes and add route logging to startup
This commit is contained in:
@@ -1,24 +1,56 @@
|
|||||||
package dev.webhookproxy.config;
|
package dev.webhookproxy.config;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Data
|
@Data
|
||||||
@Component
|
@Component
|
||||||
@ConfigurationProperties(prefix = "proxy")
|
@ConfigurationProperties(prefix = "proxy")
|
||||||
public class ProxyConfig {
|
public class ProxyConfig {
|
||||||
|
|
||||||
private List<String> routes = List.of();
|
private List<Route> routes = List.of();
|
||||||
private Filters filters;
|
|
||||||
|
|
||||||
@Getter
|
@PostConstruct
|
||||||
@Setter
|
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<String> 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
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public static class Filters {
|
public static class Filters {
|
||||||
private List<String> usernameFilter;
|
private List<String> usernameFilter = List.of();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,15 +32,6 @@ public class WebhookController {
|
|||||||
|
|
||||||
log.info("Incoming notification type: {}", payload.getNotificationType());
|
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);
|
forwardingService.forward(payload, rawBody);
|
||||||
|
|
||||||
return ResponseEntity.ok("OK");
|
return ResponseEntity.ok("OK");
|
||||||
|
|||||||
@@ -32,23 +32,38 @@ public class DiscordForwardingService {
|
|||||||
|
|
||||||
public void forward(SeerrPayload payload, String rawBody) {
|
public void forward(SeerrPayload payload, String rawBody) {
|
||||||
String mediaName = payload.getSubject();
|
String mediaName = payload.getSubject();
|
||||||
List<String> targets = proxyConfig.getRoutes();
|
List<ProxyConfig.Route> routes = proxyConfig.getRoutes();
|
||||||
|
|
||||||
if (targets.isEmpty()) {
|
if (routes.isEmpty()) {
|
||||||
log.warn("No Discord webhooks configured — skipping.");
|
log.warn("No Discord webhooks configured — skipping.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Forwarding notification for media {} to {} Discord webhook(s).", mediaName, targets.size());
|
|
||||||
|
|
||||||
String discordBody = buildDiscordPayload(payload);
|
String discordBody = buildDiscordPayload(payload);
|
||||||
|
|
||||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||||
for (String webhookUrl : targets) {
|
for (ProxyConfig.Route route : routes) {
|
||||||
futures.add(sendAsync(webhookUrl, discordBody, mediaName));
|
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<String> usernameFilter = route.getFilters().getUsernameFilter();
|
||||||
|
if (usernameFilter.isEmpty()) return false;
|
||||||
|
if (payload.getRequest() == null) return false;
|
||||||
|
return usernameFilter.contains(payload.getRequest().getRequestedByUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Void> sendAsync(String webhookUrl, String body, String notificationType) {
|
private CompletableFuture<Void> sendAsync(String webhookUrl, String body, String notificationType) {
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ server:
|
|||||||
port: 8080
|
port: 8080
|
||||||
|
|
||||||
proxy:
|
proxy:
|
||||||
filters:
|
|
||||||
usernameFilter:
|
|
||||||
- private
|
|
||||||
routes:
|
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
|
# Spring Boot Actuator — exposes /actuator/health endpoint
|
||||||
management:
|
management:
|
||||||
|
|||||||
Reference in New Issue
Block a user