mirror of
https://github.com/imgfloat/server.git
synced 2026-02-05 03:39:26 +00:00
Sanitize user input in logging statements
This commit is contained in:
@@ -12,6 +12,7 @@ import dev.kruhlmann.imgfloat.model.PlaybackRequest;
|
|||||||
import dev.kruhlmann.imgfloat.model.TransformRequest;
|
import dev.kruhlmann.imgfloat.model.TransformRequest;
|
||||||
import dev.kruhlmann.imgfloat.model.TwitchUserProfile;
|
import dev.kruhlmann.imgfloat.model.TwitchUserProfile;
|
||||||
import dev.kruhlmann.imgfloat.model.VisibilityRequest;
|
import dev.kruhlmann.imgfloat.model.VisibilityRequest;
|
||||||
|
import dev.kruhlmann.imgfloat.util.LogSanitizer;
|
||||||
import dev.kruhlmann.imgfloat.service.AuthorizationService;
|
import dev.kruhlmann.imgfloat.service.AuthorizationService;
|
||||||
import dev.kruhlmann.imgfloat.service.ChannelDirectoryService;
|
import dev.kruhlmann.imgfloat.service.ChannelDirectoryService;
|
||||||
import dev.kruhlmann.imgfloat.service.TwitchUserLookupService;
|
import dev.kruhlmann.imgfloat.service.TwitchUserLookupService;
|
||||||
@@ -76,11 +77,14 @@ public class ChannelApiController {
|
|||||||
OAuth2AuthenticationToken oauthToken
|
OAuth2AuthenticationToken oauthToken
|
||||||
) {
|
) {
|
||||||
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
||||||
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
|
String logRequestUsername = LogSanitizer.sanitize(request.getUsername());
|
||||||
authorizationService.userMatchesSessionUsernameOrThrowHttpError(broadcaster, sessionUsername);
|
authorizationService.userMatchesSessionUsernameOrThrowHttpError(broadcaster, sessionUsername);
|
||||||
LOG.info("User {} adding admin {} to {}", sessionUsername, request.getUsername(), broadcaster.replaceAll("[\n\r]", "_"));
|
LOG.info("User {} adding admin {} to {}", logSessionUsername, logRequestUsername, logBroadcaster);
|
||||||
boolean added = channelDirectoryService.addAdmin(broadcaster, request.getUsername());
|
boolean added = channelDirectoryService.addAdmin(broadcaster, request.getUsername());
|
||||||
if (!added) {
|
if (!added) {
|
||||||
LOG.info("User {} already admin for {} or could not be added", request.getUsername(), broadcaster.replaceAll("[\n\r]", "_"));
|
LOG.info("User {} already admin for {} or could not be added", logRequestUsername, logBroadcaster);
|
||||||
}
|
}
|
||||||
return ResponseEntity.ok().body(added);
|
return ResponseEntity.ok().body(added);
|
||||||
}
|
}
|
||||||
@@ -92,8 +96,10 @@ public class ChannelApiController {
|
|||||||
HttpServletRequest request
|
HttpServletRequest request
|
||||||
) {
|
) {
|
||||||
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
||||||
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
authorizationService.userMatchesSessionUsernameOrThrowHttpError(broadcaster, sessionUsername);
|
authorizationService.userMatchesSessionUsernameOrThrowHttpError(broadcaster, sessionUsername);
|
||||||
LOG.debug("Listing admins for {} by {}", broadcaster, sessionUsername);
|
LOG.debug("Listing admins for {} by {}", logBroadcaster, logSessionUsername);
|
||||||
var channel = channelDirectoryService.getOrCreateChannel(broadcaster);
|
var channel = channelDirectoryService.getOrCreateChannel(broadcaster);
|
||||||
List<String> admins = channel.getAdmins().stream().sorted(Comparator.naturalOrder()).toList();
|
List<String> admins = channel.getAdmins().stream().sorted(Comparator.naturalOrder()).toList();
|
||||||
OAuth2AuthorizedClient authorizedClient = resolveAuthorizedClient(oauthToken, null, request);
|
OAuth2AuthorizedClient authorizedClient = resolveAuthorizedClient(oauthToken, null, request);
|
||||||
@@ -115,16 +121,18 @@ public class ChannelApiController {
|
|||||||
HttpServletRequest request
|
HttpServletRequest request
|
||||||
) {
|
) {
|
||||||
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
||||||
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
authorizationService.userMatchesSessionUsernameOrThrowHttpError(broadcaster, sessionUsername);
|
authorizationService.userMatchesSessionUsernameOrThrowHttpError(broadcaster, sessionUsername);
|
||||||
LOG.debug("Listing admin suggestions for {} by {}", broadcaster, sessionUsername);
|
LOG.debug("Listing admin suggestions for {} by {}", logBroadcaster, logSessionUsername);
|
||||||
var channel = channelDirectoryService.getOrCreateChannel(broadcaster);
|
var channel = channelDirectoryService.getOrCreateChannel(broadcaster);
|
||||||
OAuth2AuthorizedClient authorizedClient = resolveAuthorizedClient(oauthToken, null, request);
|
OAuth2AuthorizedClient authorizedClient = resolveAuthorizedClient(oauthToken, null, request);
|
||||||
|
|
||||||
if (authorizedClient == null) {
|
if (authorizedClient == null) {
|
||||||
LOG.warn(
|
LOG.warn(
|
||||||
"No authorized Twitch client found for {} while fetching admin suggestions for {}",
|
"No authorized Twitch client found for {} while fetching admin suggestions for {}",
|
||||||
sessionUsername,
|
logSessionUsername,
|
||||||
broadcaster.replaceAll("[\n\r]", "_")
|
logBroadcaster
|
||||||
);
|
);
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
@@ -139,8 +147,8 @@ public class ChannelApiController {
|
|||||||
if (accessToken == null || accessToken.isBlank() || clientId == null || clientId.isBlank()) {
|
if (accessToken == null || accessToken.isBlank() || clientId == null || clientId.isBlank()) {
|
||||||
LOG.warn(
|
LOG.warn(
|
||||||
"Missing Twitch credentials for {} while fetching admin suggestions for {}",
|
"Missing Twitch credentials for {} while fetching admin suggestions for {}",
|
||||||
sessionUsername,
|
logSessionUsername,
|
||||||
broadcaster
|
logBroadcaster
|
||||||
);
|
);
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
@@ -154,8 +162,11 @@ public class ChannelApiController {
|
|||||||
OAuth2AuthenticationToken oauthToken
|
OAuth2AuthenticationToken oauthToken
|
||||||
) {
|
) {
|
||||||
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
||||||
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
|
String logUsername = LogSanitizer.sanitize(username);
|
||||||
authorizationService.userMatchesSessionUsernameOrThrowHttpError(broadcaster, sessionUsername);
|
authorizationService.userMatchesSessionUsernameOrThrowHttpError(broadcaster, sessionUsername);
|
||||||
LOG.info("User {} removing admin {} from {}", sessionUsername, username, broadcaster);
|
LOG.info("User {} removing admin {} from {}", logSessionUsername, logUsername, logBroadcaster);
|
||||||
boolean removed = channelDirectoryService.removeAdmin(broadcaster, username);
|
boolean removed = channelDirectoryService.removeAdmin(broadcaster, username);
|
||||||
return ResponseEntity.ok().body(removed);
|
return ResponseEntity.ok().body(removed);
|
||||||
}
|
}
|
||||||
@@ -182,11 +193,13 @@ public class ChannelApiController {
|
|||||||
OAuth2AuthenticationToken oauthToken
|
OAuth2AuthenticationToken oauthToken
|
||||||
) {
|
) {
|
||||||
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
||||||
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
authorizationService.userMatchesSessionUsernameOrThrowHttpError(broadcaster, sessionUsername);
|
authorizationService.userMatchesSessionUsernameOrThrowHttpError(broadcaster, sessionUsername);
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"Updating canvas for {} by {}: {}x{}",
|
"Updating canvas for {} by {}: {}x{}",
|
||||||
broadcaster.replaceAll("[\n\r]", "_"),
|
logBroadcaster,
|
||||||
sessionUsername,
|
logSessionUsername,
|
||||||
request.getWidth(),
|
request.getWidth(),
|
||||||
request.getHeight()
|
request.getHeight()
|
||||||
);
|
);
|
||||||
@@ -200,22 +213,25 @@ public class ChannelApiController {
|
|||||||
OAuth2AuthenticationToken oauthToken
|
OAuth2AuthenticationToken oauthToken
|
||||||
) {
|
) {
|
||||||
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
||||||
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
authorizationService.userIsBroadcasterOrChannelAdminForBroadcasterOrThrowHttpError(
|
authorizationService.userIsBroadcasterOrChannelAdminForBroadcasterOrThrowHttpError(
|
||||||
broadcaster,
|
broadcaster,
|
||||||
sessionUsername
|
sessionUsername
|
||||||
);
|
);
|
||||||
if (file == null || file.isEmpty()) {
|
if (file == null || file.isEmpty()) {
|
||||||
LOG.warn("User {} attempted to upload empty file to {}", sessionUsername, broadcaster);
|
LOG.warn("User {} attempted to upload empty file to {}", logSessionUsername, logBroadcaster);
|
||||||
throw new ResponseStatusException(BAD_REQUEST, "Asset file is required");
|
throw new ResponseStatusException(BAD_REQUEST, "Asset file is required");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
LOG.info("User {} uploading asset {} to {}", sessionUsername, file.getOriginalFilename(), broadcaster);
|
String logOriginalFilename = LogSanitizer.sanitize(file.getOriginalFilename());
|
||||||
|
LOG.info("User {} uploading asset {} to {}", logSessionUsername, logOriginalFilename, logBroadcaster);
|
||||||
return channelDirectoryService
|
return channelDirectoryService
|
||||||
.createAsset(broadcaster, file)
|
.createAsset(broadcaster, file)
|
||||||
.map(ResponseEntity::ok)
|
.map(ResponseEntity::ok)
|
||||||
.orElseThrow(() -> new ResponseStatusException(BAD_REQUEST, "Unable to read image"));
|
.orElseThrow(() -> new ResponseStatusException(BAD_REQUEST, "Unable to read image"));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOG.error("Failed to process asset upload for {} by {}", broadcaster, sessionUsername, e);
|
LOG.error("Failed to process asset upload for {} by {}", logBroadcaster, logSessionUsername, e);
|
||||||
throw new ResponseStatusException(BAD_REQUEST, "Failed to process image", e);
|
throw new ResponseStatusException(BAD_REQUEST, "Failed to process image", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,16 +244,19 @@ public class ChannelApiController {
|
|||||||
OAuth2AuthenticationToken oauthToken
|
OAuth2AuthenticationToken oauthToken
|
||||||
) {
|
) {
|
||||||
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
||||||
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logAssetId = LogSanitizer.sanitize(assetId);
|
||||||
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
authorizationService.userIsBroadcasterOrChannelAdminForBroadcasterOrThrowHttpError(
|
authorizationService.userIsBroadcasterOrChannelAdminForBroadcasterOrThrowHttpError(
|
||||||
broadcaster,
|
broadcaster,
|
||||||
sessionUsername
|
sessionUsername
|
||||||
);
|
);
|
||||||
LOG.debug("Applying transform to asset {} on {} by {}", assetId, broadcaster, sessionUsername);
|
LOG.debug("Applying transform to asset {} on {} by {}", logAssetId, logBroadcaster, logSessionUsername);
|
||||||
return channelDirectoryService
|
return channelDirectoryService
|
||||||
.updateTransform(broadcaster, assetId, request)
|
.updateTransform(broadcaster, assetId, request)
|
||||||
.map(ResponseEntity::ok)
|
.map(ResponseEntity::ok)
|
||||||
.orElseThrow(() -> {
|
.orElseThrow(() -> {
|
||||||
LOG.warn("Transform request for missing asset {} on {} by {}", assetId, broadcaster, sessionUsername);
|
LOG.warn("Transform request for missing asset {} on {} by {}", logAssetId, logBroadcaster, logSessionUsername);
|
||||||
return createAsset404();
|
return createAsset404();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -250,11 +269,14 @@ public class ChannelApiController {
|
|||||||
OAuth2AuthenticationToken oauthToken
|
OAuth2AuthenticationToken oauthToken
|
||||||
) {
|
) {
|
||||||
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
||||||
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logAssetId = LogSanitizer.sanitize(assetId);
|
||||||
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
authorizationService.userIsBroadcasterOrChannelAdminForBroadcasterOrThrowHttpError(
|
authorizationService.userIsBroadcasterOrChannelAdminForBroadcasterOrThrowHttpError(
|
||||||
broadcaster,
|
broadcaster,
|
||||||
sessionUsername
|
sessionUsername
|
||||||
);
|
);
|
||||||
LOG.info("Triggering playback for asset {} on {} by {}", assetId, broadcaster, sessionUsername);
|
LOG.info("Triggering playback for asset {} on {} by {}", logAssetId, logBroadcaster, logSessionUsername);
|
||||||
return channelDirectoryService
|
return channelDirectoryService
|
||||||
.triggerPlayback(broadcaster, assetId, request)
|
.triggerPlayback(broadcaster, assetId, request)
|
||||||
.map(ResponseEntity::ok)
|
.map(ResponseEntity::ok)
|
||||||
@@ -269,15 +291,18 @@ public class ChannelApiController {
|
|||||||
OAuth2AuthenticationToken oauthToken
|
OAuth2AuthenticationToken oauthToken
|
||||||
) {
|
) {
|
||||||
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
||||||
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logAssetId = LogSanitizer.sanitize(assetId);
|
||||||
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
authorizationService.userIsBroadcasterOrChannelAdminForBroadcasterOrThrowHttpError(
|
authorizationService.userIsBroadcasterOrChannelAdminForBroadcasterOrThrowHttpError(
|
||||||
broadcaster,
|
broadcaster,
|
||||||
sessionUsername
|
sessionUsername
|
||||||
);
|
);
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"Updating visibility for asset {} on {} by {} to hidden={} ",
|
"Updating visibility for asset {} on {} by {} to hidden={} ",
|
||||||
assetId,
|
logAssetId,
|
||||||
broadcaster.replaceAll("[\n\r]", "_"),
|
logBroadcaster,
|
||||||
sessionUsername,
|
logSessionUsername,
|
||||||
request.isHidden()
|
request.isHidden()
|
||||||
);
|
);
|
||||||
return channelDirectoryService
|
return channelDirectoryService
|
||||||
@@ -286,9 +311,9 @@ public class ChannelApiController {
|
|||||||
.orElseThrow(() -> {
|
.orElseThrow(() -> {
|
||||||
LOG.warn(
|
LOG.warn(
|
||||||
"Visibility update for missing asset {} on {} by {}",
|
"Visibility update for missing asset {} on {} by {}",
|
||||||
assetId.replaceAll("[\n\r]", "_"),
|
logAssetId,
|
||||||
broadcaster.replaceAll("[\n\r]", "_"),
|
logBroadcaster,
|
||||||
sessionUsername
|
logSessionUsername
|
||||||
);
|
);
|
||||||
return createAsset404();
|
return createAsset404();
|
||||||
});
|
});
|
||||||
@@ -299,7 +324,9 @@ public class ChannelApiController {
|
|||||||
@PathVariable("broadcaster") String broadcaster,
|
@PathVariable("broadcaster") String broadcaster,
|
||||||
@PathVariable("assetId") String assetId
|
@PathVariable("assetId") String assetId
|
||||||
) {
|
) {
|
||||||
LOG.debug("Serving asset {} for broadcaster {}", assetId, broadcaster);
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logAssetId = LogSanitizer.sanitize(assetId);
|
||||||
|
LOG.debug("Serving asset {} for broadcaster {}", logAssetId, logBroadcaster);
|
||||||
return channelDirectoryService
|
return channelDirectoryService
|
||||||
.getAssetContent(assetId)
|
.getAssetContent(assetId)
|
||||||
.map((content) ->
|
.map((content) ->
|
||||||
@@ -317,7 +344,9 @@ public class ChannelApiController {
|
|||||||
@PathVariable("broadcaster") String broadcaster,
|
@PathVariable("broadcaster") String broadcaster,
|
||||||
@PathVariable("assetId") String assetId
|
@PathVariable("assetId") String assetId
|
||||||
) {
|
) {
|
||||||
LOG.debug("Serving preview for asset {} for broadcaster {}", assetId, broadcaster);
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logAssetId = LogSanitizer.sanitize(assetId);
|
||||||
|
LOG.debug("Serving preview for asset {} for broadcaster {}", logAssetId, logBroadcaster);
|
||||||
return channelDirectoryService
|
return channelDirectoryService
|
||||||
.getAssetPreview(assetId, true)
|
.getAssetPreview(assetId, true)
|
||||||
.map((content) ->
|
.map((content) ->
|
||||||
@@ -346,16 +375,19 @@ public class ChannelApiController {
|
|||||||
OAuth2AuthenticationToken oauthToken
|
OAuth2AuthenticationToken oauthToken
|
||||||
) {
|
) {
|
||||||
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
||||||
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logAssetId = LogSanitizer.sanitize(assetId);
|
||||||
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
authorizationService.userIsBroadcasterOrChannelAdminForBroadcasterOrThrowHttpError(
|
authorizationService.userIsBroadcasterOrChannelAdminForBroadcasterOrThrowHttpError(
|
||||||
broadcaster,
|
broadcaster,
|
||||||
sessionUsername
|
sessionUsername
|
||||||
);
|
);
|
||||||
boolean removed = channelDirectoryService.deleteAsset(assetId);
|
boolean removed = channelDirectoryService.deleteAsset(assetId);
|
||||||
if (!removed) {
|
if (!removed) {
|
||||||
LOG.warn("Attempt to delete missing asset {} on {} by {}", assetId, broadcaster, sessionUsername);
|
LOG.warn("Attempt to delete missing asset {} on {} by {}", logAssetId, logBroadcaster, logSessionUsername);
|
||||||
throw createAsset404();
|
throw createAsset404();
|
||||||
}
|
}
|
||||||
LOG.info("Asset {} deleted on {} by {}", assetId, broadcaster, sessionUsername);
|
LOG.info("Asset {} deleted on {} by {}", logAssetId, logBroadcaster, logSessionUsername);
|
||||||
return ResponseEntity.ok().build();
|
return ResponseEntity.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import dev.kruhlmann.imgfloat.model.OauthSessionUser;
|
import dev.kruhlmann.imgfloat.model.OauthSessionUser;
|
||||||
import dev.kruhlmann.imgfloat.model.Settings;
|
import dev.kruhlmann.imgfloat.model.Settings;
|
||||||
|
import dev.kruhlmann.imgfloat.util.LogSanitizer;
|
||||||
import dev.kruhlmann.imgfloat.service.AuthorizationService;
|
import dev.kruhlmann.imgfloat.service.AuthorizationService;
|
||||||
import dev.kruhlmann.imgfloat.service.ChannelDirectoryService;
|
import dev.kruhlmann.imgfloat.service.ChannelDirectoryService;
|
||||||
import dev.kruhlmann.imgfloat.service.SettingsService;
|
import dev.kruhlmann.imgfloat.service.SettingsService;
|
||||||
@@ -49,7 +50,8 @@ public class ViewController {
|
|||||||
public String home(OAuth2AuthenticationToken oauthToken, Model model) {
|
public String home(OAuth2AuthenticationToken oauthToken, Model model) {
|
||||||
if (oauthToken != null) {
|
if (oauthToken != null) {
|
||||||
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
||||||
LOG.info("Rendering dashboard for {}", sessionUsername);
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
|
LOG.info("Rendering dashboard for {}", logSessionUsername);
|
||||||
model.addAttribute("username", sessionUsername);
|
model.addAttribute("username", sessionUsername);
|
||||||
model.addAttribute("channel", sessionUsername);
|
model.addAttribute("channel", sessionUsername);
|
||||||
model.addAttribute("adminChannels", channelDirectoryService.adminChannelsFor(sessionUsername));
|
model.addAttribute("adminChannels", channelDirectoryService.adminChannelsFor(sessionUsername));
|
||||||
@@ -70,7 +72,8 @@ public class ViewController {
|
|||||||
public String settingsView(OAuth2AuthenticationToken oauthToken, Model model) {
|
public String settingsView(OAuth2AuthenticationToken oauthToken, Model model) {
|
||||||
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
String sessionUsername = OauthSessionUser.from(oauthToken).login();
|
||||||
authorizationService.userIsSystemAdministratorOrThrowHttpError(sessionUsername);
|
authorizationService.userIsSystemAdministratorOrThrowHttpError(sessionUsername);
|
||||||
LOG.info("Rendering settings for {}", sessionUsername);
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
|
LOG.info("Rendering settings for {}", logSessionUsername);
|
||||||
Settings settings = settingsService.get();
|
Settings settings = settingsService.get();
|
||||||
try {
|
try {
|
||||||
model.addAttribute("settingsJson", objectMapper.writeValueAsString(settings));
|
model.addAttribute("settingsJson", objectMapper.writeValueAsString(settings));
|
||||||
@@ -92,10 +95,12 @@ public class ViewController {
|
|||||||
broadcaster,
|
broadcaster,
|
||||||
sessionUsername
|
sessionUsername
|
||||||
);
|
);
|
||||||
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
LOG.info(
|
LOG.info(
|
||||||
"Rendering admin console for {} (requested by {})",
|
"Rendering admin console for {} (requested by {})",
|
||||||
broadcaster.replaceAll("[\n\r]", "_"),
|
logBroadcaster,
|
||||||
sessionUsername
|
logSessionUsername
|
||||||
);
|
);
|
||||||
Settings settings = settingsService.get();
|
Settings settings = settingsService.get();
|
||||||
model.addAttribute("broadcaster", broadcaster.toLowerCase());
|
model.addAttribute("broadcaster", broadcaster.toLowerCase());
|
||||||
@@ -116,7 +121,8 @@ public class ViewController {
|
|||||||
@org.springframework.web.bind.annotation.PathVariable("broadcaster") String broadcaster,
|
@org.springframework.web.bind.annotation.PathVariable("broadcaster") String broadcaster,
|
||||||
Model model
|
Model model
|
||||||
) {
|
) {
|
||||||
LOG.debug("Rendering broadcast overlay for {}", broadcaster);
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
|
LOG.debug("Rendering broadcast overlay for {}", logBroadcaster);
|
||||||
model.addAttribute("broadcaster", broadcaster.toLowerCase());
|
model.addAttribute("broadcaster", broadcaster.toLowerCase());
|
||||||
return "broadcast";
|
return "broadcast";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import static org.springframework.http.HttpStatus.UNAUTHORIZED;
|
|||||||
import dev.kruhlmann.imgfloat.model.OauthSessionUser;
|
import dev.kruhlmann.imgfloat.model.OauthSessionUser;
|
||||||
import dev.kruhlmann.imgfloat.service.ChannelDirectoryService;
|
import dev.kruhlmann.imgfloat.service.ChannelDirectoryService;
|
||||||
import dev.kruhlmann.imgfloat.service.SystemAdministratorService;
|
import dev.kruhlmann.imgfloat.service.SystemAdministratorService;
|
||||||
|
import dev.kruhlmann.imgfloat.util.LogSanitizer;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -33,15 +34,17 @@ public class AuthorizationService {
|
|||||||
LOG.warn("Access denied for broadcaster-only action by unauthenticated user");
|
LOG.warn("Access denied for broadcaster-only action by unauthenticated user");
|
||||||
throw new ResponseStatusException(UNAUTHORIZED, "You must be logged in to manage your channel");
|
throw new ResponseStatusException(UNAUTHORIZED, "You must be logged in to manage your channel");
|
||||||
}
|
}
|
||||||
|
String logSessionUsername = LogSanitizer.sanitize(sessionUsername);
|
||||||
if (submittedUsername == null) {
|
if (submittedUsername == null) {
|
||||||
LOG.warn("User match with oauth token failed: submitted username is null for user {}", sessionUsername);
|
LOG.warn("User match with oauth token failed: submitted username is null for user {}", logSessionUsername);
|
||||||
throw new ResponseStatusException(NOT_FOUND, "You can only manage your own channel");
|
throw new ResponseStatusException(NOT_FOUND, "You can only manage your own channel");
|
||||||
}
|
}
|
||||||
|
String logSubmittedUsername = LogSanitizer.sanitize(submittedUsername);
|
||||||
if (!sessionUsername.equals(submittedUsername)) {
|
if (!sessionUsername.equals(submittedUsername)) {
|
||||||
LOG.warn(
|
LOG.warn(
|
||||||
"User match with oauth token failed: session user {} does not match submitted user {}",
|
"User match with oauth token failed: session user {} does not match submitted user {}",
|
||||||
sessionUsername,
|
logSessionUsername,
|
||||||
submittedUsername
|
logSubmittedUsername
|
||||||
);
|
);
|
||||||
throw new ResponseStatusException(FORBIDDEN, "You are not this user");
|
throw new ResponseStatusException(FORBIDDEN, "You are not this user");
|
||||||
}
|
}
|
||||||
@@ -51,12 +54,12 @@ public class AuthorizationService {
|
|||||||
String broadcaster,
|
String broadcaster,
|
||||||
String sessionUsername
|
String sessionUsername
|
||||||
) {
|
) {
|
||||||
broadcaster = broadcaster.replaceAll("[\n\r]", "_");
|
String logBroadcaster = LogSanitizer.sanitize(broadcaster);
|
||||||
if (!userIsBroadcasterOrChannelAdminForBroadcaster(broadcaster, sessionUsername)) {
|
if (!userIsBroadcasterOrChannelAdminForBroadcaster(logBroadcaster, sessionUsername)) {
|
||||||
LOG.warn(
|
LOG.warn(
|
||||||
"Access denied for broadcaster/admin-only action by user {} on broadcaster {}",
|
"Access denied for broadcaster/admin-only action by user {} on broadcaster {}",
|
||||||
sessionUsername,
|
LogSanitizer.sanitize(sessionUsername),
|
||||||
broadcaster
|
logBroadcaster
|
||||||
);
|
);
|
||||||
throw new ResponseStatusException(FORBIDDEN, "You do not have permission to manage this channel");
|
throw new ResponseStatusException(FORBIDDEN, "You do not have permission to manage this channel");
|
||||||
}
|
}
|
||||||
@@ -64,14 +67,18 @@ public class AuthorizationService {
|
|||||||
|
|
||||||
public void userIsSystemAdministratorOrThrowHttpError(String sessionUsername) {
|
public void userIsSystemAdministratorOrThrowHttpError(String sessionUsername) {
|
||||||
if (!userIsSystemAdministrator(sessionUsername)) {
|
if (!userIsSystemAdministrator(sessionUsername)) {
|
||||||
LOG.warn("Access denied for system administrator-only action by user {}", sessionUsername);
|
LOG.warn("Access denied for system administrator-only action by user {}", LogSanitizer.sanitize(sessionUsername));
|
||||||
throw new ResponseStatusException(FORBIDDEN, "You do not have permission to perform this action");
|
throw new ResponseStatusException(FORBIDDEN, "You do not have permission to perform this action");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean userIsBroadcaster(String a, String b) {
|
public boolean userIsBroadcaster(String a, String b) {
|
||||||
if (a == null || b == null) {
|
if (a == null || b == null) {
|
||||||
LOG.warn("Broadcaster check failed: one or both usernames are null (a: {}, b: {})", a, b);
|
LOG.warn(
|
||||||
|
"Broadcaster check failed: one or both usernames are null (a: {}, b: {})",
|
||||||
|
LogSanitizer.sanitize(a),
|
||||||
|
LogSanitizer.sanitize(b)
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return a.equals(b);
|
return a.equals(b);
|
||||||
@@ -81,8 +88,8 @@ public class AuthorizationService {
|
|||||||
if (sessionUsername == null || broadcaster == null) {
|
if (sessionUsername == null || broadcaster == null) {
|
||||||
LOG.warn(
|
LOG.warn(
|
||||||
"Channel admin check failed: broadcaster or session username is null (broadcaster: {}, sessionUsername: {})",
|
"Channel admin check failed: broadcaster or session username is null (broadcaster: {}, sessionUsername: {})",
|
||||||
broadcaster,
|
LogSanitizer.sanitize(broadcaster),
|
||||||
sessionUsername
|
LogSanitizer.sanitize(sessionUsername)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/main/java/dev/kruhlmann/imgfloat/util/LogSanitizer.java
Normal file
17
src/main/java/dev/kruhlmann/imgfloat/util/LogSanitizer.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package dev.kruhlmann.imgfloat.util;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public final class LogSanitizer {
|
||||||
|
|
||||||
|
private static final Pattern NEWLINE_CHARACTERS = Pattern.compile("[\\r\\n]+");
|
||||||
|
|
||||||
|
private LogSanitizer() {}
|
||||||
|
|
||||||
|
public static String sanitize(String value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return NEWLINE_CHARACTERS.matcher(value).replaceAll("_");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user