diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs index a906b170..1f57fa29 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs @@ -1,9 +1,9 @@ -#nullable enable using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Logging; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Filter; @@ -11,17 +11,12 @@ using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Logging; using LBPUnion.ProjectLighthouse.Types.Serialization; using LBPUnion.ProjectLighthouse.Types.Users; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class CommentController : ControllerBase +public class CommentController : GameController { private readonly DatabaseContext database; public CommentController(DatabaseContext database) diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/DeveloperController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/DeveloperController.cs index 503356d6..6b735a93 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/DeveloperController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/DeveloperController.cs @@ -1,14 +1,10 @@ -using LBPUnion.ProjectLighthouse.Types.Serialization; -using Microsoft.AspNetCore.Authorization; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; +using LBPUnion.ProjectLighthouse.Types.Serialization; using Microsoft.AspNetCore.Mvc; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class DeveloperController : Controller +public class DeveloperController : GameController { [HttpGet("developer_videos")] public IActionResult DeveloperVideos() => this.Ok(new GameDeveloperVideos()); diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/FriendsController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/FriendsController.cs index 83e198d8..13956e94 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/FriendsController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/FriendsController.cs @@ -1,23 +1,18 @@ -#nullable enable using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users; using LBPUnion.ProjectLighthouse.StorableLists.Stores; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Serialization; using LBPUnion.ProjectLighthouse.Types.Users; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class FriendsController : ControllerBase +public class FriendsController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Login/ClientConfigurationController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Login/ClientConfigurationController.cs index f4ed348c..d69fc45a 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Login/ClientConfigurationController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Login/ClientConfigurationController.cs @@ -1,22 +1,18 @@ -#nullable enable using System.Diagnostics.CodeAnalysis; using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; using LBPUnion.ProjectLighthouse.Types.Serialization; using LBPUnion.ProjectLighthouse.Types.Users; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Login; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/plain")] -public class ClientConfigurationController : ControllerBase +public class ClientConfigurationController : GameController { private readonly DatabaseContext database; @@ -26,6 +22,7 @@ public class ClientConfigurationController : ControllerBase } [HttpGet("network_settings.nws")] + [UseDigest(EnforceDigest = false)] [SuppressMessage("ReSharper", "StringLiteralTypo")] public IActionResult NetworkSettings() { @@ -41,15 +38,18 @@ public class ClientConfigurationController : ControllerBase [HttpGet("t_conf")] [Produces("text/xml")] + [UseDigest(EnforceDigest = false)] public IActionResult Conf() => this.Ok(new TelemetryConfigResponse()); // The challenge config here is currently based on the official server's config. // We should probably make this configurable in the future. [HttpGet("ChallengeConfig.xml")] [Produces("text/xml")] + [UseDigest(EnforceDigest = false)] public IActionResult Challenges() => this.Ok(GameChallengeResponse.ServerChallenges()); [HttpGet("farc_hashes")] + [UseDigest(EnforceDigest = false)] public IActionResult FarcHashes() => this.Ok(); [HttpGet("privacySettings")] diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Login/LogoutController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Login/LogoutController.cs index 89140f71..71625ae8 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Login/LogoutController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Login/LogoutController.cs @@ -1,20 +1,15 @@ using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; using LBPUnion.ProjectLighthouse.Types.Entities.Token; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Login; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/goodbye")] -[Produces("text/xml")] -public class LogoutController : ControllerBase +public class LogoutController : GameController { - private readonly DatabaseContext database; public LogoutController(DatabaseContext database) @@ -22,8 +17,8 @@ public class LogoutController : ControllerBase this.database = database; } - [HttpPost] - public async Task OnPost() + [HttpPost("goodbye")] + public async Task OnLogout() { GameTokenEntity token = this.GetToken(); @@ -37,6 +32,4 @@ public class LogoutController : ControllerBase return this.Ok(); } - - } \ No newline at end of file diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Matching/EnterLevelController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Matching/EnterLevelController.cs index e8b2aa37..3ca628d3 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Matching/EnterLevelController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Matching/EnterLevelController.cs @@ -1,22 +1,17 @@ -#nullable enable using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Interaction; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Users; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Matching; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class EnterLevelController : ControllerBase +public class EnterLevelController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Matching/MatchController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Matching/MatchController.cs index 2b3b295b..3bedbfbf 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Matching/MatchController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Matching/MatchController.cs @@ -1,27 +1,22 @@ -#nullable enable using System.Text.Json; using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Logging; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Logging; using LBPUnion.ProjectLighthouse.Types.Matchmaking; using LBPUnion.ProjectLighthouse.Types.Matchmaking.MatchCommands; using LBPUnion.ProjectLighthouse.Types.Matchmaking.Rooms; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Matching; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class MatchController : ControllerBase +public class MatchController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/MessageController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/MessageController.cs index 26ae10ac..c0f680f2 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/MessageController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/MessageController.cs @@ -7,23 +7,20 @@ using LBPUnion.ProjectLighthouse.Localization; using LBPUnion.ProjectLighthouse.Localization.StringLists; using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Serialization; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Notifications; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Logging; using LBPUnion.ProjectLighthouse.Types.Mail; using LBPUnion.ProjectLighthouse.Types.Serialization; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/plain")] -public class MessageController : ControllerBase +public class MessageController : GameController { private readonly DatabaseContext database; @@ -47,9 +44,11 @@ along with this program. If not, see ."; } [HttpGet("eula")] + [UseDigest(EnforceDigest = false)] public IActionResult Eula() => this.Ok($"{license}\n{ServerConfiguration.Instance.EulaText}"); [HttpGet("announce")] + [UseDigest(EnforceDigest = false)] public async Task Announce() { GameTokenEntity token = this.GetToken(); diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/ReportController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/ReportController.cs index bf5007c3..0668e5b0 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/ReportController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/ReportController.cs @@ -1,24 +1,19 @@ -#nullable enable -using System.Text.Json; +using System.Text.Json; using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Files; using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Moderation; using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Moderation.Reports; using LBPUnion.ProjectLighthouse.Types.Serialization; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class ReportController : ControllerBase +public class ReportController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Resources/PhotosController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Resources/PhotosController.cs index 4c73d0a0..59cabb00 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Resources/PhotosController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Resources/PhotosController.cs @@ -1,4 +1,3 @@ -#nullable enable using Discord; using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Database; @@ -6,6 +5,7 @@ using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Files; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Logging; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; using LBPUnion.ProjectLighthouse.Types.Entities.Token; @@ -13,17 +13,12 @@ using LBPUnion.ProjectLighthouse.Types.Filter; using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Logging; using LBPUnion.ProjectLighthouse.Types.Serialization; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Resources; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class PhotosController : ControllerBase +public class PhotosController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Resources/ResourcesController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Resources/ResourcesController.cs index 7231ccaf..da4748bd 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Resources/ResourcesController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Resources/ResourcesController.cs @@ -1,23 +1,18 @@ -#nullable enable using System.Text; using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Files; using LBPUnion.ProjectLighthouse.Logging; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Misc; using LBPUnion.ProjectLighthouse.Types.Logging; using LBPUnion.ProjectLighthouse.Types.Resources; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using IOFile = System.IO.File; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Resources; -[ApiController] -[Authorize] -[Produces("text/xml")] -[Route("LITTLEBIGPLANETPS3_XML")] -public class ResourcesController : ControllerBase +public class ResourcesController : GameController { [HttpPost("showModerated")] @@ -52,6 +47,7 @@ public class ResourcesController : ControllerBase [HttpPost("upload/{hash}/unattributed")] [HttpPost("upload/{hash}")] + [UseDigest(DigestHeaderName = "X-Digest-B", ExcludeBodyFromDigest = true)] public async Task UploadResource(string hash) { string assetsDirectory = FileHelper.ResourcePath; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CategoryController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CategoryController.cs index 60ac1c58..61a17691 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CategoryController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CategoryController.cs @@ -4,6 +4,7 @@ using LBPUnion.ProjectLighthouse.Filter; using LBPUnion.ProjectLighthouse.Filter.Sorts; using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; @@ -13,17 +14,12 @@ using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Logging; using LBPUnion.ProjectLighthouse.Types.Misc; using LBPUnion.ProjectLighthouse.Types.Serialization; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class CategoryController : ControllerBase +public class CategoryController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/LevelTagsController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/LevelTagsController.cs index 2b069099..ee39499f 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/LevelTagsController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/LevelTagsController.cs @@ -1,22 +1,18 @@ using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Interaction; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Users; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML")] -[Produces("text/plain")] -public class LevelTagsController : ControllerBase +public class LevelTagsController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs index 67fff180..2a24d798 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs @@ -1,9 +1,9 @@ -#nullable enable using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Filter; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; using LBPUnion.ProjectLighthouse.Types.Entities.Token; @@ -11,17 +11,12 @@ using LBPUnion.ProjectLighthouse.Types.Filter; using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Serialization; using LBPUnion.ProjectLighthouse.Types.Users; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class ListController : ControllerBase +public class ListController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PlaylistController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PlaylistController.cs index 4763708a..6e6af98b 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PlaylistController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PlaylistController.cs @@ -1,21 +1,16 @@ -#nullable enable using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Serialization; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class PlaylistController : ControllerBase +public class PlaylistController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PublishController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PublishController.cs index 7bedc01d..41d93c53 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PublishController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/PublishController.cs @@ -6,6 +6,7 @@ using LBPUnion.ProjectLighthouse.Files; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Servers.GameServer.Helpers; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; using LBPUnion.ProjectLighthouse.Types.Entities.Token; @@ -23,7 +24,7 @@ namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots; [Authorize] [Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/xml")] -public class PublishController : ControllerBase +public class PublishController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ReviewController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ReviewController.cs index 0dd54c07..7f2e14a1 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ReviewController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ReviewController.cs @@ -3,22 +3,18 @@ using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Interaction; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Filter; using LBPUnion.ProjectLighthouse.Types.Serialization; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class ReviewController : ControllerBase +public class ReviewController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ScoreController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ScoreController.cs index 79ae3163..0efb8193 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ScoreController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ScoreController.cs @@ -1,8 +1,8 @@ -#nullable enable using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Logging; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.StorableLists.Stores; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Token; @@ -10,17 +10,12 @@ using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Logging; using LBPUnion.ProjectLighthouse.Types.Serialization; using LBPUnion.ProjectLighthouse.Types.Users; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class ScoreController : ControllerBase +public class ScoreController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/SearchController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/SearchController.cs index a4f129b5..f34112cb 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/SearchController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/SearchController.cs @@ -1,25 +1,20 @@ -#nullable enable using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Filter; using LBPUnion.ProjectLighthouse.Filter.Filters; using LBPUnion.ProjectLighthouse.Filter.Sorts; using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Filter; using LBPUnion.ProjectLighthouse.Types.Serialization; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/slots")] -[Produces("text/xml")] -public class SearchController : ControllerBase +public class SearchController : GameController { private readonly DatabaseContext database; public SearchController(DatabaseContext database) diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/SlotsController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/SlotsController.cs index f71267ba..5471dc36 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/SlotsController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/SlotsController.cs @@ -1,4 +1,3 @@ -#nullable enable using System.Linq.Expressions; using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; @@ -8,6 +7,7 @@ using LBPUnion.ProjectLighthouse.Filter.Sorts; using LBPUnion.ProjectLighthouse.Filter.Sorts.Metadata; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Filter; @@ -15,17 +15,12 @@ using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Misc; using LBPUnion.ProjectLighthouse.Types.Serialization; using LBPUnion.ProjectLighthouse.Types.Users; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class SlotsController : ControllerBase +public class SlotsController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/StatisticsController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/StatisticsController.cs index 3f70b3d0..253791d0 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/StatisticsController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/StatisticsController.cs @@ -1,20 +1,17 @@ using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Helpers; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Filter; using LBPUnion.ProjectLighthouse.Filter.Filters; using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Types.Serialization; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/plain")] -public class StatisticsController : ControllerBase +public class StatisticsController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/StoreController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/StoreController.cs index 0b6a8407..358d84d6 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/StoreController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/StoreController.cs @@ -1,13 +1,9 @@ -using Microsoft.AspNetCore.Authorization; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using Microsoft.AspNetCore.Mvc; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class StoreController : Controller +public class StoreController : GameController { [HttpGet("promotions")] public IActionResult Promotions() => this.Ok(); diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/UserController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/UserController.cs index 7019cdd7..f7ecd94a 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/UserController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/UserController.cs @@ -5,6 +5,7 @@ using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Files; using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Servers.GameServer.Helpers; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; @@ -13,17 +14,12 @@ using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Logging; using LBPUnion.ProjectLighthouse.Types.Serialization; using LBPUnion.ProjectLighthouse.Types.Users; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers; -[ApiController] -[Authorize] -[Route("LITTLEBIGPLANETPS3_XML/")] -[Produces("text/xml")] -public class UserController : ControllerBase +public class UserController : GameController { private readonly DatabaseContext database; diff --git a/ProjectLighthouse.Servers.GameServer/Middlewares/DigestMiddleware.cs b/ProjectLighthouse.Servers.GameServer/Middlewares/DigestMiddleware.cs index ecb0824c..c96d5e91 100644 --- a/ProjectLighthouse.Servers.GameServer/Middlewares/DigestMiddleware.cs +++ b/ProjectLighthouse.Servers.GameServer/Middlewares/DigestMiddleware.cs @@ -1,7 +1,7 @@ -using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Middlewares; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using Microsoft.Extensions.Primitives; using Org.BouncyCastle.Utilities.Zlib; @@ -9,108 +9,17 @@ namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Middlewares; public class DigestMiddleware : Middleware { - private readonly bool computeDigests; + private readonly List digestKeys; - public DigestMiddleware(RequestDelegate next, bool computeDigests) : base(next) + public DigestMiddleware(RequestDelegate next, List digestKeys) : base(next) { - this.computeDigests = computeDigests; + this.digestKeys = digestKeys; } - #if !DEBUG - private static readonly HashSet exemptPathList = new() + private static async Task HandleResponseCompression(HttpContext context, MemoryStream responseBuffer) { - "/login", - "/eula", - "/announce", - "/status", - "/farc_hashes", - "/t_conf", - "/network_settings.nws", - "/ChallengeConfig.xml", - }; - #endif - - public override async Task InvokeAsync(HttpContext context) - { - // Client digest check. - if (!context.Request.Cookies.TryGetValue("MM_AUTH", out string? authCookie)) authCookie = string.Empty; - string digestPath = context.Request.Path; - #if !DEBUG - const string url = "/LITTLEBIGPLANETPS3_XML"; - string strippedPath = digestPath.Contains(url) ? digestPath[url.Length..] : ""; - #endif - byte[] bodyBytes = await context.Request.BodyReader.ReadAllAsync(); - - bool usedAlternateDigestKey = false; - - if (this.computeDigests && digestPath.StartsWith("/LITTLEBIGPLANETPS3_XML")) - { - // The game sets X-Digest-B on a resource upload instead of X-Digest-A - string digestHeaderKey = "X-Digest-A"; - bool excludeBodyFromDigest = false; - if (digestPath.Contains("/upload/")) - { - digestHeaderKey = "X-Digest-B"; - excludeBodyFromDigest = true; - } - - string clientRequestDigest = CryptoHelper.ComputeDigest(digestPath, - authCookie, - bodyBytes, - ServerConfiguration.Instance.DigestKey.PrimaryDigestKey, - excludeBodyFromDigest); - - // Check the digest we've just calculated against the digest header if the game set the header. They should match. - if (context.Request.Headers.TryGetValue(digestHeaderKey, out StringValues sentDigest)) - { - if (clientRequestDigest != sentDigest) - { - // If we got here, the normal ServerDigestKey failed to validate. Lets try again with the alternate digest key. - usedAlternateDigestKey = true; - - clientRequestDigest = CryptoHelper.ComputeDigest(digestPath, - authCookie, - bodyBytes, - ServerConfiguration.Instance.DigestKey.AlternateDigestKey, - excludeBodyFromDigest); - if (clientRequestDigest != sentDigest) - { - #if DEBUG - Console.WriteLine("Digest failed"); - Console.WriteLine("digestKey: " + ServerConfiguration.Instance.DigestKey.PrimaryDigestKey); - Console.WriteLine("altDigestKey: " + ServerConfiguration.Instance.DigestKey.AlternateDigestKey); - Console.WriteLine("computed digest: " + clientRequestDigest); - #endif - // We still failed to validate. Abort the request. - context.Response.StatusCode = 403; - return; - } - } - } - - #if !DEBUG - // The game doesn't start sending digests until after the announcement so if it's not one of those requests - // and it doesn't include a digest we need to reject the request - else if (!exemptPathList.Contains(strippedPath)) - { - context.Response.StatusCode = 403; - return; - } - #endif - - context.Response.Headers.Append("X-Digest-B", clientRequestDigest); - context.Request.Body.Position = 0; - } - - // This does the same as above, but for the response stream. - await using MemoryStream responseBuffer = new(); - Stream oldResponseStream = context.Response.Body; - context.Response.Body = responseBuffer; - - await this.next(context); // Handle the request so we can get the server digest hash - responseBuffer.Position = 0; - - if (responseBuffer.Length > 1000 && + const int minCompressionLen = 1000; + if (responseBuffer.Length > minCompressionLen && context.Request.Headers.AcceptEncoding.Contains("deflate") && (context.Response.ContentType ?? string.Empty).Contains("text/xml")) { @@ -130,30 +39,95 @@ public class DigestMiddleware : Middleware } else { - string headerName = !context.Response.Headers.ContentLength.HasValue - ? "Content-Length" - : "X-Original-Content-Length"; + string headerName = !context.Response.Headers.ContentLength.HasValue ? "Content-Length" : "X-Original-Content-Length"; context.Response.Headers.Append(headerName, responseBuffer.Length.ToString()); } + } - // Compute the server digest hash. - if (this.computeDigests) + public override async Task InvokeAsync(HttpContext context) + { + // If no digest keys are supplied, then we can't do anything + if (this.digestKeys.Count == 0) { - responseBuffer.Position = 0; - - string digestKey = usedAlternateDigestKey - ? ServerConfiguration.Instance.DigestKey.AlternateDigestKey - : ServerConfiguration.Instance.DigestKey.PrimaryDigestKey; - - // Compute the digest for the response. - string serverDigest = - CryptoHelper.ComputeDigest(context.Request.Path, authCookie, responseBuffer.ToArray(), digestKey); - context.Response.Headers.Append("X-Digest-A", serverDigest); + await this.next(context); + return; } - // Copy the buffered response to the actual response stream. + UseDigestAttribute? digestAttribute = context.GetEndpoint()?.Metadata.GetMetadata(); + if (digestAttribute == null) + { + await this.next(context); + return; + } + + if (!context.Request.Cookies.TryGetValue("MM_AUTH", out string? authCookie)) authCookie = string.Empty; + + string digestPath = context.Request.Path; + + byte[] bodyBytes = await context.Request.BodyReader.ReadAllAsync(); + + if ((!context.Request.Headers.TryGetValue(digestAttribute.DigestHeaderName, out StringValues digestHeaders) || + digestHeaders.Count != 1) && digestAttribute.EnforceDigest) + { + context.Response.StatusCode = 403; + return; + } + + string? clientDigest = digestHeaders.FirstOrDefault() ?? null; + + string? matchingDigestKey = null; + string? calculatedRequestDigest = null; + + if (clientDigest != null) + { + foreach (string digestKey in this.digestKeys) + { + string calculatedDigest = CalculateDigest(digestKey, bodyBytes); + if (calculatedDigest != clientDigest) continue; + + matchingDigestKey = digestKey; + calculatedRequestDigest = calculatedDigest; + } + } + + matchingDigestKey ??= this.digestKeys.First(); + + switch (calculatedRequestDigest) + { + case null when digestAttribute.EnforceDigest: + context.Response.StatusCode = 403; + return; + case null: + calculatedRequestDigest = CalculateDigest(matchingDigestKey, bodyBytes); + break; + } + + context.Response.Headers.Append("X-Digest-B", calculatedRequestDigest); + + // Let endpoint generate response so we can calculate the digest for it + Stream originalBody = context.Response.Body; + await using MemoryStream responseBuffer = new(); + context.Response.Body = responseBuffer; + + await this.next(context); + + await HandleResponseCompression(context, responseBuffer); + + string responseDigest = CalculateDigest(matchingDigestKey, responseBuffer.ToArray()); + + context.Response.Headers.Append("X-Digest-A", responseDigest); + responseBuffer.Position = 0; - await responseBuffer.CopyToAsync(oldResponseStream); - context.Response.Body = oldResponseStream; + await responseBuffer.CopyToAsync(originalBody); + context.Response.Body = originalBody; + return; + + string CalculateDigest(string digestKey, byte[] data) => + CryptoHelper.ComputeDigest(digestPath, + authCookie, + data, + digestKey, + digestAttribute.ExcludeBodyFromDigest); } + } \ No newline at end of file diff --git a/ProjectLighthouse.Servers.GameServer/Startup/GameServerStartup.cs b/ProjectLighthouse.Servers.GameServer/Startup/GameServerStartup.cs index 0d372e8f..64499ac7 100644 --- a/ProjectLighthouse.Servers.GameServer/Startup/GameServerStartup.cs +++ b/ProjectLighthouse.Servers.GameServer/Startup/GameServerStartup.cs @@ -84,8 +84,6 @@ public class GameServerStartup // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env) { - bool computeDigests = true; - if (string.IsNullOrEmpty(ServerConfiguration.Instance.DigestKey.PrimaryDigestKey)) { Logger.Warn @@ -94,7 +92,6 @@ public class GameServerStartup "To increase security, it is recommended that you find and set this variable.", LogArea.Startup ); - computeDigests = false; } #if DEBUG @@ -105,11 +102,17 @@ public class GameServerStartup app.UseMiddleware(); app.UseMiddleware(); - app.UseMiddleware(computeDigests); app.UseMiddleware(); app.UseRouting(); + List digestKeys = + [ + ServerConfiguration.Instance.DigestKey.PrimaryDigestKey, + ServerConfiguration.Instance.DigestKey.AlternateDigestKey, + ]; + app.UseMiddleware(digestKeys); + app.UseAuthorization(); app.UseEndpoints(endpoints => endpoints.MapControllers()); diff --git a/ProjectLighthouse.Servers.GameServer/Types/GameController.cs b/ProjectLighthouse.Servers.GameServer/Types/GameController.cs new file mode 100644 index 00000000..9e0aab2b --- /dev/null +++ b/ProjectLighthouse.Servers.GameServer/Types/GameController.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types; + +[ApiController] +[Authorize] +[UseDigest] +[Route("LITTLEBIGPLANETPS3_XML/")] +[Produces("text/xml")] +public class GameController : ControllerBase; \ No newline at end of file diff --git a/ProjectLighthouse.Servers.GameServer/Types/UseDigestAttribute.cs b/ProjectLighthouse.Servers.GameServer/Types/UseDigestAttribute.cs new file mode 100644 index 00000000..28f6e5af --- /dev/null +++ b/ProjectLighthouse.Servers.GameServer/Types/UseDigestAttribute.cs @@ -0,0 +1,11 @@ +namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types; + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] +public class UseDigestAttribute : Attribute +{ + public bool EnforceDigest { get; set; } = true; + + public string DigestHeaderName { get; set; } = "X-Digest-A"; + + public bool ExcludeBodyFromDigest { get; set; } +} \ No newline at end of file diff --git a/ProjectLighthouse.Tests.GameApiTests/Unit/Middlewares/DigestMiddlewareTests.cs b/ProjectLighthouse.Tests.GameApiTests/Unit/Middlewares/DigestMiddlewareTests.cs index b6b7354a..e099790a 100644 --- a/ProjectLighthouse.Tests.GameApiTests/Unit/Middlewares/DigestMiddlewareTests.cs +++ b/ProjectLighthouse.Tests.GameApiTests/Unit/Middlewares/DigestMiddlewareTests.cs @@ -3,8 +3,8 @@ using System.Collections.Generic; using System.IO; using System.Text; using System.Threading.Tasks; -using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Servers.GameServer.Middlewares; +using LBPUnion.ProjectLighthouse.Servers.GameServer.Types; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using Xunit; @@ -14,25 +14,48 @@ namespace ProjectLighthouse.Tests.GameApiTests.Unit.Middlewares; [Trait("Category", "Unit")] public class DigestMiddlewareTests { - - [Fact] - public async Task DigestMiddleware_ShouldNotComputeDigests_WhenDigestsDisabled() + private static DefaultHttpContext GetHttpContext + (Stream body, string path, string cookie, Dictionary? extraHeaders = null, UseDigestAttribute? digestAttribute = null) { + DefaultHttpContext context = new() { Request = { - Body = new MemoryStream(), - Path = "/LITTLEBIGPLANETPS3_XML/notification", - Headers = { KeyValuePair.Create("Cookie", "MM_AUTH=unittest"), }, + Body = body, + Path = path, + Headers = + { + KeyValuePair.Create("Cookie", cookie), + }, }, }; + if (extraHeaders != null) + { + foreach ((string key, StringValues value) in extraHeaders) + { + context.Request.Headers.Append(key, value); + } + } + + if (digestAttribute != null) + { + context.SetEndpoint(new Endpoint(null, new EndpointMetadataCollection(digestAttribute), null)); + } + + return context; + } + + [Fact] + public async Task DigestMiddleware_ShouldNotComputeDigests_WithoutDigestAttribute() + { + DefaultHttpContext context = GetHttpContext(new MemoryStream(), "/LITTLEBIGPLANETPS3_XML/notification", "MM_AUTH=unittest"); DigestMiddleware middleware = new(httpContext => { httpContext.Response.StatusCode = 200; httpContext.Response.WriteAsync(""); return Task.CompletedTask; - }, false); + }, []); await middleware.InvokeAsync(context); @@ -46,33 +69,24 @@ public class DigestMiddlewareTests [Fact] public async Task DigestMiddleware_ShouldReject_WhenDigestHeaderIsMissing() { - DefaultHttpContext context = new() - { - Request = - { - Body = new MemoryStream(), - Path = "/LITTLEBIGPLANETPS3_XML/notification", - Headers = - { - KeyValuePair.Create("Cookie", "MM_AUTH=unittest"), - }, - }, - }; - ServerConfiguration.Instance.DigestKey.PrimaryDigestKey = "bruh"; + DefaultHttpContext context = GetHttpContext(new MemoryStream(), + "/LITTLEBIGPLANETPS3_XML/notification", + "MM_AUTH=unittest", + null, + new UseDigestAttribute()); DigestMiddleware middleware = new(httpContext => { httpContext.Response.StatusCode = 200; httpContext.Response.WriteAsync(""); return Task.CompletedTask; }, - true); + ["bruh",]); await middleware.InvokeAsync(context); const int expectedCode = 403; - Assert.True(expectedCode == context.Response.StatusCode, - "The digest middleware accepted the request when it shouldn't have (are you running this test in Debug mode?)"); + Assert.Equal(expectedCode, context.Response.StatusCode); Assert.False(context.Response.Headers.TryGetValue("X-Digest-A", out _)); Assert.False(context.Response.Headers.TryGetValue("X-Digest-B", out _)); } @@ -80,28 +94,23 @@ public class DigestMiddlewareTests [Fact] public async Task DigestMiddleware_ShouldReject_WhenRequestDigestInvalid() { - DefaultHttpContext context = new() - { - Request = + DefaultHttpContext context = GetHttpContext(new MemoryStream(), + "/LITTLEBIGPLANETPS3_XML/notification", + "MM_AUTH=unittest", + new Dictionary { - Body = new MemoryStream(), - Path = "/LITTLEBIGPLANETPS3_XML/notification", - Headers = { - KeyValuePair.Create("Cookie", "MM_AUTH=unittest"), - KeyValuePair.Create("X-Digest-A", "invalid_digest"), + "X-Digest-A", "invalid_digest" }, }, - }; - ServerConfiguration.Instance.DigestKey.PrimaryDigestKey = "bruh"; - ServerConfiguration.Instance.DigestKey.AlternateDigestKey = "test"; + new UseDigestAttribute()); DigestMiddleware middleware = new(httpContext => { httpContext.Response.StatusCode = 200; httpContext.Response.WriteAsync(""); return Task.CompletedTask; }, - true); + ["bruh",]); await middleware.InvokeAsync(context); @@ -115,28 +124,24 @@ public class DigestMiddlewareTests [Fact] public async Task DigestMiddleware_ShouldUseAlternateDigest_WhenPrimaryDigestInvalid() { - DefaultHttpContext context = new() - { - Request = + DefaultHttpContext context = GetHttpContext(new MemoryStream(), + "/LITTLEBIGPLANETPS3_XML/notification", + "MM_AUTH=unittest", + new Dictionary { - Body = new MemoryStream(), - Path = "/LITTLEBIGPLANETPS3_XML/notification", - Headers = { - KeyValuePair.Create("Cookie", "MM_AUTH=unittest"), - KeyValuePair.Create("X-Digest-A", "df619790a2579a077eae4a6b6864966ff4768723"), + "X-Digest-A", "df619790a2579a077eae4a6b6864966ff4768723" }, }, - }; - ServerConfiguration.Instance.DigestKey.PrimaryDigestKey = "test"; - ServerConfiguration.Instance.DigestKey.AlternateDigestKey = "bruh"; + new UseDigestAttribute()); + DigestMiddleware middleware = new(httpContext => { httpContext.Response.StatusCode = 200; httpContext.Response.WriteAsync(""); return Task.CompletedTask; }, - true); + ["test", "bruh",]); await middleware.InvokeAsync(context); @@ -152,28 +157,24 @@ public class DigestMiddlewareTests } [Fact] - public async Task DigestMiddleware_ShouldNotReject_WhenRequestingAnnounce() + public async Task DigestMiddleware_ShouldNotReject_WhenNotEnforcingDigest() { - DefaultHttpContext context = new() - { - Request = + DefaultHttpContext context = GetHttpContext(new MemoryStream(), + "/LITTLEBIGPLANETPS3_XML/announce", + "MM_AUTH=unittest", + new Dictionary(), + new UseDigestAttribute { - Body = new MemoryStream(), - Path = "/LITTLEBIGPLANETPS3_XML/announce", - Headers = - { - KeyValuePair.Create("Cookie", "MM_AUTH=unittest"), - }, - }, - }; - ServerConfiguration.Instance.DigestKey.PrimaryDigestKey = "bruh"; + EnforceDigest = false, + }); + DigestMiddleware middleware = new(httpContext => { httpContext.Response.StatusCode = 200; httpContext.Response.WriteAsync(""); return Task.CompletedTask; }, - true); + ["bruh",]); await middleware.InvokeAsync(context); @@ -191,26 +192,24 @@ public class DigestMiddlewareTests [Fact] public async Task DigestMiddleware_ShouldCalculate_WhenAuthCookieEmpty() { - DefaultHttpContext context = new() - { - Request = + DefaultHttpContext context = GetHttpContext(new MemoryStream(), + "/LITTLEBIGPLANETPS3_XML/notification", + "", + new Dictionary { - Body = new MemoryStream(), - Path = "/LITTLEBIGPLANETPS3_XML/notification", - Headers = { - KeyValuePair.Create("X-Digest-A", "0a06d25662c2d3bab2a767c0c504898df2385e62"), + "X-Digest-A", "0a06d25662c2d3bab2a767c0c504898df2385e62" }, }, - }; - ServerConfiguration.Instance.DigestKey.PrimaryDigestKey = "bruh"; + new UseDigestAttribute()); + DigestMiddleware middleware = new(httpContext => { httpContext.Response.StatusCode = 200; httpContext.Response.WriteAsync(""); return Task.CompletedTask; }, - true); + ["bruh",]); await middleware.InvokeAsync(context); @@ -228,27 +227,24 @@ public class DigestMiddlewareTests [Fact] public async Task DigestMiddleware_ShouldComputeDigestsWithNoBody_WhenDigestsEnabled() { - DefaultHttpContext context = new() - { - Request = + DefaultHttpContext context = GetHttpContext(new MemoryStream(), + "/LITTLEBIGPLANETPS3_XML/notification", + "MM_AUTH=unittest", + new Dictionary { - Body = new MemoryStream(), - Path = "/LITTLEBIGPLANETPS3_XML/notification", - Headers = { - KeyValuePair.Create("Cookie", "MM_AUTH=unittest"), - KeyValuePair.Create("X-Digest-A", "df619790a2579a077eae4a6b6864966ff4768723"), + "X-Digest-A", "df619790a2579a077eae4a6b6864966ff4768723" }, }, - }; - ServerConfiguration.Instance.DigestKey.PrimaryDigestKey = "bruh"; + new UseDigestAttribute()); + DigestMiddleware middleware = new(httpContext => { httpContext.Response.StatusCode = 200; httpContext.Response.WriteAsync(""); return Task.CompletedTask; }, - true); + ["bruh",]); await middleware.InvokeAsync(context); @@ -266,27 +262,24 @@ public class DigestMiddlewareTests [Fact] public async Task DigestMiddleware_ShouldComputeDigestsWithBody_WhenDigestsEnabled_AndNoResponseBody() { - DefaultHttpContext context = new() - { - Request = + DefaultHttpContext context = GetHttpContext(new MemoryStream("digest test"u8.ToArray()), + "/LITTLEBIGPLANETPS3_XML/filter", + "MM_AUTH=unittest", + new Dictionary { - Body = new MemoryStream("digest test"u8.ToArray()), - Path = "/LITTLEBIGPLANETPS3_XML/filter", - Headers = { - KeyValuePair.Create("Cookie", "MM_AUTH=unittest"), - KeyValuePair.Create("X-Digest-A", "3105059f9283773f7982a4d79455bcc97c330f10"), + "X-Digest-A", "3105059f9283773f7982a4d79455bcc97c330f10" }, }, - }; - ServerConfiguration.Instance.DigestKey.PrimaryDigestKey = "bruh"; + new UseDigestAttribute()); + DigestMiddleware middleware = new(httpContext => { httpContext.Response.StatusCode = 200; httpContext.Response.WriteAsync(""); return Task.CompletedTask; }, - true); + ["bruh",]); await middleware.InvokeAsync(context); @@ -304,27 +297,24 @@ public class DigestMiddlewareTests [Fact] public async Task DigestMiddleware_ShouldComputeDigestsWithBody_WhenDigestsEnabled_AndResponseBody() { - DefaultHttpContext context = new() - { - Request = + DefaultHttpContext context = GetHttpContext(new MemoryStream("digest test"u8.ToArray()), + "/LITTLEBIGPLANETPS3_XML/filter", + "MM_AUTH=unittest", + new Dictionary { - Body = new MemoryStream("digest test"u8.ToArray()), - Path = "/LITTLEBIGPLANETPS3_XML/filter", - Headers = { - KeyValuePair.Create("Cookie", "MM_AUTH=unittest"), - KeyValuePair.Create("X-Digest-A", "3105059f9283773f7982a4d79455bcc97c330f10"), + "X-Digest-A", "3105059f9283773f7982a4d79455bcc97c330f10" }, }, - }; - ServerConfiguration.Instance.DigestKey.PrimaryDigestKey = "bruh"; + new UseDigestAttribute()); + DigestMiddleware middleware = new(httpContext => { httpContext.Response.StatusCode = 200; httpContext.Response.WriteAsync("digest test"); return Task.CompletedTask; }, - true); + ["bruh",]); await middleware.InvokeAsync(context); @@ -340,29 +330,31 @@ public class DigestMiddlewareTests } [Fact] - public async Task DigestMiddleware_ShouldComputeDigestsWithBody_WhenUploading() + public async Task DigestMiddleware_ShouldExcludeBody_WithAttributeSetting() { - DefaultHttpContext context = new() - { - Request = + DefaultHttpContext context = GetHttpContext(new MemoryStream("digest test"u8.ToArray()), + "/LITTLEBIGPLANETPS3_XML/upload/unittesthash", + "MM_AUTH=unittest", + new Dictionary { - Body = new MemoryStream("digest test"u8.ToArray()), - Path = "/LITTLEBIGPLANETPS3_XML/upload/unittesthash", - Headers = { - KeyValuePair.Create("Cookie", "MM_AUTH=unittest"), - KeyValuePair.Create("X-Digest-B", "2e54cd2bc69ff8c1ff85dd3b4f62e0a0e27d9e23"), + "X-Digest-B", "2e54cd2bc69ff8c1ff85dd3b4f62e0a0e27d9e23" }, }, - }; - ServerConfiguration.Instance.DigestKey.PrimaryDigestKey = "bruh"; + new UseDigestAttribute + { + DigestHeaderName = "X-Digest-B", + ExcludeBodyFromDigest = true, + }); + + DigestMiddleware middleware = new(httpContext => { httpContext.Response.StatusCode = 200; httpContext.Response.WriteAsync(""); return Task.CompletedTask; }, - true); + ["bruh",]); await middleware.InvokeAsync(context); @@ -398,7 +390,8 @@ public class DigestMiddlewareTests }, }, }; - ServerConfiguration.Instance.DigestKey.PrimaryDigestKey = "bruh"; + context.SetEndpoint(new Endpoint(null, new EndpointMetadataCollection(new UseDigestAttribute()), null)); + DigestMiddleware middleware = new(httpContext => { httpContext.Response.StatusCode = 200; @@ -406,7 +399,7 @@ public class DigestMiddlewareTests httpContext.Response.Headers.ContentType = "text/xml"; return Task.CompletedTask; }, - true); + ["bruh",]); await middleware.InvokeAsync(context);