From 6a15569d0cfa09f37b559e3fa82d14ffaac1d54b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Kr=C3=BChlmann?= Date: Wed, 10 Dec 2025 13:37:27 +0100 Subject: [PATCH] Open public routes --- .../imgfloat/app/config/SecurityConfig.java | 5 +++ .../app/controller/ChannelApiController.java | 33 +++++++++++-------- .../app/controller/ViewController.java | 6 ---- .../app/service/ChannelDirectoryService.java | 8 +++++ 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/imgfloat/app/config/SecurityConfig.java b/src/main/java/com/imgfloat/app/config/SecurityConfig.java index 8c326b8..42908d4 100644 --- a/src/main/java/com/imgfloat/app/config/SecurityConfig.java +++ b/src/main/java/com/imgfloat/app/config/SecurityConfig.java @@ -2,6 +2,7 @@ package com.imgfloat.app.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -30,6 +31,10 @@ public class SecurityConfig { "/swagger-ui.html", "/swagger-ui/**" ).permitAll() + .requestMatchers(HttpMethod.GET, "/view/*/broadcast").permitAll() + .requestMatchers(HttpMethod.GET, "/api/channels/*/assets/visible").permitAll() + .requestMatchers(HttpMethod.GET, "/api/channels/*/canvas").permitAll() + .requestMatchers(HttpMethod.GET, "/api/channels/*/assets/*/content").permitAll() .requestMatchers("/ws/**").permitAll() .anyRequest().authenticated() ) diff --git a/src/main/java/com/imgfloat/app/controller/ChannelApiController.java b/src/main/java/com/imgfloat/app/controller/ChannelApiController.java index c352d1c..c73c088 100644 --- a/src/main/java/com/imgfloat/app/controller/ChannelApiController.java +++ b/src/main/java/com/imgfloat/app/controller/ChannelApiController.java @@ -107,20 +107,12 @@ public class ChannelApiController { } @GetMapping("/assets/visible") - public Collection listVisible(@PathVariable("broadcaster") String broadcaster, - OAuth2AuthenticationToken authentication) { - String login = TwitchUser.from(authentication).login(); - if (!channelDirectoryService.isBroadcaster(broadcaster, login)) { - throw new ResponseStatusException(FORBIDDEN, "Only broadcaster can load public overlay"); - } + public Collection listVisible(@PathVariable("broadcaster") String broadcaster) { return channelDirectoryService.getVisibleAssets(broadcaster); } @GetMapping("/canvas") - public CanvasSettingsRequest getCanvas(@PathVariable("broadcaster") String broadcaster, - OAuth2AuthenticationToken authentication) { - String login = TwitchUser.from(authentication).login(); - ensureAuthorized(broadcaster, login); + public CanvasSettingsRequest getCanvas(@PathVariable("broadcaster") String broadcaster) { return channelDirectoryService.getCanvasSettings(broadcaster); } @@ -179,13 +171,26 @@ public class ChannelApiController { public ResponseEntity getAssetContent(@PathVariable("broadcaster") String broadcaster, @PathVariable("assetId") String assetId, OAuth2AuthenticationToken authentication) { - String login = TwitchUser.from(authentication).login(); - ensureAuthorized(broadcaster, login); - return channelDirectoryService.getAssetContent(broadcaster, assetId) + boolean authorized = false; + if (authentication != null) { + String login = TwitchUser.from(authentication).login(); + authorized = channelDirectoryService.isBroadcaster(broadcaster, login) + || channelDirectoryService.isAdmin(broadcaster, login); + } + + if (authorized) { + return channelDirectoryService.getAssetContent(broadcaster, assetId) + .map(content -> ResponseEntity.ok() + .contentType(MediaType.parseMediaType(content.mediaType())) + .body(content.bytes())) + .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, "Asset not found")); + } + + return channelDirectoryService.getVisibleAssetContent(broadcaster, assetId) .map(content -> ResponseEntity.ok() .contentType(MediaType.parseMediaType(content.mediaType())) .body(content.bytes())) - .orElseThrow(() -> new ResponseStatusException(NOT_FOUND, "Asset not found")); + .orElseThrow(() -> new ResponseStatusException(FORBIDDEN, "Asset not available")); } @DeleteMapping("/assets/{assetId}") diff --git a/src/main/java/com/imgfloat/app/controller/ViewController.java b/src/main/java/com/imgfloat/app/controller/ViewController.java index f963a23..386c837 100644 --- a/src/main/java/com/imgfloat/app/controller/ViewController.java +++ b/src/main/java/com/imgfloat/app/controller/ViewController.java @@ -44,14 +44,8 @@ public class ViewController { @org.springframework.web.bind.annotation.GetMapping("/view/{broadcaster}/broadcast") public String broadcastView(@org.springframework.web.bind.annotation.PathVariable("broadcaster") String broadcaster, - OAuth2AuthenticationToken authentication, Model model) { - String login = TwitchUser.from(authentication).login(); - if (!channelDirectoryService.isBroadcaster(broadcaster, login)) { - throw new ResponseStatusException(FORBIDDEN, "Only the broadcaster can render this view"); - } model.addAttribute("broadcaster", broadcaster.toLowerCase()); - model.addAttribute("username", login); return "broadcast"; } } diff --git a/src/main/java/com/imgfloat/app/service/ChannelDirectoryService.java b/src/main/java/com/imgfloat/app/service/ChannelDirectoryService.java index d5d3842..f63165e 100644 --- a/src/main/java/com/imgfloat/app/service/ChannelDirectoryService.java +++ b/src/main/java/com/imgfloat/app/service/ChannelDirectoryService.java @@ -219,6 +219,14 @@ public class ChannelDirectoryService { .flatMap(this::decodeAssetData); } + public Optional getVisibleAssetContent(String broadcaster, String assetId) { + String normalized = normalize(broadcaster); + return assetRepository.findById(assetId) + .filter(asset -> normalized.equals(asset.getBroadcaster())) + .filter(asset -> !asset.isHidden()) + .flatMap(this::decodeAssetData); + } + public boolean isBroadcaster(String broadcaster, String username) { return broadcaster != null && broadcaster.equalsIgnoreCase(username); }