diff --git a/.idea/.idea.ProjectLighthouse/.idea/dataSources.xml b/.idea/.idea.ProjectLighthouse/.idea/dataSources.xml index 4b88ef02..c64bade5 100644 --- a/.idea/.idea.ProjectLighthouse/.idea/dataSources.xml +++ b/.idea/.idea.ProjectLighthouse/.idea/dataSources.xml @@ -8,5 +8,12 @@ jdbc:mysql://localhost:3306/lighthouse $ProjectFileDir$ + + mariadb + true + org.mariadb.jdbc.Driver + jdbc:mariadb://localhost:3306 + $ProjectFileDir$ + \ No newline at end of file diff --git a/.idea/.idea.ProjectLighthouse/.idea/jsLibraryMappings.xml b/.idea/.idea.ProjectLighthouse/.idea/jsLibraryMappings.xml new file mode 100644 index 00000000..e0f60e14 --- /dev/null +++ b/.idea/.idea.ProjectLighthouse/.idea/jsLibraryMappings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ProjectLighthouse.Tests/LighthouseTest.cs b/ProjectLighthouse.Tests/LighthouseTest.cs index 3efb3684..22babd5c 100644 --- a/ProjectLighthouse.Tests/LighthouseTest.cs +++ b/ProjectLighthouse.Tests/LighthouseTest.cs @@ -9,6 +9,7 @@ using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Types; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; +using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Tests { @@ -25,9 +26,15 @@ namespace LBPUnion.ProjectLighthouse.Tests this.Client = this.Server.CreateClient(); } - public async Task AuthenticateResponse(int number = 0) + public async Task AuthenticateResponse(int number = 0, bool createUser = true) { const string username = "unitTestUser"; + if (createUser) + { + await using Database database = new(); + if (await database.Users.FirstOrDefaultAsync(u => u.Username == $"{username}{number}") == null) + await database.CreateUser($"{username}{number}", HashHelper.BCryptHash($"unitTestPassword{number}")); + } string stringContent = $"{LoginData.UsernamePrefix}{username}{number}{(char)0x00}"; diff --git a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs index 346b957b..d7f5fd19 100644 --- a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs +++ b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs @@ -49,11 +49,10 @@ namespace LBPUnion.ProjectLighthouse.Tests { LoginResult loginResult = await this.Authenticate(); - HttpResponseMessage response = await this.AuthenticatedRequest("/LITTLEBIGPLANETPS3_XML/announce", loginResult.AuthTicket); + HttpResponseMessage response = await this.AuthenticatedRequest("/LITTLEBIGPLANETPS3_XML/enterLevel/1", loginResult.AuthTicket); string responseContent = await response.Content.ReadAsStringAsync(); - Assert.True(response.IsSuccessStatusCode); - Assert.Contains("You are now logged in", responseContent); + Assert.False(response.StatusCode == HttpStatusCode.Forbidden); } [DatabaseFact] diff --git a/ProjectLighthouse.Tests/Tests/DatabaseTests.cs b/ProjectLighthouse.Tests/Tests/DatabaseTests.cs index f2071792..01d49d1f 100644 --- a/ProjectLighthouse.Tests/Tests/DatabaseTests.cs +++ b/ProjectLighthouse.Tests/Tests/DatabaseTests.cs @@ -1,5 +1,6 @@ using System; using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Types; namespace LBPUnion.ProjectLighthouse.Tests @@ -12,8 +13,8 @@ namespace LBPUnion.ProjectLighthouse.Tests await using Database database = new(); int rand = new Random().Next(); - User userA = await database.CreateUser("createUserTwiceTest" + rand); - User userB = await database.CreateUser("createUserTwiceTest" + rand); + User userA = await database.CreateUser("createUserTwiceTest" + rand, HashHelper.GenerateAuthToken()); + User userB = await database.CreateUser("createUserTwiceTest" + rand, HashHelper.GenerateAuthToken()); database.Users.Remove(userA); database.Users.Remove(userB); diff --git a/ProjectLighthouse.Tests/Tests/MatchTests.cs b/ProjectLighthouse.Tests/Tests/MatchTests.cs index 5c52f9f5..721dc941 100644 --- a/ProjectLighthouse.Tests/Tests/MatchTests.cs +++ b/ProjectLighthouse.Tests/Tests/MatchTests.cs @@ -3,6 +3,7 @@ using System.Net.Http; using System.Text; using System.Threading; using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Types; using Xunit; @@ -36,7 +37,6 @@ namespace LBPUnion.ProjectLighthouse.Tests semaphore.Release(); Assert.True(result.IsSuccessStatusCode); } - public async Task GetPlayerCount() => Convert.ToInt32(await this.Client.GetStringAsync("LITTLEBIGPLANETPS3_XML/totalPlayerCount")); [DatabaseFact] public async Task ShouldIncrementPlayerCount() @@ -45,14 +45,14 @@ namespace LBPUnion.ProjectLighthouse.Tests await semaphore.WaitAsync(); - int oldPlayerCount = await this.GetPlayerCount(); + int oldPlayerCount = await StatisticsHelper.RecentMatches(); HttpResponseMessage result = await this.AuthenticatedUploadDataRequest ("LITTLEBIGPLANETPS3_XML/match", Encoding.ASCII.GetBytes("[UpdateMyPlayerData,[\"Player\":\"1984\"]]"), loginResult.AuthTicket); Assert.True(result.IsSuccessStatusCode); - int playerCount = await this.GetPlayerCount(); + int playerCount = await StatisticsHelper.RecentMatches(); semaphore.Release(); Assert.Equal(oldPlayerCount + 1, playerCount); diff --git a/ProjectLighthouse.Tests/Tests/SlotTests.cs b/ProjectLighthouse.Tests/Tests/SlotTests.cs index 52f4d690..7af3d264 100644 --- a/ProjectLighthouse.Tests/Tests/SlotTests.cs +++ b/ProjectLighthouse.Tests/Tests/SlotTests.cs @@ -1,5 +1,6 @@ using System.Net.Http; using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Profiles; @@ -14,8 +15,8 @@ namespace LBPUnion.ProjectLighthouse.Tests { await using Database database = new(); - User userA = await database.CreateUser("unitTestUser0"); - User userB = await database.CreateUser("unitTestUser1"); + User userA = await database.CreateUser("unitTestUser0", HashHelper.GenerateAuthToken()); + User userB = await database.CreateUser("unitTestUser1", HashHelper.GenerateAuthToken()); Location l = new() { diff --git a/ProjectLighthouse.sln.DotSettings b/ProjectLighthouse.sln.DotSettings index 34c3a59a..54a00f4c 100644 --- a/ProjectLighthouse.sln.DotSettings +++ b/ProjectLighthouse.sln.DotSettings @@ -78,7 +78,9 @@ MM NAT NP + PS PSP + RPCS <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="" Suffix="" Style="aaBb" /></Policy> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> diff --git a/ProjectLighthouse/Controllers/CommentController.cs b/ProjectLighthouse/Controllers/CommentController.cs index fd7cbbbf..de9ffa5c 100644 --- a/ProjectLighthouse/Controllers/CommentController.cs +++ b/ProjectLighthouse/Controllers/CommentController.cs @@ -47,7 +47,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers XmlSerializer serializer = new(typeof(Comment)); Comment? comment = (Comment?)serializer.Deserialize(new StringReader(bodyString)); - User? poster = await this.database.UserFromRequest(this.Request); + User? poster = await this.database.UserFromGameRequest(this.Request); if (poster == null) return this.StatusCode(403, ""); User? target = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); @@ -66,7 +66,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("deleteUserComment/{username}")] public async Task DeleteComment([FromQuery] int commentId, string username) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); Comment? comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId); diff --git a/ProjectLighthouse/Controllers/EnterLevelController.cs b/ProjectLighthouse/Controllers/EnterLevelController.cs index af799c02..3cd45500 100644 --- a/ProjectLighthouse/Controllers/EnterLevelController.cs +++ b/ProjectLighthouse/Controllers/EnterLevelController.cs @@ -24,13 +24,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("play/user/{slotId}")] public async Task PlayLevel(int slotId) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slotId); if (slot == null) return this.StatusCode(403, ""); - Token? token = await this.database.TokenFromRequest(this.Request); + GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); GameVersion gameVersion = token.GameVersion; @@ -94,7 +94,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("enterLevel/{id:int}")] public async Task EnterLevel(int id) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id); diff --git a/ProjectLighthouse/Controllers/ExternalAuth/AuthenticationController.cs b/ProjectLighthouse/Controllers/ExternalAuth/AuthenticationController.cs new file mode 100644 index 00000000..323ea19f --- /dev/null +++ b/ProjectLighthouse/Controllers/ExternalAuth/AuthenticationController.cs @@ -0,0 +1,91 @@ +#nullable enable +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Types; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace LBPUnion.ProjectLighthouse.Controllers.ExternalAuth +{ + [ApiController] + [Route("/authentication")] + public class AuthenticationController : ControllerBase + { + private readonly Database database; + + public AuthenticationController(Database database) + { + this.database = database; + } + + [HttpGet("approve/{id:int}")] + public async Task Approve(int id) + { + User? user = this.database.UserFromWebRequest(this.Request); + if (user == null) return this.Redirect("/login"); + + AuthenticationAttempt? authAttempt = await this.database.AuthenticationAttempts.Include + (a => a.GameToken) + .FirstOrDefaultAsync(a => a.AuthenticationAttemptId == id); + if (authAttempt == null) return this.NotFound(); + + if (authAttempt.GameToken.UserId != user.UserId) return this.StatusCode(403, ""); + + authAttempt.GameToken.Approved = true; + this.database.AuthenticationAttempts.Remove(authAttempt); + + await this.database.SaveChangesAsync(); + + return this.Redirect("~/authentication"); + } + + [HttpGet("deny/{id:int}")] + public async Task Deny(int id) + { + User? user = this.database.UserFromWebRequest(this.Request); + if (user == null) return this.Redirect("/login"); + + AuthenticationAttempt? authAttempt = await this.database.AuthenticationAttempts.Include + (a => a.GameToken) + .FirstOrDefaultAsync(a => a.AuthenticationAttemptId == id); + if (authAttempt == null) return this.NotFound(); + + if (authAttempt.GameToken.UserId != user.UserId) return this.StatusCode(403, ""); + + this.database.GameTokens.Remove(authAttempt.GameToken); + this.database.AuthenticationAttempts.Remove(authAttempt); + + DeniedAuthenticationHelper.SetDeniedAt($"{authAttempt.IPAddress}|{user.Username}"); + + await this.database.SaveChangesAsync(); + + return this.Redirect("~/authentication"); + } + + [HttpGet("denyAll")] + public async Task DenyAll() + { + User? user = this.database.UserFromWebRequest(this.Request); + if (user == null) return this.Redirect("/login"); + + List authAttempts = await this.database.AuthenticationAttempts.Include + (a => a.GameToken) + .Where(a => a.GameToken.UserId == user.UserId) + .ToListAsync(); + + foreach (AuthenticationAttempt authAttempt in authAttempts) + { + this.database.GameTokens.Remove(authAttempt.GameToken); + this.database.AuthenticationAttempts.Remove(authAttempt); + + DeniedAuthenticationHelper.SetDeniedAt($"{authAttempt.IPAddress}|{user.Username}"); + } + + await this.database.SaveChangesAsync(); + + return this.Redirect("~/authentication"); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/FriendsController.cs b/ProjectLighthouse/Controllers/FriendsController.cs index e4b2ef6a..9fc3b414 100644 --- a/ProjectLighthouse/Controllers/FriendsController.cs +++ b/ProjectLighthouse/Controllers/FriendsController.cs @@ -26,7 +26,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("npdata")] public async Task NPData() { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); this.Request.Body.Position = 0; @@ -69,13 +69,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("myFriends")] public async Task MyFriends() { - (User, Token)? userAndToken = await this.database.UserAndTokenFromRequest(this.Request); + (User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request); if (userAndToken == null) return this.StatusCode(403, ""); // ReSharper disable once PossibleInvalidOperationException User user = userAndToken.Value.Item1; - Token token = userAndToken.Value.Item2; + GameToken gameToken = userAndToken.Value.Item2; if (!FriendHelper.FriendIdsByUserId.TryGetValue(user.UserId, out int[]? friendIds) || friendIds == null) { @@ -88,7 +88,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers User? friend = await this.database.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.UserId == friendId); if (friend == null) continue; - friends += friend.Serialize(token.GameVersion); + friends += friend.Serialize(gameToken.GameVersion); } return this.Ok(LbpSerializer.StringElement("myFriends", friends)); diff --git a/ProjectLighthouse/Controllers/ListController.cs b/ProjectLighthouse/Controllers/ListController.cs index f4139dc1..7b751551 100644 --- a/ProjectLighthouse/Controllers/ListController.cs +++ b/ProjectLighthouse/Controllers/ListController.cs @@ -29,7 +29,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("slots/lolcatftw/{username}")] public async Task GetLevelQueue(string username, [FromQuery] int pageSize, [FromQuery] int pageStart) { - Token? token = await this.database.TokenFromRequest(this.Request); + GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); GameVersion gameVersion = token.GameVersion; @@ -56,7 +56,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("lolcatftw/add/user/{id:int}")] public async Task AddQueuedLevel(int id) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); QueuedLevel? queuedLevel = await this.database.QueuedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id); @@ -79,7 +79,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("lolcatftw/remove/user/{id:int}")] public async Task RemoveQueuedLevel(int id) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); QueuedLevel? queuedLevel = await this.database.QueuedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id); @@ -93,7 +93,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("lolcatftw/clear")] public async Task ClearQueuedLevels() { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); this.database.QueuedLevels.RemoveRange(this.database.QueuedLevels.Where(q => q.UserId == user.UserId)); @@ -110,7 +110,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("favouriteSlots/{username}")] public async Task GetFavouriteSlots(string username, [FromQuery] int pageSize, [FromQuery] int pageStart) { - Token? token = await this.database.TokenFromRequest(this.Request); + GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); GameVersion gameVersion = token.GameVersion; @@ -137,7 +137,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("favourite/slot/user/{id:int}")] public async Task AddFavouriteSlot(int id) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); HeartedLevel? heartedLevel = await this.database.HeartedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id); @@ -160,7 +160,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("unfavourite/slot/user/{id:int}")] public async Task RemoveFavouriteSlot(int id) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); HeartedLevel? heartedLevel = await this.database.HeartedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id); @@ -180,7 +180,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("favouriteUsers/{username}")] public async Task GetFavouriteUsers(string username, [FromQuery] int pageSize, [FromQuery] int pageStart) { - Token? token = await this.database.TokenFromRequest(this.Request); + GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); IEnumerable heartedProfiles = this.database.HeartedProfiles.Include @@ -204,7 +204,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("favourite/user/{username}")] public async Task AddFavouriteUser(string username) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); @@ -231,7 +231,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("unfavourite/user/{username}")] public async Task RemoveFavouriteUser(string username) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); diff --git a/ProjectLighthouse/Controllers/LoginController.cs b/ProjectLighthouse/Controllers/LoginController.cs index 6bce4863..19efa5e9 100644 --- a/ProjectLighthouse/Controllers/LoginController.cs +++ b/ProjectLighthouse/Controllers/LoginController.cs @@ -1,5 +1,6 @@ #nullable enable using System.IO; +using System.Linq; using System.Net; using System.Threading.Tasks; using Kettu; @@ -8,6 +9,7 @@ using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types.Settings; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Controllers { @@ -46,12 +48,44 @@ namespace LBPUnion.ProjectLighthouse.Controllers string userLocation = ipAddress.ToString(); - Token? token = await this.database.AuthenticateUser(loginData, userLocation, titleId); + GameToken? token = await this.database.AuthenticateUser(loginData, userLocation, titleId); if (token == null) return this.StatusCode(403, ""); - User? user = await this.database.UserFromToken(token); + User? user = await this.database.UserFromGameToken(token, true); if (user == null) return this.StatusCode(403, ""); + if (ServerSettings.Instance.UseExternalAuth) + { + string ipAddressAndName = $"{token.UserLocation}|{user.Username}"; + if (DeniedAuthenticationHelper.RecentlyDenied(ipAddressAndName) || (DeniedAuthenticationHelper.GetAttempts(ipAddressAndName) > 3)) + { + this.database.AuthenticationAttempts.RemoveRange + (this.database.AuthenticationAttempts.Include(a => a.GameToken).Where(a => a.GameToken.UserId == user.UserId)); + + DeniedAuthenticationHelper.AddAttempt(ipAddressAndName); + + await this.database.SaveChangesAsync(); + return this.StatusCode(403, ""); + } + + AuthenticationAttempt authAttempt = new() + { + GameToken = token, + GameTokenId = token.TokenId, + Timestamp = TimestampHelper.Timestamp, + IPAddress = userLocation, + Platform = token.GameVersion == GameVersion.LittleBigPlanetVita ? Platform.Vita : Platform.PS3, // TODO: properly identify RPCS3 + }; + + this.database.AuthenticationAttempts.Add(authAttempt); + } + else + { + token.Approved = true; + } + + await this.database.SaveChangesAsync(); + Logger.Log($"Successfully logged in user {user.Username} as {token.GameVersion} client ({titleId})", LoggerLevelLogin.Instance); // Create a new room on LBP2+/Vita diff --git a/ProjectLighthouse/Controllers/MatchController.cs b/ProjectLighthouse/Controllers/MatchController.cs index 94f4fff5..87bd6e31 100644 --- a/ProjectLighthouse/Controllers/MatchController.cs +++ b/ProjectLighthouse/Controllers/MatchController.cs @@ -32,13 +32,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers [Produces("text/plain")] public async Task Match() { - (User, Token)? userAndToken = await this.database.UserAndTokenFromRequest(this.Request); + (User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request); if (userAndToken == null) return this.StatusCode(403, ""); // ReSharper disable once PossibleInvalidOperationException User user = userAndToken.Value.Item1; - Token token = userAndToken.Value.Item2; + GameToken gameToken = userAndToken.Value.Item2; #region Parse match data @@ -97,7 +97,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers if (matchData is UpdateMyPlayerData playerData) { - MatchHelper.SetUserLocation(user.UserId, token.UserLocation); + MatchHelper.SetUserLocation(user.UserId, gameToken.UserLocation); Room? room = RoomHelper.FindRoomByUser(user, true); if (playerData.RoomState != null) @@ -108,7 +108,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers if (matchData is FindBestRoom && MatchHelper.UserLocations.Count > 1) { - FindBestRoomResponse? response = RoomHelper.FindBestRoom(user, token.UserLocation); + FindBestRoomResponse? response = RoomHelper.FindBestRoom(user, gameToken.UserLocation); if (response == null) return this.NotFound(); diff --git a/ProjectLighthouse/Controllers/MessageController.cs b/ProjectLighthouse/Controllers/MessageController.cs index beab0d93..aff3ddd6 100644 --- a/ProjectLighthouse/Controllers/MessageController.cs +++ b/ProjectLighthouse/Controllers/MessageController.cs @@ -27,10 +27,17 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("announce")] public async Task Announce() { - User user = await this.database.UserFromRequest(this.Request); + User user = await this.database.UserFromGameRequest(this.Request, true); if (user == null) return this.StatusCode(403, ""); - return this.Ok($"You are now logged in as user {user.Username} (id {user.UserId}).\n\n" + ServerSettings.Instance.EulaText); + return this.Ok + ( + $"Please stay on this screen.\n" + + $"Before continuing, you must approve this session at {ServerSettings.Instance.ExternalUrl}.\n" + + $"Please keep in mind that if the session is denied you may have to wait up to 5-10 minutes to try logging in again.\n" + + $"Once approved, you may press X and continue.\n\n" + + ServerSettings.Instance.EulaText + ); } [HttpGet("notification")] @@ -42,7 +49,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("filter")] public async Task Filter() { - User user = await this.database.UserFromRequest(this.Request); + User user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); string loggedText = await new StreamReader(this.Request.Body).ReadToEndAsync(); diff --git a/ProjectLighthouse/Controllers/PhotosController.cs b/ProjectLighthouse/Controllers/PhotosController.cs index 6dce4228..6d30d184 100644 --- a/ProjectLighthouse/Controllers/PhotosController.cs +++ b/ProjectLighthouse/Controllers/PhotosController.cs @@ -29,7 +29,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("uploadPhoto")] public async Task UploadPhoto() { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); this.Request.Body.Position = 0; @@ -120,7 +120,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("deletePhoto/{id:int}")] public async Task DeletePhoto(int id) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); Photo? photo = await this.database.Photos.FirstOrDefaultAsync(p => p.PhotoId == id); diff --git a/ProjectLighthouse/Controllers/PublishController.cs b/ProjectLighthouse/Controllers/PublishController.cs index d7094138..61444bc0 100644 --- a/ProjectLighthouse/Controllers/PublishController.cs +++ b/ProjectLighthouse/Controllers/PublishController.cs @@ -32,7 +32,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("startPublish")] public async Task StartPublish() { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); Slot? slot = await this.GetSlotFromBody(); @@ -65,14 +65,14 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("publish")] public async Task Publish() { -// User user = await this.database.UserFromRequest(this.Request); - (User, Token)? userAndToken = await this.database.UserAndTokenFromRequest(this.Request); +// User user = await this.database.UserFromGameRequest(this.Request); + (User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request); if (userAndToken == null) return this.StatusCode(403, ""); // ReSharper disable once PossibleInvalidOperationException User user = userAndToken.Value.Item1; - Token token = userAndToken.Value.Item2; + GameToken gameToken = userAndToken.Value.Item2; Slot? slot = await this.GetSlotFromBody(); if (slot == null || slot.Location == null) return this.BadRequest(); @@ -95,7 +95,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers slot.SlotId = oldSlot.SlotId; slot.FirstUploaded = oldSlot.FirstUploaded; slot.LastUpdated = TimeHelper.UnixTimeMilliseconds(); - slot.GameVersion = token.GameVersion; + slot.GameVersion = gameToken.GameVersion; this.database.Entry(oldSlot).CurrentValues.SetValues(slot); await this.database.SaveChangesAsync(); @@ -114,7 +114,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers slot.CreatorId = user.UserId; slot.FirstUploaded = TimeHelper.UnixTimeMilliseconds(); slot.LastUpdated = TimeHelper.UnixTimeMilliseconds(); - slot.GameVersion = token.GameVersion; + slot.GameVersion = gameToken.GameVersion; if (slot.MinimumPlayers == 0 || slot.MaximumPlayers == 0) { @@ -131,7 +131,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("unpublish/{id:int}")] public async Task Unpublish(int id) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); Slot? slot = await this.database.Slots.Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == id); diff --git a/ProjectLighthouse/Controllers/ResourcesController.cs b/ProjectLighthouse/Controllers/ResourcesController.cs index adb7734b..24949857 100644 --- a/ProjectLighthouse/Controllers/ResourcesController.cs +++ b/ProjectLighthouse/Controllers/ResourcesController.cs @@ -14,8 +14,8 @@ using IOFile = System.IO.File; namespace LBPUnion.ProjectLighthouse.Controllers { [ApiController] - [Route("LITTLEBIGPLANETPS3_XML/")] [Produces("text/xml")] + [Route("LITTLEBIGPLANETPS3_XML")] public class ResourcesController : ControllerBase { [HttpPost("showModerated")] @@ -39,6 +39,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers return this.Ok(LbpSerializer.StringElement("resources", resources)); } + [ResponseCache(Duration = 86400)] + [HttpGet("/gameAssets/{hash}")] [HttpGet("r/{hash}")] public IActionResult GetResource(string hash) { diff --git a/ProjectLighthouse/Controllers/ReviewController.cs b/ProjectLighthouse/Controllers/ReviewController.cs index 690cdf2e..54f15b15 100644 --- a/ProjectLighthouse/Controllers/ReviewController.cs +++ b/ProjectLighthouse/Controllers/ReviewController.cs @@ -31,7 +31,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("rate/user/{slotId}")] public async Task Rate(int slotId, [FromQuery] int rating) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); Slot? slot = await this.database.Slots.Include(s => s.Creator).Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == slotId); @@ -58,7 +58,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("dpadrate/user/{slotId:int}")] public async Task DPadRate(int slotId, [FromQuery] int rating) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); Slot? slot = await this.database.Slots.Include(s => s.Creator).Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == slotId); diff --git a/ProjectLighthouse/Controllers/ScoreController.cs b/ProjectLighthouse/Controllers/ScoreController.cs index 6f75e4d1..d97f07e9 100644 --- a/ProjectLighthouse/Controllers/ScoreController.cs +++ b/ProjectLighthouse/Controllers/ScoreController.cs @@ -28,13 +28,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("scoreboard/user/{id:int}")] public async Task SubmitScore(int id, [FromQuery] bool lbp1 = false, [FromQuery] bool lbp2 = false, [FromQuery] bool lbp3 = false) { - (User, Token)? userAndToken = await this.database.UserAndTokenFromRequest(this.Request); + (User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request); if (userAndToken == null) return this.StatusCode(403, ""); // ReSharper disable once PossibleInvalidOperationException User user = userAndToken.Value.Item1; - Token token = userAndToken.Value.Item2; + GameToken gameToken = userAndToken.Value.Item2; this.Request.Body.Position = 0; string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); @@ -48,7 +48,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers Slot? slot = this.database.Slots.FirstOrDefault(s => s.SlotId == score.SlotId); if (slot == null) return this.BadRequest(); - switch (token.GameVersion) + switch (gameToken.GameVersion) { case GameVersion.LittleBigPlanet1: slot.PlaysLBP1Complete++; @@ -95,7 +95,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers public async Task TopScores(int slotId, int type, [FromQuery] int pageStart = -1, [FromQuery] int pageSize = 5) { // Get username - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); diff --git a/ProjectLighthouse/Controllers/SlotsController.cs b/ProjectLighthouse/Controllers/SlotsController.cs index 2ded22b4..27b7c8ac 100644 --- a/ProjectLighthouse/Controllers/SlotsController.cs +++ b/ProjectLighthouse/Controllers/SlotsController.cs @@ -27,7 +27,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("slots/by")] public async Task SlotsBy([FromQuery] string u, [FromQuery] int pageStart, [FromQuery] int pageSize) { - Token? token = await this.database.TokenFromRequest(this.Request); + GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); GameVersion gameVersion = token.GameVersion; @@ -69,10 +69,10 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("s/user/{id:int}")] public async Task SUser(int id) { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); - Token? token = await this.database.TokenFromRequest(this.Request); + GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); GameVersion gameVersion = token.GameVersion; @@ -97,7 +97,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("slots")] public async Task NewestSlots([FromQuery] int pageStart, [FromQuery] int pageSize) { - Token? token = await this.database.TokenFromRequest(this.Request); + GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); GameVersion gameVersion = token.GameVersion; @@ -116,7 +116,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("slots/mmpicks")] public async Task TeamPickedSlots([FromQuery] int pageStart, [FromQuery] int pageSize) { - Token? token = await this.database.TokenFromRequest(this.Request); + GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); GameVersion gameVersion = token.GameVersion; @@ -136,7 +136,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("slots/lbp2luckydip")] public async Task LuckyDipSlots([FromQuery] int pageStart, [FromQuery] int pageSize, [FromQuery] int seed) { - Token? token = await this.database.TokenFromRequest(this.Request); + GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); GameVersion gameVersion = token.GameVersion; diff --git a/ProjectLighthouse/Controllers/UserController.cs b/ProjectLighthouse/Controllers/UserController.cs index 94a7da6a..03f3a783 100644 --- a/ProjectLighthouse/Controllers/UserController.cs +++ b/ProjectLighthouse/Controllers/UserController.cs @@ -36,7 +36,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("user/{username}")] public async Task GetUser(string username) { - Token? token = await this.database.TokenFromRequest(this.Request); + GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); string? user = await this.GetSerializedUser(username, token.GameVersion); @@ -48,7 +48,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpGet("users")] public async Task GetUserAlt([FromQuery] string[] u) { - Token? token = await this.database.TokenFromRequest(this.Request); + GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); List serializedUsers = new(); @@ -69,7 +69,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("updateUser")] public async Task UpdateUser() { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); XmlReaderSettings settings = new() @@ -165,7 +165,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("update_my_pins")] public async Task UpdateMyPins() { - User? user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); string pinsString = await new StreamReader(this.Request.Body).ReadToEndAsync(); diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs index 2d1bfbeb..0468cb74 100644 --- a/ProjectLighthouse/Database.cs +++ b/ProjectLighthouse/Database.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using System.Threading.Tasks; using Kettu; @@ -22,7 +23,8 @@ namespace LBPUnion.ProjectLighthouse public DbSet HeartedLevels { get; set; } public DbSet HeartedProfiles { get; set; } public DbSet Comments { get; set; } - public DbSet Tokens { get; set; } + public DbSet GameTokens { get; set; } + public DbSet WebTokens { get; set; } public DbSet Scores { get; set; } public DbSet PhotoSubjects { get; set; } public DbSet Photos { get; set; } @@ -31,12 +33,15 @@ namespace LBPUnion.ProjectLighthouse public DbSet RatedLevels { get; set; } public DbSet Reviews { get; set; } public DbSet RatedReviews { get; set; } + public DbSet AuthenticationAttempts { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(ServerSettings.Instance.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion); - public async Task CreateUser(string username) + public async Task CreateUser(string username, string password) { + if (!password.StartsWith("$2a")) throw new ArgumentException(nameof(password) + " is not a BCrypt hash"); + User user; if ((user = await this.Users.Where(u => u.Username == username).FirstOrDefaultAsync()) != null) return user; @@ -47,6 +52,7 @@ namespace LBPUnion.ProjectLighthouse user = new User { Username = username, + Password = password, LocationId = l.Id, Biography = username + " hasn't introduced themselves yet.", }; @@ -57,13 +63,14 @@ namespace LBPUnion.ProjectLighthouse return user; } - #nullable enable - public async Task AuthenticateUser(LoginData loginData, string userLocation, string titleId = "") +#nullable enable + public async Task AuthenticateUser(LoginData loginData, string userLocation, string titleId = "") { // TODO: don't use psn name to authenticate - User user = await this.Users.FirstOrDefaultAsync(u => u.Username == loginData.Username) ?? await this.CreateUser(loginData.Username); + User? user = await this.Users.FirstOrDefaultAsync(u => u.Username == loginData.Username); + if (user == null) return null; - Token token = new() + GameToken gameToken = new() { UserToken = HashHelper.GenerateAuthToken(), UserId = user.UserId, @@ -71,58 +78,102 @@ namespace LBPUnion.ProjectLighthouse GameVersion = GameVersionHelper.FromTitleId(titleId), }; - if (token.GameVersion == GameVersion.Unknown) + if (gameToken.GameVersion == GameVersion.Unknown) { Logger.Log($"Unknown GameVersion for TitleId {titleId}", LoggerLevelLogin.Instance); return null; } - this.Tokens.Add(token); + this.GameTokens.Add(gameToken); await this.SaveChangesAsync(); - return token; + return gameToken; } - public async Task UserFromAuthToken(string authToken) + #region Game Token Shenanigans + + public async Task UserFromMMAuth(string authToken, bool allowUnapproved = false) { - Token? token = await this.Tokens.FirstOrDefaultAsync(t => t.UserToken == authToken); + if (ServerStatics.IsUnitTesting) allowUnapproved = true; + GameToken? token = await this.GameTokens.FirstOrDefaultAsync(t => t.UserToken == authToken); + if (token == null) return null; + if (!allowUnapproved && !token.Approved) return null; return await this.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.UserId == token.UserId); } - public async Task UserFromToken(Token token) => await this.UserFromAuthToken(token.UserToken); + public async Task UserFromGameToken + (GameToken gameToken, bool allowUnapproved = false) + => await this.UserFromMMAuth(gameToken.UserToken, allowUnapproved); - public async Task UserFromRequest(HttpRequest request) + public async Task UserFromGameRequest(HttpRequest request, bool allowUnapproved = false) { + if (ServerStatics.IsUnitTesting) allowUnapproved = true; if (!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null) return null; - return await this.UserFromAuthToken(mmAuth); + return await this.UserFromMMAuth(mmAuth, allowUnapproved); } - public async Task TokenFromRequest(HttpRequest request) + public async Task GameTokenFromRequest(HttpRequest request, bool allowUnapproved = false) { + if (ServerStatics.IsUnitTesting) allowUnapproved = true; if (!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null) return null; - return await this.Tokens.FirstOrDefaultAsync(t => t.UserToken == mmAuth); - } + GameToken? token = await this.GameTokens.FirstOrDefaultAsync(t => t.UserToken == mmAuth); - public async Task<(User, Token)?> UserAndTokenFromRequest(HttpRequest request) - { - if (!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null) return null; - - Token? token = await this.Tokens.FirstOrDefaultAsync(t => t.UserToken == mmAuth); if (token == null) return null; + if (!allowUnapproved && !token.Approved) return null; - User? user = await this.UserFromToken(token); + return token; + } + + public async Task<(User, GameToken)?> UserAndGameTokenFromRequest(HttpRequest request, bool allowUnapproved = false) + { + if (ServerStatics.IsUnitTesting) allowUnapproved = true; + if (!request.Cookies.TryGetValue("MM_AUTH", out string? mmAuth) || mmAuth == null) return null; + + GameToken? token = await this.GameTokens.FirstOrDefaultAsync(t => t.UserToken == mmAuth); + if (token == null) return null; + if (!allowUnapproved && !token.Approved) return null; + + User? user = await this.UserFromGameToken(token); if (user == null) return null; return (user, token); } + #endregion + + #region Web Token Shenanigans + + public User? UserFromLighthouseToken(string lighthouseToken) + { + WebToken? token = this.WebTokens.FirstOrDefault(t => t.UserToken == lighthouseToken); + if (token == null) return null; + + return this.Users.Include(u => u.Location).FirstOrDefault(u => u.UserId == token.UserId); + } + + public User? UserFromWebRequest(HttpRequest request) + { + if (!request.Cookies.TryGetValue("LighthouseToken", out string? lighthouseToken) || lighthouseToken == null) return null; + + return this.UserFromLighthouseToken(lighthouseToken); + } + + public WebToken? WebTokenFromRequest(HttpRequest request) + { + if (!request.Cookies.TryGetValue("LighthouseToken", out string? lighthouseToken) || lighthouseToken == null) return null; + + return this.WebTokens.FirstOrDefault(t => t.UserToken == lighthouseToken); + } + + #endregion + public async Task PhotoFromSubject(PhotoSubject subject) => await this.Photos.FirstOrDefaultAsync(p => p.PhotoSubjectIds.Contains(subject.PhotoSubjectId.ToString())); - #nullable disable +#nullable disable } } \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/DeniedAuthenticationHelper.cs b/ProjectLighthouse/Helpers/DeniedAuthenticationHelper.cs new file mode 100644 index 00000000..1dc990a0 --- /dev/null +++ b/ProjectLighthouse/Helpers/DeniedAuthenticationHelper.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; + +namespace LBPUnion.ProjectLighthouse.Helpers +{ + public static class DeniedAuthenticationHelper + { + public static readonly Dictionary IPAddressAndNameDeniedAt = new(); + public static readonly Dictionary AttemptsByIPAddressAndName = new(); + + public static void SetDeniedAt(string ipAddressAndName, long timestamp = 0) + { + if (timestamp == 0) timestamp = TimestampHelper.Timestamp; + + if (IPAddressAndNameDeniedAt.TryGetValue(ipAddressAndName, out long _)) IPAddressAndNameDeniedAt.Remove(ipAddressAndName); + IPAddressAndNameDeniedAt.Add(ipAddressAndName, timestamp); + } + + public static bool RecentlyDenied(string ipAddressAndName) + { + if (!IPAddressAndNameDeniedAt.TryGetValue(ipAddressAndName, out long timestamp)) return false; + + return TimestampHelper.Timestamp < timestamp + 300; + } + + public static void AddAttempt(string ipAddressAndName) + { + if (AttemptsByIPAddressAndName.TryGetValue(ipAddressAndName, out int attempts)) AttemptsByIPAddressAndName.Remove(ipAddressAndName); + AttemptsByIPAddressAndName.Add(ipAddressAndName, attempts + 1); + } + + public static int GetAttempts(string ipAddressAndName) + { + if (!AttemptsByIPAddressAndName.TryGetValue(ipAddressAndName, out int attempts)) return 0; + + return attempts; + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/GitVersionHelper.cs b/ProjectLighthouse/Helpers/GitVersionHelper.cs index 857728fe..bc4e8cad 100644 --- a/ProjectLighthouse/Helpers/GitVersionHelper.cs +++ b/ProjectLighthouse/Helpers/GitVersionHelper.cs @@ -2,6 +2,7 @@ using System; using System.IO; using Kettu; using LBPUnion.ProjectLighthouse.Logging; +using LBPUnion.ProjectLighthouse.Types.Settings; namespace LBPUnion.ProjectLighthouse.Helpers { @@ -50,6 +51,7 @@ namespace LBPUnion.ProjectLighthouse.Helpers public static string CommitHash { get; set; } public static string Branch { get; set; } + public static string FullVersion => $"{ServerStatics.ServerName} {Branch}@{CommitHash}"; public static bool IsDirty => CommitHash.EndsWith("-dirty"); public static bool CanCheckForUpdates { get; set; } } diff --git a/ProjectLighthouse/Helpers/RoomHelper.cs b/ProjectLighthouse/Helpers/RoomHelper.cs index 285e2b93..e2c4c589 100644 --- a/ProjectLighthouse/Helpers/RoomHelper.cs +++ b/ProjectLighthouse/Helpers/RoomHelper.cs @@ -139,7 +139,14 @@ namespace LBPUnion.ProjectLighthouse.Helpers // Delete old rooms based on host if (host != null) { - Rooms.RemoveAll(r => r.Host == host); + try + { + Rooms.RemoveAll(r => r.Host == host); + } + catch + { + // TODO: detect the room that failed and remove it + } } // Remove players in this new room from other rooms diff --git a/ProjectLighthouse/Helpers/StatisticsHelper.cs b/ProjectLighthouse/Helpers/StatisticsHelper.cs index 3a43ed81..53d51710 100644 --- a/ProjectLighthouse/Helpers/StatisticsHelper.cs +++ b/ProjectLighthouse/Helpers/StatisticsHelper.cs @@ -13,5 +13,7 @@ namespace LBPUnion.ProjectLighthouse.Helpers public static async Task SlotCount() => await database.Slots.CountAsync(); public static async Task MMPicksCount() => await database.Slots.CountAsync(s => s.TeamPick); + + public static async Task PhotoCount() => await database.Photos.CountAsync(); } } \ No newline at end of file diff --git a/ProjectLighthouse/Migrations/20211019021627_InitialCreate.Designer.cs b/ProjectLighthouse/Migrations/20211019021627_InitialCreate.Designer.cs index 7fcae3a9..053a8eee 100644 --- a/ProjectLighthouse/Migrations/20211019021627_InitialCreate.Designer.cs +++ b/ProjectLighthouse/Migrations/20211019021627_InitialCreate.Designer.cs @@ -154,7 +154,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Slots"); }); - modelBuilder.Entity("ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211019031221_HeartedLevels.Designer.cs b/ProjectLighthouse/Migrations/20211019031221_HeartedLevels.Designer.cs index d531cf75..43af2c8a 100644 --- a/ProjectLighthouse/Migrations/20211019031221_HeartedLevels.Designer.cs +++ b/ProjectLighthouse/Migrations/20211019031221_HeartedLevels.Designer.cs @@ -175,7 +175,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Slots"); }); - modelBuilder.Entity("ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211019203627_LastMatches.Designer.cs b/ProjectLighthouse/Migrations/20211019203627_LastMatches.Designer.cs index aebb0f62..03647fc8 100644 --- a/ProjectLighthouse/Migrations/20211019203627_LastMatches.Designer.cs +++ b/ProjectLighthouse/Migrations/20211019203627_LastMatches.Designer.cs @@ -189,7 +189,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Slots"); }); - modelBuilder.Entity("ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211020220840_ResourceList.Designer.cs b/ProjectLighthouse/Migrations/20211020220840_ResourceList.Designer.cs index 36a02088..11880c79 100644 --- a/ProjectLighthouse/Migrations/20211020220840_ResourceList.Designer.cs +++ b/ProjectLighthouse/Migrations/20211020220840_ResourceList.Designer.cs @@ -189,7 +189,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Slots"); }); - modelBuilder.Entity("ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211026010814_FavouriteUsers.Designer.cs b/ProjectLighthouse/Migrations/20211026010814_FavouriteUsers.Designer.cs index 5c292a1e..5f0ff875 100644 --- a/ProjectLighthouse/Migrations/20211026010814_FavouriteUsers.Designer.cs +++ b/ProjectLighthouse/Migrations/20211026010814_FavouriteUsers.Designer.cs @@ -208,7 +208,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Locations"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211028015915_AddSlotTimestamp.Designer.cs b/ProjectLighthouse/Migrations/20211028015915_AddSlotTimestamp.Designer.cs index 48beed7d..09a0a521 100644 --- a/ProjectLighthouse/Migrations/20211028015915_AddSlotTimestamp.Designer.cs +++ b/ProjectLighthouse/Migrations/20211028015915_AddSlotTimestamp.Designer.cs @@ -211,7 +211,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Locations"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211028021513_AddSlotFirstUploadedAndLastUpdated.Designer.cs b/ProjectLighthouse/Migrations/20211028021513_AddSlotFirstUploadedAndLastUpdated.Designer.cs index d1ba6622..3cf2e85b 100644 --- a/ProjectLighthouse/Migrations/20211028021513_AddSlotFirstUploadedAndLastUpdated.Designer.cs +++ b/ProjectLighthouse/Migrations/20211028021513_AddSlotFirstUploadedAndLastUpdated.Designer.cs @@ -214,7 +214,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Locations"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211029213334_RemoveUsedSlotsFromDb.Designer.cs b/ProjectLighthouse/Migrations/20211029213334_RemoveUsedSlotsFromDb.Designer.cs index 59a0dcc7..ef52f9e7 100644 --- a/ProjectLighthouse/Migrations/20211029213334_RemoveUsedSlotsFromDb.Designer.cs +++ b/ProjectLighthouse/Migrations/20211029213334_RemoveUsedSlotsFromDb.Designer.cs @@ -214,7 +214,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Locations"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211030203837_AddMMPickToSlot.Designer.cs b/ProjectLighthouse/Migrations/20211030203837_AddMMPickToSlot.Designer.cs index f9f84485..eeca745a 100644 --- a/ProjectLighthouse/Migrations/20211030203837_AddMMPickToSlot.Designer.cs +++ b/ProjectLighthouse/Migrations/20211030203837_AddMMPickToSlot.Designer.cs @@ -217,7 +217,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Locations"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211031234245_AddScoresTable.Designer.cs b/ProjectLighthouse/Migrations/20211031234245_AddScoresTable.Designer.cs index ce6e6792..14211110 100644 --- a/ProjectLighthouse/Migrations/20211031234245_AddScoresTable.Designer.cs +++ b/ProjectLighthouse/Migrations/20211031234245_AddScoresTable.Designer.cs @@ -242,7 +242,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211102215859_RenameTeamPick.Designer.cs b/ProjectLighthouse/Migrations/20211102215859_RenameTeamPick.Designer.cs index 34087d12..131c53ad 100644 --- a/ProjectLighthouse/Migrations/20211102215859_RenameTeamPick.Designer.cs +++ b/ProjectLighthouse/Migrations/20211102215859_RenameTeamPick.Designer.cs @@ -242,7 +242,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211103194917_RemoveStartupMigrations.Designer.cs b/ProjectLighthouse/Migrations/20211103194917_RemoveStartupMigrations.Designer.cs index f26e5451..ce336fce 100644 --- a/ProjectLighthouse/Migrations/20211103194917_RemoveStartupMigrations.Designer.cs +++ b/ProjectLighthouse/Migrations/20211103194917_RemoveStartupMigrations.Designer.cs @@ -242,7 +242,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211104031327_AddGameVersionToToken.Designer.cs b/ProjectLighthouse/Migrations/20211104031327_AddGameVersionToToken.Designer.cs index 9814b171..215e0608 100644 --- a/ProjectLighthouse/Migrations/20211104031327_AddGameVersionToToken.Designer.cs +++ b/ProjectLighthouse/Migrations/20211104031327_AddGameVersionToToken.Designer.cs @@ -242,7 +242,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211104040509_AddGameVersionToSlots.Designer.cs b/ProjectLighthouse/Migrations/20211104040509_AddGameVersionToSlots.Designer.cs index 0727a0e5..94070a76 100644 --- a/ProjectLighthouse/Migrations/20211104040509_AddGameVersionToSlots.Designer.cs +++ b/ProjectLighthouse/Migrations/20211104040509_AddGameVersionToSlots.Designer.cs @@ -245,7 +245,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211104195812_AddPhotoSupport.Designer.cs b/ProjectLighthouse/Migrations/20211104195812_AddPhotoSupport.Designer.cs index b848597f..8e738f6a 100644 --- a/ProjectLighthouse/Migrations/20211104195812_AddPhotoSupport.Designer.cs +++ b/ProjectLighthouse/Migrations/20211104195812_AddPhotoSupport.Designer.cs @@ -293,7 +293,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211105205010_UpdatePhotoAndPhotoSubjectToDoStuffWeirdName.Designer.cs b/ProjectLighthouse/Migrations/20211105205010_UpdatePhotoAndPhotoSubjectToDoStuffWeirdName.Designer.cs index 9dee3007..31f84ecc 100644 --- a/ProjectLighthouse/Migrations/20211105205010_UpdatePhotoAndPhotoSubjectToDoStuffWeirdName.Designer.cs +++ b/ProjectLighthouse/Migrations/20211105205010_UpdatePhotoAndPhotoSubjectToDoStuffWeirdName.Designer.cs @@ -303,7 +303,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211105205239_DropPhotoSubjectParentPhoto.Designer.cs b/ProjectLighthouse/Migrations/20211105205239_DropPhotoSubjectParentPhoto.Designer.cs index 5f463653..7ee30fe0 100644 --- a/ProjectLighthouse/Migrations/20211105205239_DropPhotoSubjectParentPhoto.Designer.cs +++ b/ProjectLighthouse/Migrations/20211105205239_DropPhotoSubjectParentPhoto.Designer.cs @@ -298,7 +298,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211105205749_DropPhotoSlot.Designer.cs b/ProjectLighthouse/Migrations/20211105205749_DropPhotoSlot.Designer.cs index 9cb364e3..9d153964 100644 --- a/ProjectLighthouse/Migrations/20211105205749_DropPhotoSlot.Designer.cs +++ b/ProjectLighthouse/Migrations/20211105205749_DropPhotoSlot.Designer.cs @@ -293,7 +293,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211106010424_AddCreatorToPhoto.Designer.cs b/ProjectLighthouse/Migrations/20211106010424_AddCreatorToPhoto.Designer.cs index dfaa00d8..a1804945 100644 --- a/ProjectLighthouse/Migrations/20211106010424_AddCreatorToPhoto.Designer.cs +++ b/ProjectLighthouse/Migrations/20211106010424_AddCreatorToPhoto.Designer.cs @@ -298,7 +298,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211107023452_NoPhotosByMeOrWithMeInUser.Designer.cs b/ProjectLighthouse/Migrations/20211107023452_NoPhotosByMeOrWithMeInUser.Designer.cs index 46f8d20f..22841820 100644 --- a/ProjectLighthouse/Migrations/20211107023452_NoPhotosByMeOrWithMeInUser.Designer.cs +++ b/ProjectLighthouse/Migrations/20211107023452_NoPhotosByMeOrWithMeInUser.Designer.cs @@ -303,7 +303,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211108013443_RemoveCommentsEnabled.Designer.cs b/ProjectLighthouse/Migrations/20211108013443_RemoveCommentsEnabled.Designer.cs index 67842c32..89324073 100644 --- a/ProjectLighthouse/Migrations/20211108013443_RemoveCommentsEnabled.Designer.cs +++ b/ProjectLighthouse/Migrations/20211108013443_RemoveCommentsEnabled.Designer.cs @@ -303,7 +303,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211108015422_AddPlaysToSlot.Designer.cs b/ProjectLighthouse/Migrations/20211108015422_AddPlaysToSlot.Designer.cs index 40001bd0..59bcc054 100644 --- a/ProjectLighthouse/Migrations/20211108015422_AddPlaysToSlot.Designer.cs +++ b/ProjectLighthouse/Migrations/20211108015422_AddPlaysToSlot.Designer.cs @@ -306,7 +306,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211108054552_RemoveCountsFromDatabase.Designer.cs b/ProjectLighthouse/Migrations/20211108054552_RemoveCountsFromDatabase.Designer.cs index 4d2d382f..30993275 100644 --- a/ProjectLighthouse/Migrations/20211108054552_RemoveCountsFromDatabase.Designer.cs +++ b/ProjectLighthouse/Migrations/20211108054552_RemoveCountsFromDatabase.Designer.cs @@ -306,7 +306,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211108093616_GameSpecificPlayCounts.Designer.cs b/ProjectLighthouse/Migrations/20211108093616_GameSpecificPlayCounts.Designer.cs index abf45882..c649e759 100644 --- a/ProjectLighthouse/Migrations/20211108093616_GameSpecificPlayCounts.Designer.cs +++ b/ProjectLighthouse/Migrations/20211108093616_GameSpecificPlayCounts.Designer.cs @@ -330,7 +330,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211108114052_VisitedLevelsTable.Designer.cs b/ProjectLighthouse/Migrations/20211108114052_VisitedLevelsTable.Designer.cs index f78f1d58..9ea4167f 100644 --- a/ProjectLighthouse/Migrations/20211108114052_VisitedLevelsTable.Designer.cs +++ b/ProjectLighthouse/Migrations/20211108114052_VisitedLevelsTable.Designer.cs @@ -354,7 +354,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211108212022_BooYayRateLevels.Designer.cs b/ProjectLighthouse/Migrations/20211108212022_BooYayRateLevels.Designer.cs index 4d1d9dbf..fc982fdc 100644 --- a/ProjectLighthouse/Migrations/20211108212022_BooYayRateLevels.Designer.cs +++ b/ProjectLighthouse/Migrations/20211108212022_BooYayRateLevels.Designer.cs @@ -381,7 +381,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211109225543_AddLevelTypeToSlot.Designer.cs b/ProjectLighthouse/Migrations/20211109225543_AddLevelTypeToSlot.Designer.cs index cc243392..f14eb761 100644 --- a/ProjectLighthouse/Migrations/20211109225543_AddLevelTypeToSlot.Designer.cs +++ b/ProjectLighthouse/Migrations/20211109225543_AddLevelTypeToSlot.Designer.cs @@ -384,7 +384,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211113091631_AddUserLocationToToken.Designer.cs b/ProjectLighthouse/Migrations/20211113091631_AddUserLocationToToken.Designer.cs index 76be44ce..02bde039 100644 --- a/ProjectLighthouse/Migrations/20211113091631_AddUserLocationToToken.Designer.cs +++ b/ProjectLighthouse/Migrations/20211113091631_AddUserLocationToToken.Designer.cs @@ -384,7 +384,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211113215128_VisitedLevelPlayCounts.Designer.cs b/ProjectLighthouse/Migrations/20211113215128_VisitedLevelPlayCounts.Designer.cs index 5d93e5a2..8385d1da 100644 --- a/ProjectLighthouse/Migrations/20211113215128_VisitedLevelPlayCounts.Designer.cs +++ b/ProjectLighthouse/Migrations/20211113215128_VisitedLevelPlayCounts.Designer.cs @@ -401,7 +401,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211113220306_VisitedLevelDropGameVersion.Designer.cs b/ProjectLighthouse/Migrations/20211113220306_VisitedLevelDropGameVersion.Designer.cs index b48129af..38304f22 100644 --- a/ProjectLighthouse/Migrations/20211113220306_VisitedLevelDropGameVersion.Designer.cs +++ b/ProjectLighthouse/Migrations/20211113220306_VisitedLevelDropGameVersion.Designer.cs @@ -398,7 +398,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211114231343_UserRefactor.Designer.cs b/ProjectLighthouse/Migrations/20211114231343_UserRefactor.Designer.cs index cf70b3b0..49a61ffa 100644 --- a/ProjectLighthouse/Migrations/20211114231343_UserRefactor.Designer.cs +++ b/ProjectLighthouse/Migrations/20211114231343_UserRefactor.Designer.cs @@ -384,7 +384,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211115050553_UserAddDefaultsToNullableStrings.Designer.cs b/ProjectLighthouse/Migrations/20211115050553_UserAddDefaultsToNullableStrings.Designer.cs index 556eb96f..3aad3cc8 100644 --- a/ProjectLighthouse/Migrations/20211115050553_UserAddDefaultsToNullableStrings.Designer.cs +++ b/ProjectLighthouse/Migrations/20211115050553_UserAddDefaultsToNullableStrings.Designer.cs @@ -400,7 +400,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211115052941_SlotAddLbpVitaPlays.Designer.cs b/ProjectLighthouse/Migrations/20211115052941_SlotAddLbpVitaPlays.Designer.cs index efb62ea6..d3531618 100644 --- a/ProjectLighthouse/Migrations/20211115052941_SlotAddLbpVitaPlays.Designer.cs +++ b/ProjectLighthouse/Migrations/20211115052941_SlotAddLbpVitaPlays.Designer.cs @@ -412,7 +412,7 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => { b.Property("TokenId") .ValueGeneratedOnAdd() diff --git a/ProjectLighthouse/Migrations/20211120045239_AddPasswordToUser.Designer.cs b/ProjectLighthouse/Migrations/20211120045239_AddPasswordToUser.Designer.cs new file mode 100644 index 00000000..1afd4976 --- /dev/null +++ b/ProjectLighthouse/Migrations/20211120045239_AddPasswordToUser.Designer.cs @@ -0,0 +1,654 @@ +// +using LBPUnion.ProjectLighthouse; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + [DbContext(typeof(Database))] + [Migration("20211120045239_AddPasswordToUser")] + partial class AddPasswordToUser + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b => + { + b.Property("HeartedProfileId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("HeartedUserId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("HeartedProfileId"); + + b.HasIndex("HeartedUserId"); + + b.HasIndex("UserId"); + + b.ToTable("HeartedProfiles"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b => + { + b.Property("HeartedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("HeartedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("HeartedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b => + { + b.Property("QueuedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("QueuedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("QueuedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b => + { + b.Property("RatedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("int"); + + b.Property("RatingLBP1") + .HasColumnType("double"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("RatedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("RatedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b => + { + b.Property("SlotId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AuthorLabels") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("BackgroundHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatorId") + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FirstUploaded") + .HasColumnType("bigint"); + + b.Property("GameVersion") + .HasColumnType("int"); + + b.Property("IconHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InitiallyLocked") + .HasColumnType("tinyint(1)"); + + b.Property("LastUpdated") + .HasColumnType("bigint"); + + b.Property("Lbp1Only") + .HasColumnType("tinyint(1)"); + + b.Property("LevelType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MaximumPlayers") + .HasColumnType("int"); + + b.Property("MinimumPlayers") + .HasColumnType("int"); + + b.Property("MoveRequired") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PlaysLBP1") + .HasColumnType("int"); + + b.Property("PlaysLBP1Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP1Unique") + .HasColumnType("int"); + + b.Property("PlaysLBP2") + .HasColumnType("int"); + + b.Property("PlaysLBP2Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP2Unique") + .HasColumnType("int"); + + b.Property("PlaysLBP3") + .HasColumnType("int"); + + b.Property("PlaysLBP3Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP3Unique") + .HasColumnType("int"); + + b.Property("PlaysLBPVita") + .HasColumnType("int"); + + b.Property("PlaysLBPVitaComplete") + .HasColumnType("int"); + + b.Property("PlaysLBPVitaUnique") + .HasColumnType("int"); + + b.Property("ResourceCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("RootLevel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Shareable") + .HasColumnType("int"); + + b.Property("SubLevel") + .HasColumnType("tinyint(1)"); + + b.Property("TeamPick") + .HasColumnType("tinyint(1)"); + + b.HasKey("SlotId"); + + b.HasIndex("CreatorId"); + + b.HasIndex("LocationId"); + + b.ToTable("Slots"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b => + { + b.Property("VisitedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PlaysLBP1") + .HasColumnType("int"); + + b.Property("PlaysLBP2") + .HasColumnType("int"); + + b.Property("PlaysLBP3") + .HasColumnType("int"); + + b.Property("PlaysLBPVita") + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("VisitedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("VisitedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b => + { + b.Property("PhotoId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatorId") + .HasColumnType("int"); + + b.Property("LargeHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MediumHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhotoSubjectCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PlanHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SmallHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("PhotoId"); + + b.HasIndex("CreatorId"); + + b.ToTable("Photos"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b => + { + b.Property("PhotoSubjectId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Bounds") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("PhotoSubjectId"); + + b.HasIndex("UserId"); + + b.ToTable("PhotoSubjects"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b => + { + b.Property("CommentId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Message") + .HasColumnType("longtext"); + + b.Property("PosterUserId") + .HasColumnType("int"); + + b.Property("TargetUserId") + .HasColumnType("int"); + + b.Property("ThumbsDown") + .HasColumnType("int"); + + b.Property("ThumbsUp") + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("CommentId"); + + b.HasIndex("PosterUserId"); + + b.HasIndex("TargetUserId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.LastMatch", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("UserId"); + + b.ToTable("LastMatches"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Location", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("X") + .HasColumnType("int"); + + b.Property("Y") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Locations"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b => + { + b.Property("ScoreId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PlayerIdCollection") + .HasColumnType("longtext"); + + b.Property("Points") + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("ScoreId"); + + b.HasIndex("SlotId"); + + b.ToTable("Scores"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => + { + b.Property("TokenId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("GameVersion") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.Property("UserLocation") + .HasColumnType("longtext"); + + b.Property("UserToken") + .HasColumnType("longtext"); + + b.HasKey("TokenId"); + + b.ToTable("Tokens"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Biography") + .HasColumnType("longtext"); + + b.Property("Game") + .HasColumnType("int"); + + b.Property("IconHash") + .HasColumnType("longtext"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("Password") + .HasColumnType("longtext"); + + b.Property("Pins") + .HasColumnType("longtext"); + + b.Property("PlanetHash") + .HasColumnType("longtext"); + + b.Property("Username") + .HasColumnType("longtext"); + + b.HasKey("UserId"); + + b.HasIndex("LocationId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "HeartedUser") + .WithMany() + .HasForeignKey("HeartedUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("HeartedUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator") + .WithMany() + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Location"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator") + .WithMany() + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Poster") + .WithMany() + .HasForeignKey("PosterUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Target") + .WithMany() + .HasForeignKey("TargetUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Poster"); + + b.Navigation("Target"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Location"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProjectLighthouse/Migrations/20211120045239_AddPasswordToUser.cs b/ProjectLighthouse/Migrations/20211120045239_AddPasswordToUser.cs new file mode 100644 index 00000000..e962eee8 --- /dev/null +++ b/ProjectLighthouse/Migrations/20211120045239_AddPasswordToUser.cs @@ -0,0 +1,26 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + public partial class AddPasswordToUser : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Password", + table: "Users", + type: "longtext", + nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "Password", + table: "Users"); + } + } +} diff --git a/ProjectLighthouse/Migrations/20211120052549_RenameTokensToGameTokens.Designer.cs b/ProjectLighthouse/Migrations/20211120052549_RenameTokensToGameTokens.Designer.cs new file mode 100644 index 00000000..f0e1ea83 --- /dev/null +++ b/ProjectLighthouse/Migrations/20211120052549_RenameTokensToGameTokens.Designer.cs @@ -0,0 +1,654 @@ +// +using LBPUnion.ProjectLighthouse; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + [DbContext(typeof(Database))] + [Migration("20211120052549_RenameTokensToGameTokens")] + partial class RenameTokensToGameTokens + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => + { + b.Property("TokenId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("GameVersion") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.Property("UserLocation") + .HasColumnType("longtext"); + + b.Property("UserToken") + .HasColumnType("longtext"); + + b.HasKey("TokenId"); + + b.ToTable("GameTokens"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b => + { + b.Property("HeartedProfileId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("HeartedUserId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("HeartedProfileId"); + + b.HasIndex("HeartedUserId"); + + b.HasIndex("UserId"); + + b.ToTable("HeartedProfiles"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b => + { + b.Property("HeartedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("HeartedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("HeartedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b => + { + b.Property("QueuedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("QueuedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("QueuedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b => + { + b.Property("RatedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("int"); + + b.Property("RatingLBP1") + .HasColumnType("double"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("RatedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("RatedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b => + { + b.Property("SlotId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AuthorLabels") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("BackgroundHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatorId") + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FirstUploaded") + .HasColumnType("bigint"); + + b.Property("GameVersion") + .HasColumnType("int"); + + b.Property("IconHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InitiallyLocked") + .HasColumnType("tinyint(1)"); + + b.Property("LastUpdated") + .HasColumnType("bigint"); + + b.Property("Lbp1Only") + .HasColumnType("tinyint(1)"); + + b.Property("LevelType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MaximumPlayers") + .HasColumnType("int"); + + b.Property("MinimumPlayers") + .HasColumnType("int"); + + b.Property("MoveRequired") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PlaysLBP1") + .HasColumnType("int"); + + b.Property("PlaysLBP1Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP1Unique") + .HasColumnType("int"); + + b.Property("PlaysLBP2") + .HasColumnType("int"); + + b.Property("PlaysLBP2Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP2Unique") + .HasColumnType("int"); + + b.Property("PlaysLBP3") + .HasColumnType("int"); + + b.Property("PlaysLBP3Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP3Unique") + .HasColumnType("int"); + + b.Property("PlaysLBPVita") + .HasColumnType("int"); + + b.Property("PlaysLBPVitaComplete") + .HasColumnType("int"); + + b.Property("PlaysLBPVitaUnique") + .HasColumnType("int"); + + b.Property("ResourceCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("RootLevel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Shareable") + .HasColumnType("int"); + + b.Property("SubLevel") + .HasColumnType("tinyint(1)"); + + b.Property("TeamPick") + .HasColumnType("tinyint(1)"); + + b.HasKey("SlotId"); + + b.HasIndex("CreatorId"); + + b.HasIndex("LocationId"); + + b.ToTable("Slots"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b => + { + b.Property("VisitedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PlaysLBP1") + .HasColumnType("int"); + + b.Property("PlaysLBP2") + .HasColumnType("int"); + + b.Property("PlaysLBP3") + .HasColumnType("int"); + + b.Property("PlaysLBPVita") + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("VisitedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("VisitedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b => + { + b.Property("PhotoId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatorId") + .HasColumnType("int"); + + b.Property("LargeHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MediumHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhotoSubjectCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PlanHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SmallHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("PhotoId"); + + b.HasIndex("CreatorId"); + + b.ToTable("Photos"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b => + { + b.Property("PhotoSubjectId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Bounds") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("PhotoSubjectId"); + + b.HasIndex("UserId"); + + b.ToTable("PhotoSubjects"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b => + { + b.Property("CommentId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Message") + .HasColumnType("longtext"); + + b.Property("PosterUserId") + .HasColumnType("int"); + + b.Property("TargetUserId") + .HasColumnType("int"); + + b.Property("ThumbsDown") + .HasColumnType("int"); + + b.Property("ThumbsUp") + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("CommentId"); + + b.HasIndex("PosterUserId"); + + b.HasIndex("TargetUserId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.LastMatch", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("UserId"); + + b.ToTable("LastMatches"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Location", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("X") + .HasColumnType("int"); + + b.Property("Y") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Locations"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b => + { + b.Property("ScoreId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PlayerIdCollection") + .HasColumnType("longtext"); + + b.Property("Points") + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("ScoreId"); + + b.HasIndex("SlotId"); + + b.ToTable("Scores"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Biography") + .HasColumnType("longtext"); + + b.Property("Game") + .HasColumnType("int"); + + b.Property("IconHash") + .HasColumnType("longtext"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("Password") + .HasColumnType("longtext"); + + b.Property("Pins") + .HasColumnType("longtext"); + + b.Property("PlanetHash") + .HasColumnType("longtext"); + + b.Property("Username") + .HasColumnType("longtext"); + + b.HasKey("UserId"); + + b.HasIndex("LocationId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "HeartedUser") + .WithMany() + .HasForeignKey("HeartedUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("HeartedUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator") + .WithMany() + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Location"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator") + .WithMany() + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Poster") + .WithMany() + .HasForeignKey("PosterUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Target") + .WithMany() + .HasForeignKey("TargetUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Poster"); + + b.Navigation("Target"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Location"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProjectLighthouse/Migrations/20211120052549_RenameTokensToGameTokens.cs b/ProjectLighthouse/Migrations/20211120052549_RenameTokensToGameTokens.cs new file mode 100644 index 00000000..59150955 --- /dev/null +++ b/ProjectLighthouse/Migrations/20211120052549_RenameTokensToGameTokens.cs @@ -0,0 +1,41 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + public partial class RenameTokensToGameTokens : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_Tokens", + table: "Tokens"); + + migrationBuilder.RenameTable( + name: "Tokens", + newName: "GameTokens"); + + migrationBuilder.AddPrimaryKey( + name: "PK_GameTokens", + table: "GameTokens", + column: "TokenId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropPrimaryKey( + name: "PK_GameTokens", + table: "GameTokens"); + + migrationBuilder.RenameTable( + name: "GameTokens", + newName: "Tokens"); + + migrationBuilder.AddPrimaryKey( + name: "PK_Tokens", + table: "Tokens", + column: "TokenId"); + } + } +} diff --git a/ProjectLighthouse/Migrations/20211120053654_AddWebTokens.Designer.cs b/ProjectLighthouse/Migrations/20211120053654_AddWebTokens.Designer.cs new file mode 100644 index 00000000..fe402f9f --- /dev/null +++ b/ProjectLighthouse/Migrations/20211120053654_AddWebTokens.Designer.cs @@ -0,0 +1,671 @@ +// +using LBPUnion.ProjectLighthouse; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + [DbContext(typeof(Database))] + [Migration("20211120053654_AddWebTokens")] + partial class AddWebTokens + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => + { + b.Property("TokenId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("GameVersion") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.Property("UserLocation") + .HasColumnType("longtext"); + + b.Property("UserToken") + .HasColumnType("longtext"); + + b.HasKey("TokenId"); + + b.ToTable("GameTokens"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b => + { + b.Property("HeartedProfileId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("HeartedUserId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("HeartedProfileId"); + + b.HasIndex("HeartedUserId"); + + b.HasIndex("UserId"); + + b.ToTable("HeartedProfiles"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b => + { + b.Property("HeartedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("HeartedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("HeartedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b => + { + b.Property("QueuedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("QueuedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("QueuedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b => + { + b.Property("RatedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("int"); + + b.Property("RatingLBP1") + .HasColumnType("double"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("RatedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("RatedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b => + { + b.Property("SlotId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AuthorLabels") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("BackgroundHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatorId") + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FirstUploaded") + .HasColumnType("bigint"); + + b.Property("GameVersion") + .HasColumnType("int"); + + b.Property("IconHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InitiallyLocked") + .HasColumnType("tinyint(1)"); + + b.Property("LastUpdated") + .HasColumnType("bigint"); + + b.Property("Lbp1Only") + .HasColumnType("tinyint(1)"); + + b.Property("LevelType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MaximumPlayers") + .HasColumnType("int"); + + b.Property("MinimumPlayers") + .HasColumnType("int"); + + b.Property("MoveRequired") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PlaysLBP1") + .HasColumnType("int"); + + b.Property("PlaysLBP1Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP1Unique") + .HasColumnType("int"); + + b.Property("PlaysLBP2") + .HasColumnType("int"); + + b.Property("PlaysLBP2Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP2Unique") + .HasColumnType("int"); + + b.Property("PlaysLBP3") + .HasColumnType("int"); + + b.Property("PlaysLBP3Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP3Unique") + .HasColumnType("int"); + + b.Property("PlaysLBPVita") + .HasColumnType("int"); + + b.Property("PlaysLBPVitaComplete") + .HasColumnType("int"); + + b.Property("PlaysLBPVitaUnique") + .HasColumnType("int"); + + b.Property("ResourceCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("RootLevel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Shareable") + .HasColumnType("int"); + + b.Property("SubLevel") + .HasColumnType("tinyint(1)"); + + b.Property("TeamPick") + .HasColumnType("tinyint(1)"); + + b.HasKey("SlotId"); + + b.HasIndex("CreatorId"); + + b.HasIndex("LocationId"); + + b.ToTable("Slots"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b => + { + b.Property("VisitedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PlaysLBP1") + .HasColumnType("int"); + + b.Property("PlaysLBP2") + .HasColumnType("int"); + + b.Property("PlaysLBP3") + .HasColumnType("int"); + + b.Property("PlaysLBPVita") + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("VisitedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("VisitedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b => + { + b.Property("PhotoId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatorId") + .HasColumnType("int"); + + b.Property("LargeHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MediumHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhotoSubjectCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PlanHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SmallHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("PhotoId"); + + b.HasIndex("CreatorId"); + + b.ToTable("Photos"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b => + { + b.Property("PhotoSubjectId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Bounds") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("PhotoSubjectId"); + + b.HasIndex("UserId"); + + b.ToTable("PhotoSubjects"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b => + { + b.Property("CommentId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Message") + .HasColumnType("longtext"); + + b.Property("PosterUserId") + .HasColumnType("int"); + + b.Property("TargetUserId") + .HasColumnType("int"); + + b.Property("ThumbsDown") + .HasColumnType("int"); + + b.Property("ThumbsUp") + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("CommentId"); + + b.HasIndex("PosterUserId"); + + b.HasIndex("TargetUserId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.LastMatch", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("UserId"); + + b.ToTable("LastMatches"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Location", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("X") + .HasColumnType("int"); + + b.Property("Y") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Locations"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b => + { + b.Property("ScoreId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PlayerIdCollection") + .HasColumnType("longtext"); + + b.Property("Points") + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("ScoreId"); + + b.HasIndex("SlotId"); + + b.ToTable("Scores"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Biography") + .HasColumnType("longtext"); + + b.Property("Game") + .HasColumnType("int"); + + b.Property("IconHash") + .HasColumnType("longtext"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("Password") + .HasColumnType("longtext"); + + b.Property("Pins") + .HasColumnType("longtext"); + + b.Property("PlanetHash") + .HasColumnType("longtext"); + + b.Property("Username") + .HasColumnType("longtext"); + + b.HasKey("UserId"); + + b.HasIndex("LocationId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.WebToken", b => + { + b.Property("TokenId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.Property("UserToken") + .HasColumnType("longtext"); + + b.HasKey("TokenId"); + + b.ToTable("WebTokens"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "HeartedUser") + .WithMany() + .HasForeignKey("HeartedUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("HeartedUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator") + .WithMany() + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Location"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator") + .WithMany() + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Poster") + .WithMany() + .HasForeignKey("PosterUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Target") + .WithMany() + .HasForeignKey("TargetUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Poster"); + + b.Navigation("Target"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Location"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProjectLighthouse/Migrations/20211120053654_AddWebTokens.cs b/ProjectLighthouse/Migrations/20211120053654_AddWebTokens.cs new file mode 100644 index 00000000..7fe503b6 --- /dev/null +++ b/ProjectLighthouse/Migrations/20211120053654_AddWebTokens.cs @@ -0,0 +1,35 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + public partial class AddWebTokens : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "WebTokens", + columns: table => new + { + TokenId = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + UserId = table.Column(type: "int", nullable: false), + UserToken = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_WebTokens", x => x.TokenId); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "WebTokens"); + } + } +} diff --git a/ProjectLighthouse/Migrations/20211122002000_AddAuthenticationAttempts.Designer.cs b/ProjectLighthouse/Migrations/20211122002000_AddAuthenticationAttempts.Designer.cs new file mode 100644 index 00000000..3122c70a --- /dev/null +++ b/ProjectLighthouse/Migrations/20211122002000_AddAuthenticationAttempts.Designer.cs @@ -0,0 +1,710 @@ +// +using LBPUnion.ProjectLighthouse; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + [DbContext(typeof(Database))] + [Migration("20211122002000_AddAuthenticationAttempts")] + partial class AddAuthenticationAttempts + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.AuthenticationAttempt", b => + { + b.Property("AuthenticationAttemptId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("GameTokenId") + .HasColumnType("int"); + + b.Property("IPAddress") + .HasColumnType("longtext"); + + b.Property("Platform") + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("AuthenticationAttemptId"); + + b.HasIndex("GameTokenId"); + + b.ToTable("AuthenticationAttempts"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => + { + b.Property("TokenId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Approved") + .HasColumnType("tinyint(1)"); + + b.Property("GameVersion") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.Property("UserLocation") + .HasColumnType("longtext"); + + b.Property("UserToken") + .HasColumnType("longtext"); + + b.HasKey("TokenId"); + + b.ToTable("GameTokens"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b => + { + b.Property("HeartedProfileId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("HeartedUserId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("HeartedProfileId"); + + b.HasIndex("HeartedUserId"); + + b.HasIndex("UserId"); + + b.ToTable("HeartedProfiles"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b => + { + b.Property("HeartedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("HeartedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("HeartedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b => + { + b.Property("QueuedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("QueuedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("QueuedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b => + { + b.Property("RatedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("int"); + + b.Property("RatingLBP1") + .HasColumnType("double"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("RatedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("RatedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b => + { + b.Property("SlotId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AuthorLabels") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("BackgroundHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatorId") + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FirstUploaded") + .HasColumnType("bigint"); + + b.Property("GameVersion") + .HasColumnType("int"); + + b.Property("IconHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InitiallyLocked") + .HasColumnType("tinyint(1)"); + + b.Property("LastUpdated") + .HasColumnType("bigint"); + + b.Property("Lbp1Only") + .HasColumnType("tinyint(1)"); + + b.Property("LevelType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MaximumPlayers") + .HasColumnType("int"); + + b.Property("MinimumPlayers") + .HasColumnType("int"); + + b.Property("MoveRequired") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PlaysLBP1") + .HasColumnType("int"); + + b.Property("PlaysLBP1Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP1Unique") + .HasColumnType("int"); + + b.Property("PlaysLBP2") + .HasColumnType("int"); + + b.Property("PlaysLBP2Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP2Unique") + .HasColumnType("int"); + + b.Property("PlaysLBP3") + .HasColumnType("int"); + + b.Property("PlaysLBP3Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP3Unique") + .HasColumnType("int"); + + b.Property("PlaysLBPVita") + .HasColumnType("int"); + + b.Property("PlaysLBPVitaComplete") + .HasColumnType("int"); + + b.Property("PlaysLBPVitaUnique") + .HasColumnType("int"); + + b.Property("ResourceCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("RootLevel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Shareable") + .HasColumnType("int"); + + b.Property("SubLevel") + .HasColumnType("tinyint(1)"); + + b.Property("TeamPick") + .HasColumnType("tinyint(1)"); + + b.HasKey("SlotId"); + + b.HasIndex("CreatorId"); + + b.HasIndex("LocationId"); + + b.ToTable("Slots"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b => + { + b.Property("VisitedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PlaysLBP1") + .HasColumnType("int"); + + b.Property("PlaysLBP2") + .HasColumnType("int"); + + b.Property("PlaysLBP3") + .HasColumnType("int"); + + b.Property("PlaysLBPVita") + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("VisitedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("VisitedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b => + { + b.Property("PhotoId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatorId") + .HasColumnType("int"); + + b.Property("LargeHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MediumHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhotoSubjectCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PlanHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SmallHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("PhotoId"); + + b.HasIndex("CreatorId"); + + b.ToTable("Photos"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b => + { + b.Property("PhotoSubjectId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Bounds") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("PhotoSubjectId"); + + b.HasIndex("UserId"); + + b.ToTable("PhotoSubjects"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b => + { + b.Property("CommentId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Message") + .HasColumnType("longtext"); + + b.Property("PosterUserId") + .HasColumnType("int"); + + b.Property("TargetUserId") + .HasColumnType("int"); + + b.Property("ThumbsDown") + .HasColumnType("int"); + + b.Property("ThumbsUp") + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("CommentId"); + + b.HasIndex("PosterUserId"); + + b.HasIndex("TargetUserId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.LastMatch", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("UserId"); + + b.ToTable("LastMatches"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Location", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("X") + .HasColumnType("int"); + + b.Property("Y") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Locations"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b => + { + b.Property("ScoreId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PlayerIdCollection") + .HasColumnType("longtext"); + + b.Property("Points") + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("ScoreId"); + + b.HasIndex("SlotId"); + + b.ToTable("Scores"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Biography") + .HasColumnType("longtext"); + + b.Property("Game") + .HasColumnType("int"); + + b.Property("IconHash") + .HasColumnType("longtext"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("Password") + .HasColumnType("longtext"); + + b.Property("Pins") + .HasColumnType("longtext"); + + b.Property("PlanetHash") + .HasColumnType("longtext"); + + b.Property("Username") + .HasColumnType("longtext"); + + b.HasKey("UserId"); + + b.HasIndex("LocationId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.WebToken", b => + { + b.Property("TokenId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.Property("UserToken") + .HasColumnType("longtext"); + + b.HasKey("TokenId"); + + b.ToTable("WebTokens"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.AuthenticationAttempt", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.GameToken", "GameToken") + .WithMany() + .HasForeignKey("GameTokenId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GameToken"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "HeartedUser") + .WithMany() + .HasForeignKey("HeartedUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("HeartedUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator") + .WithMany() + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Location"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator") + .WithMany() + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Poster") + .WithMany() + .HasForeignKey("PosterUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Target") + .WithMany() + .HasForeignKey("TargetUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Poster"); + + b.Navigation("Target"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Location"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProjectLighthouse/Migrations/20211122002000_AddAuthenticationAttempts.cs b/ProjectLighthouse/Migrations/20211122002000_AddAuthenticationAttempts.cs new file mode 100644 index 00000000..d63e4918 --- /dev/null +++ b/ProjectLighthouse/Migrations/20211122002000_AddAuthenticationAttempts.cs @@ -0,0 +1,59 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + public partial class AddAuthenticationAttempts : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "Approved", + table: "GameTokens", + type: "tinyint(1)", + nullable: false, + defaultValue: false); + + migrationBuilder.CreateTable( + name: "AuthenticationAttempts", + columns: table => new + { + AuthenticationAttemptId = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Timestamp = table.Column(type: "bigint", nullable: false), + Platform = table.Column(type: "int", nullable: false), + IPAddress = table.Column(type: "longtext", nullable: true) + .Annotation("MySql:CharSet", "utf8mb4"), + GameTokenId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AuthenticationAttempts", x => x.AuthenticationAttemptId); + table.ForeignKey( + name: "FK_AuthenticationAttempts_GameTokens_GameTokenId", + column: x => x.GameTokenId, + principalTable: "GameTokens", + principalColumn: "TokenId", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_AuthenticationAttempts_GameTokenId", + table: "AuthenticationAttempts", + column: "GameTokenId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AuthenticationAttempts"); + + migrationBuilder.DropColumn( + name: "Approved", + table: "GameTokens"); + } + } +} diff --git a/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs b/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs index a21d10d6..af460ee2 100644 --- a/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs +++ b/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs @@ -18,6 +18,57 @@ namespace ProjectLighthouse.Migrations .HasAnnotation("ProductVersion", "6.0.0") .HasAnnotation("Relational:MaxIdentifierLength", 64); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.AuthenticationAttempt", b => + { + b.Property("AuthenticationAttemptId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("GameTokenId") + .HasColumnType("int"); + + b.Property("IPAddress") + .HasColumnType("longtext"); + + b.Property("Platform") + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("AuthenticationAttemptId"); + + b.HasIndex("GameTokenId"); + + b.ToTable("AuthenticationAttempts"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.GameToken", b => + { + b.Property("TokenId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Approved") + .HasColumnType("tinyint(1)"); + + b.Property("GameVersion") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.Property("UserLocation") + .HasColumnType("longtext"); + + b.Property("UserToken") + .HasColumnType("longtext"); + + b.HasKey("TokenId"); + + b.ToTable("GameTokens"); + }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b => { b.Property("HeartedProfileId") @@ -473,29 +524,6 @@ namespace ProjectLighthouse.Migrations b.ToTable("Scores"); }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => - { - b.Property("TokenId") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - b.Property("GameVersion") - .HasColumnType("int"); - - b.Property("UserId") - .HasColumnType("int"); - - b.Property("UserLocation") - .HasColumnType("longtext"); - - b.Property("UserToken") - .HasColumnType("longtext"); - - b.HasKey("TokenId"); - - b.ToTable("Tokens"); - }); - modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b => { b.Property("UserId") @@ -514,6 +542,9 @@ namespace ProjectLighthouse.Migrations b.Property("LocationId") .HasColumnType("int"); + b.Property("Password") + .HasColumnType("longtext"); + b.Property("Pins") .HasColumnType("longtext"); @@ -530,6 +561,34 @@ namespace ProjectLighthouse.Migrations b.ToTable("Users"); }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.WebToken", b => + { + b.Property("TokenId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.Property("UserToken") + .HasColumnType("longtext"); + + b.HasKey("TokenId"); + + b.ToTable("WebTokens"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.AuthenticationAttempt", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.GameToken", "GameToken") + .WithMany() + .HasForeignKey("GameTokenId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GameToken"); + }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b => { b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "HeartedUser") diff --git a/ProjectLighthouse/Pages/ExternalAuth/AuthenticationPage.cshtml b/ProjectLighthouse/Pages/ExternalAuth/AuthenticationPage.cshtml new file mode 100644 index 00000000..58521e46 --- /dev/null +++ b/ProjectLighthouse/Pages/ExternalAuth/AuthenticationPage.cshtml @@ -0,0 +1,36 @@ +@page "/authentication" +@using LBPUnion.ProjectLighthouse.Types +@model LBPUnion.ProjectLighthouse.Pages.ExternalAuth.AuthenticationPage + +@{ + Layout = "Layouts/BaseLayout"; +} +

Authentication

+ +@if (Model.AuthenticationAttempts.Count == 0) +{ +

You have no pending authentication attempts.

+} +else +{ +

You have @Model.AuthenticationAttempts.Count authentication attempts pending.

+ + + +} + +@foreach (AuthenticationAttempt authAttempt in Model.AuthenticationAttempts) +{ + DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(authAttempt.Timestamp); +
+

A @authAttempt.Platform authentication request was logged at @timestamp.ToString("MM/dd/yyyy @ h:mm tt") UTC from the IP address @authAttempt.IPAddress.

+ +
+} \ No newline at end of file diff --git a/ProjectLighthouse/Pages/ExternalAuth/AuthenticationPage.cshtml.cs b/ProjectLighthouse/Pages/ExternalAuth/AuthenticationPage.cshtml.cs new file mode 100644 index 00000000..f64d3102 --- /dev/null +++ b/ProjectLighthouse/Pages/ExternalAuth/AuthenticationPage.cshtml.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Pages.Layouts; +using LBPUnion.ProjectLighthouse.Types; +using LBPUnion.ProjectLighthouse.Types.Settings; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace LBPUnion.ProjectLighthouse.Pages.ExternalAuth +{ + public class AuthenticationPage : BaseLayout + { + public AuthenticationPage(Database database) : base(database) + {} + + public List AuthenticationAttempts; + + public async Task OnGet() + { + if (!ServerSettings.Instance.UseExternalAuth) return this.NotFound(); + + this.AuthenticationAttempts = this.Database.AuthenticationAttempts.Include + (a => a.GameToken) + .Where(a => a.GameToken.UserId == this.User.UserId) + .OrderByDescending(a => a.Timestamp) + .ToList(); + + return this.Page(); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Pages/LandingPage.cshtml b/ProjectLighthouse/Pages/LandingPage.cshtml new file mode 100644 index 00000000..f320a553 --- /dev/null +++ b/ProjectLighthouse/Pages/LandingPage.cshtml @@ -0,0 +1,25 @@ +@page "/" +@model LBPUnion.ProjectLighthouse.Pages.LandingPage + +@{ + Layout = "Layouts/BaseLayout"; +} +

Welcome to Project Lighthouse!

+ +@if (Model.User != null) +{ +

You are currently logged in as @Model.User.Username.

+} + +@if (Model.PlayersOnline == 1) +{ +

There is 1 user currently online.

+} +else if (Model.PlayersOnline == 0) +{ +

There are no users online. Why not hop on?

+} +else +{ +

There are currently @Model.PlayersOnline users online.

+} \ No newline at end of file diff --git a/ProjectLighthouse/Pages/LandingPage.cshtml.cs b/ProjectLighthouse/Pages/LandingPage.cshtml.cs new file mode 100644 index 00000000..1edb223a --- /dev/null +++ b/ProjectLighthouse/Pages/LandingPage.cshtml.cs @@ -0,0 +1,24 @@ +#nullable enable +using System.Threading.Tasks; +using JetBrains.Annotations; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Pages.Layouts; +using Microsoft.AspNetCore.Mvc; + +namespace LBPUnion.ProjectLighthouse.Pages +{ + public class LandingPage : BaseLayout + { + public LandingPage(Database database) : base(database) + {} + + public int PlayersOnline; + + [UsedImplicitly] + public async Task OnGet() + { + this.PlayersOnline = await StatisticsHelper.RecentMatches(); + return this.Page(); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Pages/Layouts/BaseLayout.cshtml b/ProjectLighthouse/Pages/Layouts/BaseLayout.cshtml new file mode 100644 index 00000000..ca46ebd3 --- /dev/null +++ b/ProjectLighthouse/Pages/Layouts/BaseLayout.cshtml @@ -0,0 +1,64 @@ +@using LBPUnion.ProjectLighthouse.Helpers +@using LBPUnion.ProjectLighthouse.Types +@using LBPUnion.ProjectLighthouse.Types.Settings +@model LBPUnion.ProjectLighthouse.Pages.Layouts.BaseLayout + +@{ + if (Model!.User == null) + { + Model.NavigationItems.Add(new PageNavigationItem("Log in", "/login", "user alternate")); + Model.NavigationItems.Add(new PageNavigationItem("Register", "/register", "user alternate edit")); + } + else + { + if (ServerSettings.Instance.UseExternalAuth) + { + Model.NavigationItems.Add(new PageNavigationItem("Authentication", "/authentication", "key")); + } + Model.NavigationItems.Add(new PageNavigationItem("Log out", "/logout", "user alternate slash")); // should always be last + } +} + + + + + + Project Lighthouse + + + +
+ +
+ +
+
+ @RenderBody() +
+ +
+
+
+ +

Page generated by @GitVersionHelper.FullVersion.

+ @if (GitVersionHelper.IsDirty) + { +

This page was generated using a modified version of Project Lighthouse. Please make sure you are properly disclosing the source code to any users who may be using this instance.

+ } +
+
+
+ \ No newline at end of file diff --git a/ProjectLighthouse/Pages/Layouts/BaseLayout.cshtml.cs b/ProjectLighthouse/Pages/Layouts/BaseLayout.cshtml.cs new file mode 100644 index 00000000..3d3fbcc2 --- /dev/null +++ b/ProjectLighthouse/Pages/Layouts/BaseLayout.cshtml.cs @@ -0,0 +1,35 @@ +#nullable enable +using System.Collections.Generic; +using LBPUnion.ProjectLighthouse.Types; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace LBPUnion.ProjectLighthouse.Pages.Layouts +{ + public class BaseLayout : PageModel + { + public readonly Database Database; + + private User? user; + + public new User? User { + get { + if (this.user != null) return this.user; + + return user = Database.UserFromWebRequest(this.Request); + } + set => this.user = value; + } + + public BaseLayout(Database database) + { + this.Database = database; + } + + public readonly List NavigationItems = new() + { + new PageNavigationItem("Home", "/", "home"), + new PageNavigationItem("Photos", "/photos/0", "camera"), + }; + + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Pages/LoginForm.cshtml b/ProjectLighthouse/Pages/LoginForm.cshtml new file mode 100644 index 00000000..83d3dbf0 --- /dev/null +++ b/ProjectLighthouse/Pages/LoginForm.cshtml @@ -0,0 +1,33 @@ +@page "/login" +@model LBPUnion.ProjectLighthouse.Pages.LoginForm + +@{ + Layout = "Layouts/BaseLayout"; +} + + + + + +

Log in

+
+
+ + +

+ +
+ + +


+ +
+
\ No newline at end of file diff --git a/ProjectLighthouse/Pages/LoginForm.cshtml.cs b/ProjectLighthouse/Pages/LoginForm.cshtml.cs new file mode 100644 index 00000000..674eb803 --- /dev/null +++ b/ProjectLighthouse/Pages/LoginForm.cshtml.cs @@ -0,0 +1,48 @@ +#nullable enable +using System.Threading.Tasks; +using JetBrains.Annotations; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Pages.Layouts; +using LBPUnion.ProjectLighthouse.Types; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace LBPUnion.ProjectLighthouse.Pages +{ + public class LoginForm : BaseLayout + { + public LoginForm(Database database) : base(database) + {} + + public bool WasLoginRequest { get; private set; } + + [UsedImplicitly] + public async Task OnGet([FromQuery] string username, [FromQuery] string password) + { + this.WasLoginRequest = !string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password); + + if (this.WasLoginRequest) + { + User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username); + if (user == null) return this.StatusCode(403, ""); + + if (!BCrypt.Net.BCrypt.Verify(password, user.Password)) return this.StatusCode(403, ""); + + WebToken webToken = new() + { + UserId = user.UserId, + UserToken = HashHelper.GenerateAuthToken(), + }; + + this.Database.WebTokens.Add(webToken); + await this.Database.SaveChangesAsync(); + + this.Response.Cookies.Append("LighthouseToken", webToken.UserToken); + + return this.RedirectToPage(nameof(LandingPage)); + } + + return this.Page(); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Pages/LogoutPage.cshtml b/ProjectLighthouse/Pages/LogoutPage.cshtml new file mode 100644 index 00000000..ac65ce91 --- /dev/null +++ b/ProjectLighthouse/Pages/LogoutPage.cshtml @@ -0,0 +1,9 @@ +@page "/logout" +@model LBPUnion.ProjectLighthouse.Pages.LogoutPage + +@{ + Layout = "Layouts/BaseLayout"; +} + +

You have been successfully logged out. You will be redirected in 5 seconds, or you may click here to do so manually.

+ \ No newline at end of file diff --git a/ProjectLighthouse/Pages/LogoutPage.cshtml.cs b/ProjectLighthouse/Pages/LogoutPage.cshtml.cs new file mode 100644 index 00000000..792947be --- /dev/null +++ b/ProjectLighthouse/Pages/LogoutPage.cshtml.cs @@ -0,0 +1,26 @@ +#nullable enable +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Pages.Layouts; +using LBPUnion.ProjectLighthouse.Types; +using Microsoft.AspNetCore.Mvc; + +namespace LBPUnion.ProjectLighthouse.Pages +{ + public class LogoutPage : BaseLayout + { + public LogoutPage(Database database) : base(database) + {} + public async Task OnGet() + { + WebToken? token = this.Database.WebTokenFromRequest(this.Request); + if (token == null) return this.BadRequest(); + + this.Database.WebTokens.Remove(token); + await this.Database.SaveChangesAsync(); + + this.Response.Cookies.Delete("LighthouseToken"); + + return this.Page(); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Pages/PhotosPage.cshtml b/ProjectLighthouse/Pages/PhotosPage.cshtml new file mode 100644 index 00000000..98f4e12d --- /dev/null +++ b/ProjectLighthouse/Pages/PhotosPage.cshtml @@ -0,0 +1,43 @@ +@page "/photos/{pageNumber:int}" +@using LBPUnion.ProjectLighthouse.Types +@model LBPUnion.ProjectLighthouse.Pages.PhotosPage + +@{ + Layout = "Layouts/BaseLayout"; +} + +

Photos

+

There are @Model.PhotoCount total photos!

+ +@foreach (Photo photo in Model.Photos) +{ +
+ +
+ +

+ + Taken by + + @photo.Creator.Username + + +

+ +

+ Photo contains @photo.Subjects.Count @(photo.Subjects.Count == 1 ? "person" : "people"): +

+ @foreach (PhotoSubject subject in photo.Subjects) + { + @subject.User.Username + } +
+} + +@if (Model.PageNumber != 0) +{ + Previous Page +} +Next Page + +
@* solves quirk with footer *@ \ No newline at end of file diff --git a/ProjectLighthouse/Pages/PhotosPage.cshtml.cs b/ProjectLighthouse/Pages/PhotosPage.cshtml.cs new file mode 100644 index 00000000..f7be042a --- /dev/null +++ b/ProjectLighthouse/Pages/PhotosPage.cshtml.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using JetBrains.Annotations; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Pages.Layouts; +using LBPUnion.ProjectLighthouse.Types; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace LBPUnion.ProjectLighthouse.Pages +{ + public class PhotosPage : BaseLayout + { + public PhotosPage([NotNull] Database database) : base(database) + {} + + public int PhotoCount; + + public List Photos; + + public int PageNumber; + + public async Task OnGet([FromRoute] int pageNumber) + { + const int pageSize = 20; + this.PhotoCount = await StatisticsHelper.PhotoCount(); + + this.PageNumber = pageNumber; + + this.Photos = await this.Database.Photos.Include + (p => p.Creator) + .OrderByDescending(p => p.Timestamp) + .Skip(pageNumber * pageSize) + .Take(pageSize) + .ToListAsync(); + + return this.Page(); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Pages/RegisterForm.cshtml b/ProjectLighthouse/Pages/RegisterForm.cshtml new file mode 100644 index 00000000..b5385f17 --- /dev/null +++ b/ProjectLighthouse/Pages/RegisterForm.cshtml @@ -0,0 +1,38 @@ +@page "/register" +@model LBPUnion.ProjectLighthouse.Pages.RegisterForm + +@{ + Layout = "Layouts/BaseLayout"; +} + + + + + + +

Register

+
+
+ + +

+
+ + +

+
+ + +


+
+
\ No newline at end of file diff --git a/ProjectLighthouse/Pages/RegisterForm.cshtml.cs b/ProjectLighthouse/Pages/RegisterForm.cshtml.cs new file mode 100644 index 00000000..5e5347ca --- /dev/null +++ b/ProjectLighthouse/Pages/RegisterForm.cshtml.cs @@ -0,0 +1,51 @@ +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; +using JetBrains.Annotations; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Pages.Layouts; +using LBPUnion.ProjectLighthouse.Types; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace LBPUnion.ProjectLighthouse.Pages +{ + public class RegisterForm : BaseLayout + { + public RegisterForm(Database database) : base(database) + {} + + public bool WasRegisterRequest { get; private set; } + + [UsedImplicitly] + [SuppressMessage("ReSharper", "SpecifyStringComparison")] + public async Task OnGet([FromQuery] string username, [FromQuery] string password, [FromQuery] string confirmPassword) + { + this.WasRegisterRequest = !string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password) && !string.IsNullOrEmpty(confirmPassword); + + if (this.WasRegisterRequest) + { + if (password != confirmPassword) return this.BadRequest(); + + bool userExists = await this.Database.Users.FirstOrDefaultAsync(u => u.Username.ToLower() == username.ToLower()) != null; + if (userExists) return this.BadRequest(); + + User user = await this.Database.CreateUser(username, HashHelper.BCryptHash(password)); + + WebToken webToken = new() + { + UserId = user.UserId, + UserToken = HashHelper.GenerateAuthToken(), + }; + + this.Database.WebTokens.Add(webToken); + await this.Database.SaveChangesAsync(); + + this.Response.Cookies.Append("LighthouseToken", webToken.UserToken); + + return this.RedirectToPage(nameof(LandingPage)); + } + + return this.Page(); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Program.cs b/ProjectLighthouse/Program.cs index 695e2470..65c6ffac 100644 --- a/ProjectLighthouse/Program.cs +++ b/ProjectLighthouse/Program.cs @@ -29,7 +29,7 @@ namespace LBPUnion.ProjectLighthouse Logger.AddLogger(new LighthouseFileLogger()); Logger.Log("Welcome to Project Lighthouse!", LoggerLevelStartup.Instance); - Logger.Log($"Running {ServerStatics.ServerName} {GitVersionHelper.CommitHash}@{GitVersionHelper.Branch}", LoggerLevelStartup.Instance); + Logger.Log($"Running {GitVersionHelper.FullVersion}", LoggerLevelStartup.Instance); // This loads the config, see ServerSettings.cs for more information Logger.Log("Loaded config file version " + ServerSettings.Instance.ConfigVersion, LoggerLevelStartup.Instance); @@ -53,6 +53,17 @@ namespace LBPUnion.ProjectLighthouse if (ServerSettings.Instance.InfluxLoggingEnabled) Logger.AddLogger(new InfluxLogger()); } + #if DEBUG + Logger.Log + ( + "This is a debug build, so performance may suffer! " + + "If you are running Lighthouse in a production environment, " + + "it is highly recommended to run a release build. ", + LoggerLevelStartup.Instance + ); + Logger.Log("You can do so by running any dotnet command with the flag: \"-c Release\". ", LoggerLevelStartup.Instance); + #endif + stopwatch.Stop(); Logger.Log($"Ready! Startup took {stopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...", LoggerLevelStartup.Instance); @@ -77,6 +88,7 @@ namespace LBPUnion.ProjectLighthouse webBuilder => { webBuilder.UseStartup(); + webBuilder.UseWebRoot("StaticFiles"); } ) .ConfigureLogging diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj index b576a35c..a4e601cc 100644 --- a/ProjectLighthouse/ProjectLighthouse.csproj +++ b/ProjectLighthouse/ProjectLighthouse.csproj @@ -13,6 +13,7 @@ + all diff --git a/ProjectLighthouse/Startup.cs b/ProjectLighthouse/Startup.cs index 93e41f3d..0048c96c 100644 --- a/ProjectLighthouse/Startup.cs +++ b/ProjectLighthouse/Startup.cs @@ -1,17 +1,16 @@ -using System; using System.Diagnostics; using System.IO; using Kettu; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Serialization; +using LBPUnion.ProjectLighthouse.Types.Settings; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Primitives; namespace LBPUnion.ProjectLighthouse @@ -29,6 +28,11 @@ namespace LBPUnion.ProjectLighthouse public void ConfigureServices(IServiceCollection services) { services.AddControllers(); + #if DEBUG + services.AddRazorPages().WithRazorPagesAtContentRoot().AddRazorRuntimeCompilation(); + #else + services.AddRazorPages().WithRazorPagesAtContentRoot(); + #endif services.AddMvc ( @@ -54,19 +58,21 @@ namespace LBPUnion.ProjectLighthouse public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env) { bool computeDigests = true; - string serverDigestKey = Environment.GetEnvironmentVariable("SERVER_DIGEST_KEY"); - if (string.IsNullOrWhiteSpace(serverDigestKey)) + string serverDigestKey = ServerSettings.Instance.ServerDigestKey; + if (string.IsNullOrEmpty(serverDigestKey)) { Logger.Log ( - "The SERVER_DIGEST_KEY environment variable wasn't set, so digest headers won't be set or verified. This will prevent LBP 1 and LBP 3 from working. " + + "The serverDigestKey configuration option wasn't set, so digest headers won't be set or verified. This will also prevent LBP 1, LBP 2, and LBP Vita from working. " + "To increase security, it is recommended that you find and set this variable.", LoggerLevelStartup.Instance ); computeDigests = false; } - if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); + #if DEBUG + app.UseDeveloperExceptionPage(); + #endif app.UseForwardedHeaders(); @@ -90,7 +96,7 @@ namespace LBPUnion.ProjectLighthouse string digestPath = context.Request.Path; Stream body = context.Request.Body; - if (computeDigests) + if (computeDigests && digestPath.StartsWith("/LITTLEBIGPLANETPS3_XML")) { string clientRequestDigest = await HashHelper.ComputeDigest(digestPath, authCookie, body, serverDigestKey); @@ -152,7 +158,10 @@ namespace LBPUnion.ProjectLighthouse app.UseRouting(); + app.UseStaticFiles(); + app.UseEndpoints(endpoints => endpoints.MapControllers()); + app.UseEndpoints(endpoints => endpoints.MapRazorPages()); } } } \ No newline at end of file diff --git a/ProjectLighthouse/StaticFiles/css/styles.css b/ProjectLighthouse/StaticFiles/css/styles.css new file mode 100644 index 00000000..2b1738bf --- /dev/null +++ b/ProjectLighthouse/StaticFiles/css/styles.css @@ -0,0 +1,5 @@ +footer.lighthouse-footer { + width: 100%; + bottom: 0; + position: fixed; +} diff --git a/ProjectLighthouse/Types/AuthenticationAttempt.cs b/ProjectLighthouse/Types/AuthenticationAttempt.cs new file mode 100644 index 00000000..57a10cd8 --- /dev/null +++ b/ProjectLighthouse/Types/AuthenticationAttempt.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace LBPUnion.ProjectLighthouse.Types +{ + public class AuthenticationAttempt + { + [Key] + public int AuthenticationAttemptId { get; set; } + + public long Timestamp { get; set; } + public Platform Platform { get; set; } + public string IPAddress { get; set; } + + public int GameTokenId { get; set; } + + [ForeignKey(nameof(GameTokenId))] + public GameToken GameToken { get; set; } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/Token.cs b/ProjectLighthouse/Types/GameToken.cs similarity index 83% rename from ProjectLighthouse/Types/Token.cs rename to ProjectLighthouse/Types/GameToken.cs index fc448c8c..4fdca27d 100644 --- a/ProjectLighthouse/Types/Token.cs +++ b/ProjectLighthouse/Types/GameToken.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; namespace LBPUnion.ProjectLighthouse.Types { - public class Token + public class GameToken { // ReSharper disable once UnusedMember.Global [Key] @@ -15,5 +15,7 @@ namespace LBPUnion.ProjectLighthouse.Types public string UserLocation { get; set; } public GameVersion GameVersion { get; set; } + + public bool Approved { get; set; } = false; } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/PageNavigationItem.cs b/ProjectLighthouse/Types/PageNavigationItem.cs new file mode 100644 index 00000000..b832fa70 --- /dev/null +++ b/ProjectLighthouse/Types/PageNavigationItem.cs @@ -0,0 +1,17 @@ +#nullable enable + +namespace LBPUnion.ProjectLighthouse.Types +{ + public class PageNavigationItem + { + public PageNavigationItem(string name, string url, string? icon = null) + { + this.Name = name; + this.Url = url; + this.Icon = icon; + } + public string Name { get; set; } + public string Url { get; set; } + public string? Icon { get; set; } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/Platform.cs b/ProjectLighthouse/Types/Platform.cs new file mode 100644 index 00000000..3711848a --- /dev/null +++ b/ProjectLighthouse/Types/Platform.cs @@ -0,0 +1,9 @@ +namespace LBPUnion.ProjectLighthouse.Types +{ + public enum Platform + { + PS3 = 0, + RPCS3 = 1, + Vita = 2, + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/Settings/ServerSettings.cs b/ProjectLighthouse/Types/Settings/ServerSettings.cs index 405e90db..b23a61dc 100644 --- a/ProjectLighthouse/Types/Settings/ServerSettings.cs +++ b/ProjectLighthouse/Types/Settings/ServerSettings.cs @@ -68,7 +68,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings [NotNull] public static ServerSettings Instance; - public const int CurrentConfigVersion = 4; + public const int CurrentConfigVersion = 7; [JsonPropertyName("ConfigVersionDoNotModifyOrYouWillBeSlapped")] public int ConfigVersion { get; set; } = CurrentConfigVersion; @@ -87,5 +87,9 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings public string EulaText { get; set; } = ""; public string DbConnectionString { get; set; } = "server=127.0.0.1;uid=root;pwd=lighthouse;database=lighthouse"; + + public string ExternalUrl { get; set; } = "http://localhost:10060"; + public string ServerDigestKey { get; set; } + public bool UseExternalAuth { get; set; } } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/User.cs b/ProjectLighthouse/Types/User.cs index 9346fc87..42f1a853 100644 --- a/ProjectLighthouse/Types/User.cs +++ b/ProjectLighthouse/Types/User.cs @@ -12,6 +12,7 @@ namespace LBPUnion.ProjectLighthouse.Types public readonly ClientsConnected ClientsConnected = new(); public int UserId { get; set; } public string Username { get; set; } + public string Password { get; set; } public string IconHash { get; set; } public int Game { get; set; } diff --git a/ProjectLighthouse/Types/WebToken.cs b/ProjectLighthouse/Types/WebToken.cs new file mode 100644 index 00000000..2bf8fe9c --- /dev/null +++ b/ProjectLighthouse/Types/WebToken.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; + +namespace LBPUnion.ProjectLighthouse.Types +{ + public class WebToken + { + // ReSharper disable once UnusedMember.Global + [Key] + public int TokenId { get; set; } + + public int UserId { get; set; } + + public string UserToken { get; set; } + } +} \ No newline at end of file