diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs index 70765ea0..22ce63d5 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/CommentController.cs @@ -22,8 +22,6 @@ namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers; public class CommentController : ControllerBase { private readonly DatabaseContext database; - - private static readonly bool emailEnforcementEnabled = EnforceEmailConfiguration.Instance.EnableEmailEnforcement; public CommentController(DatabaseContext database) { this.database = database; @@ -37,9 +35,6 @@ public class CommentController : ControllerBase UserEntity? user = await this.database.UserFromGameToken(token); if (user == null) return this.Unauthorized(); - // Return bad request on unverified email if enforcement is enabled - if (emailEnforcementEnabled && !user.EmailAddressVerified) return this.BadRequest(); - // Return bad request if both are true or both are false if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest(); @@ -57,9 +52,6 @@ public class CommentController : ControllerBase UserEntity? user = await this.database.UserFromGameToken(token); if (user == null) return this.Unauthorized(); - // Return bad request on unverified email if enforcement is enabled - if (emailEnforcementEnabled && !user.EmailAddressVerified) return this.BadRequest(); - if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest(); int originalSlotId = slotId; @@ -127,9 +119,6 @@ public class CommentController : ControllerBase UserEntity? user = await this.database.UserFromGameToken(token); if (user == null) return this.Unauthorized(); - // Return bad request on unverified email if enforcement is enabled - if (emailEnforcementEnabled && !user.EmailAddressVerified) return this.BadRequest(); - // Deny request if in read-only mode if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest(); @@ -168,10 +157,6 @@ public class CommentController : ControllerBase public async Task DeleteComment([FromQuery] int commentId, string? username, string? slotType, int slotId) { GameTokenEntity token = this.GetToken(); - UserEntity? user = await this.database.UserFromGameToken(token); - - // Return bad request on unverified email if enforcement is enabled - if (emailEnforcementEnabled && !user.EmailAddressVerified) return this.BadRequest(); // Deny request if in read-only mode if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest(); diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Matching/EnterLevelController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Matching/EnterLevelController.cs index d2394f3a..aeebd756 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Matching/EnterLevelController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Matching/EnterLevelController.cs @@ -1,10 +1,7 @@ #nullable enable -using System.Runtime.CompilerServices; using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Helpers; -using LBPUnion.ProjectLighthouse.Configuration; -using LBPUnion.ProjectLighthouse.Migrations; using LBPUnion.ProjectLighthouse.Types.Entities.Interaction; using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Profile; diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Matching/MatchController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Matching/MatchController.cs index cec69799..fe210efd 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Matching/MatchController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Matching/MatchController.cs @@ -25,8 +25,6 @@ public class MatchController : ControllerBase { private readonly DatabaseContext database; - private static readonly bool emailEnforcementEnabled = EnforceEmailConfiguration.Instance.EnableEmailEnforcement; - public MatchController(DatabaseContext database) { this.database = database; @@ -44,9 +42,6 @@ public class MatchController : ControllerBase UserEntity? user = await this.database.UserFromGameToken(token); if (user == null) return this.Unauthorized(); - // Return bad request on unverified email if enforcement is enabled - if (emailEnforcementEnabled && !user.EmailAddressVerified) return this.BadRequest(); - await LastContactHelper.SetLastContact(this.database, user, token.GameVersion, token.Platform); // Do not allow matchmaking if it has been disabled diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Resources/PhotosController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Resources/PhotosController.cs index 2feb0e3c..2acc3dcb 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Resources/PhotosController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Resources/PhotosController.cs @@ -27,8 +27,6 @@ public class PhotosController : ControllerBase { private readonly DatabaseContext database; - private static readonly bool emailEnforcementEnabled = EnforceEmailConfiguration.Instance.EnableEmailEnforcement; - public PhotosController(DatabaseContext database) { this.database = database; @@ -41,9 +39,6 @@ public class PhotosController : ControllerBase UserEntity? user = await this.database.UserFromGameToken(token); if (user == null) return this.Unauthorized(); - // Return bad request on unverified email if enforcement is enabled - if (emailEnforcementEnabled && !user.EmailAddressVerified) return this.BadRequest(); - // Deny request if in read-only mode if (ServerConfiguration.Instance.UserGeneratedContentLimits.ReadOnlyMode) return this.BadRequest(); @@ -181,12 +176,6 @@ public class PhotosController : ControllerBase [HttpGet("photos/{slotType}/{id:int}")] public async Task SlotPhotos(string slotType, int id, [FromQuery] string? by) { - GameTokenEntity token = this.GetToken(); - UserEntity? user = await this.database.UserFromGameToken(token); - - // Return bad request on unverified email if enforcement is enabled - if (emailEnforcementEnabled && !user.EmailAddressVerified) return this.BadRequest(); - if (SlotHelper.IsTypeInvalid(slotType)) return this.BadRequest(); if (slotType == "developer") id = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer); @@ -248,10 +237,6 @@ public class PhotosController : ControllerBase public async Task DeletePhoto(int id) { GameTokenEntity token = this.GetToken(); - UserEntity? user = await this.database.UserFromGameToken(token); - - // Return bad request on unverified email if enforcement is enabled - if (emailEnforcementEnabled && !user.EmailAddressVerified) return this.BadRequest(); PhotoEntity? photo = await this.database.Photos.FirstOrDefaultAsync(p => p.PhotoId == id); if (photo == null) return this.NotFound(); diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Resources/ResourcesController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Resources/ResourcesController.cs index 800046a1..630be2c9 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Resources/ResourcesController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Resources/ResourcesController.cs @@ -1,15 +1,12 @@ #nullable enable using System.Text; using LBPUnion.ProjectLighthouse.Configuration; -using LBPUnion.ProjectLighthouse.Database; using LBPUnion.ProjectLighthouse.Extensions; using LBPUnion.ProjectLighthouse.Files; using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Misc; -using LBPUnion.ProjectLighthouse.Types.Entities.Profile; using LBPUnion.ProjectLighthouse.Types.Logging; using LBPUnion.ProjectLighthouse.Types.Resources; -using LBPUnion.ProjectLighthouse.Types.Entities.Token; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using IOFile = System.IO.File; @@ -22,18 +19,9 @@ namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Resources; [Route("LITTLEBIGPLANETPS3_XML")] public class ResourcesController : ControllerBase { - private readonly DatabaseContext database; - - public ResourcesController(DatabaseContext database) - { - this.database = database; - } - [HttpPost("showModerated")] public IActionResult ShowModerated() => this.Ok(new ResourceList()); - private static readonly bool emailEnforcementEnabled = EnforceEmailConfiguration.Instance.EnableEmailEnforcement; - [HttpPost("filterResources")] [HttpPost("showNotUploaded")] public async Task FilterResources() @@ -49,12 +37,6 @@ public class ResourcesController : ControllerBase [HttpGet("r/{hash}")] public async Task GetResource(string hash) { - GameTokenEntity token = this.GetToken(); - UserEntity? user = await this.database.UserFromGameToken(token); - - // Return bad request on unverified email if enforcement is enabled - if (emailEnforcementEnabled && !user.EmailAddressVerified) return this.BadRequest(); - string path = FileHelper.GetResourcePath(hash); string fullPath = Path.GetFullPath(path); @@ -71,12 +53,6 @@ public class ResourcesController : ControllerBase [HttpPost("upload/{hash}")] public async Task UploadResource(string hash) { - GameTokenEntity token = this.GetToken(); - UserEntity? user = await this.database.UserFromGameToken(token); - - // Return bad request on unverified email if enforcement is enabled - if (emailEnforcementEnabled && !user.EmailAddressVerified) return this.BadRequest(); - string assetsDirectory = FileHelper.ResourcePath; string path = FileHelper.GetResourcePath(hash); string fullPath = Path.GetFullPath(path); diff --git a/ProjectLighthouse.Servers.GameServer/Middlewares/EmailEnforcementMiddleware.cs b/ProjectLighthouse.Servers.GameServer/Middlewares/EmailEnforcementMiddleware.cs new file mode 100644 index 00000000..c4cf8e8e --- /dev/null +++ b/ProjectLighthouse.Servers.GameServer/Middlewares/EmailEnforcementMiddleware.cs @@ -0,0 +1,89 @@ +using LBPUnion.ProjectLighthouse.Configuration; +using LBPUnion.ProjectLighthouse.Database; +using LBPUnion.ProjectLighthouse.Middlewares; +using LBPUnion.ProjectLighthouse.Types.Entities.Profile; +using LBPUnion.ProjectLighthouse.Types.Entities.Token; + +namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Middlewares; + +public class EmailEnforcementMiddleware : MiddlewareDBContext +{ + private static readonly HashSet enforcedPaths = new() + { + "rateUserComment", + "rateComment", + "comments", + "userComments", + "postUserComment", + "postComment", + "deleteUserComment", + "deleteComment", + "slots", + "upload", + "r", + "uploadPhoto", + "photos", + "deletePhoto", + "match", + "play", + "enterLevel", + "user", + "users", + "updateUser", + "update_my_pins", + "startPublish", + "publish", + "unpublish", + "playlists", + "tags", + "tag", + "searches", + "genres", + }; + + public EmailEnforcementMiddleware(RequestDelegate next) : base(next) + { } + + public override async Task InvokeAsync(HttpContext context, DatabaseContext database) + { + // Split path into segments + string[] pathSegments = context.Request.Path.ToString().Split("/"); + bool emailEnforcementEnabled = EnforceEmailConfiguration.Instance.EnableEmailEnforcement; + + if (pathSegments[0] == "LITTLEBIGPLANETPS3_XML") + { + // Get user via GameToken + GameTokenEntity? token = await database.GameTokenFromRequest(context.Request); + UserEntity? user = await database.UserFromGameToken(token); + + // Check second part of path to see if client is within an enforced path + if (enforcedPaths.Contains(pathSegments[1])) + { + // Check if user is valid + if (user == null) + { + // Send bad request status + context.Response.StatusCode = StatusCodes.Status400BadRequest; + await context.Response.WriteAsync("Not a valid user"); + + // Don't go to next in pipeline + return; + } + + // Check if email is there and verified + if (emailEnforcementEnabled && (!user.EmailAddressVerified || user.EmailAddress == null)) + { + // Send bad request status + context.Response.StatusCode = StatusCodes.Status400BadRequest; + await context.Response.WriteAsync("Invalid user email address"); + + // Don't go to next in pipeline + return; + } + } + } + + // Go to next in pipeline + await this.next(context); + } +} \ No newline at end of file diff --git a/ProjectLighthouse.Servers.GameServer/Startup/GameServerStartup.cs b/ProjectLighthouse.Servers.GameServer/Startup/GameServerStartup.cs index 0d372e8f..8b91a3e6 100644 --- a/ProjectLighthouse.Servers.GameServer/Startup/GameServerStartup.cs +++ b/ProjectLighthouse.Servers.GameServer/Startup/GameServerStartup.cs @@ -107,6 +107,7 @@ public class GameServerStartup app.UseMiddleware(); app.UseMiddleware(computeDigests); app.UseMiddleware(); + app.UseMiddleware(); app.UseRouting(); diff --git a/ProjectLighthouse/Configuration/EnforceEmailConfiguration.cs b/ProjectLighthouse/Configuration/EnforceEmailConfiguration.cs index b044df99..1b747763 100644 --- a/ProjectLighthouse/Configuration/EnforceEmailConfiguration.cs +++ b/ProjectLighthouse/Configuration/EnforceEmailConfiguration.cs @@ -18,7 +18,10 @@ public class EnforceEmailConfiguration : ConfigurationBase