mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-05-06 02:32:28 +00:00
parent
a8410fe352
commit
4ba75f09a9
16 changed files with 188 additions and 10 deletions
|
@ -3,7 +3,7 @@
|
|||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "6.0.5",
|
||||
"version": "6.0.7",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
|
|
|
@ -57,9 +57,10 @@ public class LoginController : ControllerBase
|
|||
|
||||
string ipAddress = remoteIpAddress.ToString();
|
||||
|
||||
await this.database.RemoveExpiredTokens();
|
||||
|
||||
// Get an existing token from the IP & username
|
||||
GameToken? token = await this.database.GameTokens.Include
|
||||
(t => t.User)
|
||||
GameToken? token = await this.database.GameTokens.Include(t => t.User)
|
||||
.FirstOrDefaultAsync(t => t.UserLocation == ipAddress && t.User.Username == npTicket.Username && !t.Used);
|
||||
|
||||
if (token == null) // If we cant find an existing token, try to generate a new one
|
||||
|
@ -67,7 +68,8 @@ public class LoginController : ControllerBase
|
|||
token = await this.database.AuthenticateUser(npTicket, ipAddress);
|
||||
if (token == null)
|
||||
{
|
||||
Logger.Warn($"Unable to find/generate a token for username {npTicket.Username}", LogArea.Login);
|
||||
Logger.Warn($"Unable to " +
|
||||
$"find/generate a token for username {npTicket.Username}", LogArea.Login);
|
||||
return this.StatusCode(403, ""); // If not, then 403.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#nullable enable
|
||||
using System.Globalization;
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
|
@ -75,6 +76,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.";
|
|||
$"token.Used: {gameToken.Used}\n" +
|
||||
$"token.UserLocation: {gameToken.UserLocation}\n" +
|
||||
$"token.GameVersion: {gameToken.GameVersion}\n" +
|
||||
$"token.ExpiresAt: {gameToken.ExpiresAt.ToString(CultureInfo.CurrentCulture)}\n" +
|
||||
"---DEBUG INFO---" +
|
||||
#endif
|
||||
"\n"
|
||||
|
|
|
@ -73,6 +73,7 @@ public class LoginForm : BaseLayout
|
|||
UserId = user.UserId,
|
||||
User = user,
|
||||
EmailToken = CryptoHelper.GenerateAuthToken(),
|
||||
ExpiresAt = DateTime.Now + TimeSpan.FromHours(6),
|
||||
};
|
||||
|
||||
this.Database.EmailSetTokens.Add(emailSetToken);
|
||||
|
@ -85,6 +86,7 @@ public class LoginForm : BaseLayout
|
|||
{
|
||||
UserId = user.UserId,
|
||||
UserToken = CryptoHelper.GenerateAuthToken(),
|
||||
ExpiresAt = DateTime.Now + TimeSpan.FromDays(7),
|
||||
};
|
||||
|
||||
this.Database.WebTokens.Add(webToken);
|
||||
|
|
|
@ -94,6 +94,7 @@ public class RegisterForm : BaseLayout
|
|||
{
|
||||
UserId = user.UserId,
|
||||
UserToken = CryptoHelper.GenerateAuthToken(),
|
||||
ExpiresAt = DateTime.Now + TimeSpan.FromDays(7),
|
||||
};
|
||||
|
||||
this.Database.WebTokens.Add(webToken);
|
||||
|
|
|
@ -49,15 +49,18 @@ public class SetEmailForm : BaseLayout
|
|||
UserId = user.UserId,
|
||||
User = user,
|
||||
EmailToken = CryptoHelper.GenerateAuthToken(),
|
||||
ExpiresAt = DateTime.Now + TimeSpan.FromHours(6),
|
||||
};
|
||||
|
||||
this.Database.EmailVerificationTokens.Add(emailVerifyToken);
|
||||
|
||||
// The user just set their email address. Now, let's grant them a token to proceed with verifying the email.
|
||||
// TODO: insecure
|
||||
WebToken webToken = new()
|
||||
{
|
||||
UserId = user.UserId,
|
||||
UserToken = CryptoHelper.GenerateAuthToken(),
|
||||
ExpiresAt = DateTime.Now + TimeSpan.FromDays(7),
|
||||
};
|
||||
|
||||
this.Response.Cookies.Append
|
||||
|
|
|
@ -25,6 +25,7 @@ public class AdminTests : LighthouseWebTest
|
|||
{
|
||||
UserId = user.UserId,
|
||||
UserToken = CryptoHelper.GenerateAuthToken(),
|
||||
ExpiresAt = DateTime.Now + TimeSpan.FromHours(1),
|
||||
};
|
||||
|
||||
database.WebTokens.Add(webToken);
|
||||
|
@ -49,6 +50,7 @@ public class AdminTests : LighthouseWebTest
|
|||
{
|
||||
UserId = user.UserId,
|
||||
UserToken = CryptoHelper.GenerateAuthToken(),
|
||||
ExpiresAt = DateTime.Now + TimeSpan.FromHours(1),
|
||||
};
|
||||
|
||||
database.WebTokens.Add(webToken);
|
||||
|
|
|
@ -88,6 +88,7 @@ public class AuthenticationTests : LighthouseWebTest
|
|||
{
|
||||
UserId = user.UserId,
|
||||
UserToken = CryptoHelper.GenerateAuthToken(),
|
||||
ExpiresAt = DateTime.Now + TimeSpan.FromHours(1),
|
||||
};
|
||||
|
||||
database.WebTokens.Add(webToken);
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
|||
using LBPUnion.ProjectLighthouse.Administration;
|
||||
using LBPUnion.ProjectLighthouse.Administration.Reports;
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Levels;
|
||||
using LBPUnion.ProjectLighthouse.Levels.Categories;
|
||||
|
@ -111,6 +112,8 @@ public class Database : DbContext
|
|||
UserLocation = userLocation,
|
||||
GameVersion = npTicket.GameVersion,
|
||||
Platform = npTicket.Platform,
|
||||
// we can get away with a low expiry here since LBP will just get a new token everytime it gets 403'd
|
||||
ExpiresAt = DateTime.Now + TimeSpan.FromHours(1),
|
||||
};
|
||||
|
||||
this.GameTokens.Add(gameToken);
|
||||
|
@ -289,6 +292,13 @@ public class Database : DbContext
|
|||
if (token == null) return null;
|
||||
if (!allowUnapproved && !token.Approved) return null;
|
||||
|
||||
if (DateTime.Now > token.ExpiresAt)
|
||||
{
|
||||
this.Remove(token);
|
||||
await this.SaveChangesAsync();
|
||||
return null;
|
||||
}
|
||||
|
||||
return await this.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.UserId == token.UserId);
|
||||
}
|
||||
|
||||
|
@ -314,6 +324,13 @@ public class Database : DbContext
|
|||
if (token == null) return null;
|
||||
if (!allowUnapproved && !token.Approved) return null;
|
||||
|
||||
if (DateTime.Now > token.ExpiresAt)
|
||||
{
|
||||
this.Remove(token);
|
||||
await this.SaveChangesAsync();
|
||||
return null;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
|
@ -326,6 +343,13 @@ public class Database : DbContext
|
|||
if (token == null) return null;
|
||||
if (!allowUnapproved && !token.Approved) return null;
|
||||
|
||||
if (DateTime.Now > token.ExpiresAt)
|
||||
{
|
||||
this.Remove(token);
|
||||
await this.SaveChangesAsync();
|
||||
return null;
|
||||
}
|
||||
|
||||
User? user = await this.UserFromGameToken(token);
|
||||
|
||||
if (user == null) return null;
|
||||
|
@ -342,6 +366,13 @@ public class Database : DbContext
|
|||
WebToken? token = this.WebTokens.FirstOrDefault(t => t.UserToken == lighthouseToken);
|
||||
if (token == null) return null;
|
||||
|
||||
if (DateTime.Now > token.ExpiresAt)
|
||||
{
|
||||
this.Remove(token);
|
||||
this.SaveChanges();
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.Users.Include(u => u.Location).FirstOrDefault(u => u.UserId == token.UserId);
|
||||
}
|
||||
|
||||
|
@ -356,12 +387,21 @@ public class Database : DbContext
|
|||
{
|
||||
if (!request.Cookies.TryGetValue("LighthouseToken", out string? lighthouseToken) || lighthouseToken == null) return null;
|
||||
|
||||
return this.WebTokens.FirstOrDefault(t => t.UserToken == lighthouseToken);
|
||||
WebToken? token = this.WebTokens.FirstOrDefault(t => t.UserToken == lighthouseToken);
|
||||
if (token == null) return null;
|
||||
|
||||
if (DateTime.Now > token.ExpiresAt)
|
||||
{
|
||||
this.Remove(token);
|
||||
this.SaveChanges();
|
||||
return null;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
public async Task<User?> UserFromPasswordResetToken(string resetToken)
|
||||
{
|
||||
|
||||
PasswordResetToken? token = await this.PasswordResetTokens.FirstOrDefaultAsync(token => token.ResetToken == resetToken);
|
||||
if (token == null)
|
||||
{
|
||||
|
@ -371,8 +411,10 @@ public class Database : DbContext
|
|||
if (token.Created < DateTime.Now.AddHours(-1)) // if token is expired
|
||||
{
|
||||
this.PasswordResetTokens.Remove(token);
|
||||
await this.SaveChangesAsync();
|
||||
return null;
|
||||
}
|
||||
|
||||
return await this.Users.FirstOrDefaultAsync(user => user.UserId == token.UserId);
|
||||
}
|
||||
|
||||
|
@ -385,12 +427,23 @@ public class Database : DbContext
|
|||
if (token.Created < DateTime.Now.AddDays(-7)) // if token is expired
|
||||
{
|
||||
this.RegistrationTokens.Remove(token);
|
||||
this.SaveChanges();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task RemoveExpiredTokens()
|
||||
{
|
||||
this.GameTokens.RemoveWhere(t => DateTime.Now > t.ExpiresAt);
|
||||
this.WebTokens.RemoveWhere(t => DateTime.Now > t.ExpiresAt);
|
||||
this.EmailVerificationTokens.RemoveWhere(t => DateTime.Now > t.ExpiresAt);
|
||||
this.EmailSetTokens.RemoveWhere(t => DateTime.Now > t.ExpiresAt);
|
||||
|
||||
await this.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task RemoveRegistrationToken(string tokenString)
|
||||
{
|
||||
RegistrationToken? token = await this.RegistrationTokens.FirstOrDefaultAsync(t => t.Token == tokenString);
|
||||
|
@ -398,7 +451,6 @@ public class Database : DbContext
|
|||
if (token == null) return;
|
||||
|
||||
this.RegistrationTokens.Remove(token);
|
||||
|
||||
await this.SaveChangesAsync();
|
||||
}
|
||||
|
||||
|
@ -426,10 +478,10 @@ public class Database : DbContext
|
|||
this.RatedLevels.RemoveRange(this.RatedLevels.Where(r => r.UserId == user.UserId));
|
||||
this.GameTokens.RemoveRange(this.GameTokens.Where(t => t.UserId == user.UserId));
|
||||
this.WebTokens.RemoveRange(this.WebTokens.Where(t => t.UserId == user.UserId));
|
||||
this.Reactions.RemoveRange(this.Reactions.Where(p => p.UserId == user.UserId));
|
||||
this.Comments.RemoveRange(this.Comments.Where(c => c.PosterUserId == user.UserId));
|
||||
this.Reviews.RemoveRange(this.Reviews.Where(r => r.ReviewerId == user.UserId));
|
||||
this.Photos.RemoveRange(this.Photos.Where(p => p.CreatorId == user.UserId));
|
||||
this.Reactions.RemoveRange(this.Reactions.Where(p => p.UserId == user.UserId));
|
||||
|
||||
this.Users.Remove(user);
|
||||
|
||||
|
|
|
@ -56,6 +56,9 @@ public static class DatabaseExtensions
|
|||
return query;
|
||||
}
|
||||
|
||||
public static async Task<bool> Has<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> predicate) =>
|
||||
await queryable.FirstOrDefaultAsync(predicate) != null;
|
||||
public static async Task<bool> Has<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> predicate)
|
||||
=> await queryable.FirstOrDefaultAsync(predicate) != null;
|
||||
|
||||
public static void RemoveWhere<T>(this DbSet<T> queryable, Expression<Func<T, bool>> predicate) where T : class
|
||||
=> queryable.RemoveRange(queryable.Where(predicate));
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
using System;
|
||||
using LBPUnion.ProjectLighthouse;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ProjectLighthouse.Migrations
|
||||
{
|
||||
[DbContext(typeof(Database))]
|
||||
[Migration("20220729182709_AddExpiryTimesToTokens")]
|
||||
public partial class AddExpiryTimesToTokens : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
// Remove existing tokens
|
||||
migrationBuilder.Sql("DELETE FROM GameTokens;");
|
||||
migrationBuilder.Sql("DELETE FROM WebTokens;");
|
||||
migrationBuilder.Sql("DELETE FROM EmailSetTokens;");
|
||||
migrationBuilder.Sql("DELETE FROM EmailVerificationTokens;");
|
||||
migrationBuilder.Sql("DELETE FROM PasswordResetTokens;");
|
||||
migrationBuilder.Sql("DELETE FROM RegistrationTokens;");
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "ExpiresAt",
|
||||
table: "WebTokens",
|
||||
type: "datetime(6)",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "ExpiresAt",
|
||||
table: "GameTokens",
|
||||
type: "datetime(6)",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "ExpiresAt",
|
||||
table: "EmailVerificationTokens",
|
||||
type: "datetime(6)",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "ExpiresAt",
|
||||
table: "EmailSetTokens",
|
||||
type: "datetime(6)",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ExpiresAt",
|
||||
table: "WebTokens");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ExpiresAt",
|
||||
table: "RegistrationTokens");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ExpiresAt",
|
||||
table: "PasswordResetTokens");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ExpiresAt",
|
||||
table: "GameTokens");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ExpiresAt",
|
||||
table: "EmailVerificationTokens");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ExpiresAt",
|
||||
table: "EmailSetTokens");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -385,6 +385,9 @@ namespace ProjectLighthouse.Migrations
|
|||
b.Property<bool>("Approved")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<int>("GameVersion")
|
||||
.HasColumnType("int");
|
||||
|
||||
|
@ -419,6 +422,9 @@ namespace ProjectLighthouse.Migrations
|
|||
b.Property<DateTime>("Created")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("ResetToken")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
|
@ -540,6 +546,9 @@ namespace ProjectLighthouse.Migrations
|
|||
b.Property<string>("EmailToken")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
|
@ -559,6 +568,9 @@ namespace ProjectLighthouse.Migrations
|
|||
b.Property<string>("EmailToken")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
|
@ -731,6 +743,9 @@ namespace ProjectLighthouse.Migrations
|
|||
b.Property<DateTime>("Created")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Token")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
|
@ -841,6 +856,9 @@ namespace ProjectLighthouse.Migrations
|
|||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
|
||||
|
@ -28,4 +29,6 @@ public class GameToken
|
|||
|
||||
// Set to true on login
|
||||
public bool Used { get; set; }
|
||||
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
|
@ -14,4 +15,6 @@ public class EmailSetToken
|
|||
public User User { get; set; }
|
||||
|
||||
public string EmailToken { get; set; }
|
||||
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
|
@ -14,4 +15,6 @@ public class EmailVerificationToken
|
|||
public User User { get; set; }
|
||||
|
||||
public string EmailToken { get; set; }
|
||||
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.PlayerData;
|
||||
|
@ -11,4 +12,6 @@ public class WebToken
|
|||
public int UserId { get; set; }
|
||||
|
||||
public string UserToken { get; set; }
|
||||
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue