mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-08-05 11:28:39 +00:00
Implement 2FA (#577)
* Initial work for TOTP 2FA * Fix bug in 2FA code script * Add translations for two factor and /disable2fa * Fix compilation error * Add TwoFactorLoginPage * Add two factor login process * Little bit of backup code work * Finish two factor * Fix unit tests * ??? goofy ahh code * Use SHA-256 instead of SHA-512 * I guess SHA-256 doesn't work either * Fix comments in Base32 helper * Move QRCoder package to website * Add name to endregion comment in css * Fix bug with redirects
This commit is contained in:
parent
4fd1063502
commit
14d2f0305e
28 changed files with 1077 additions and 20 deletions
|
@ -1,6 +1,8 @@
|
|||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Middlewares;
|
||||
using LBPUnion.ProjectLighthouse.PlayerData;
|
||||
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Servers.Website.Middlewares;
|
||||
|
||||
|
@ -12,14 +14,16 @@ public class UserRequiredRedirectMiddleware : MiddlewareDBContext
|
|||
public override async Task InvokeAsync(HttpContext ctx, Database database)
|
||||
{
|
||||
User? user = database.UserFromWebRequest(ctx.Request);
|
||||
if (user == null || ctx.Request.Path.StartsWithSegments("/logout"))
|
||||
if (user == null || pathContains(ctx, "/logout"))
|
||||
{
|
||||
await this.next(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
WebToken token = await database.WebTokens.FirstAsync(t => t.UserId == user.UserId);
|
||||
|
||||
// Request ends with a path (e.g. /css/style.css)
|
||||
if (!string.IsNullOrEmpty(Path.GetExtension(ctx.Request.Path)) || ctx.Request.Path.StartsWithSegments("/gameAssets"))
|
||||
if (!string.IsNullOrEmpty(Path.GetExtension(ctx.Request.Path)) || pathContains(ctx, "/gameAssets"))
|
||||
{
|
||||
await this.next(ctx);
|
||||
return;
|
||||
|
@ -27,8 +31,7 @@ public class UserRequiredRedirectMiddleware : MiddlewareDBContext
|
|||
|
||||
if (user.PasswordResetRequired)
|
||||
{
|
||||
if (!ctx.Request.Path.StartsWithSegments("/passwordResetRequired") &&
|
||||
!ctx.Request.Path.StartsWithSegments("/passwordReset"))
|
||||
if (!pathContains(ctx, "/passwordResetRequired", "/passwordReset"))
|
||||
{
|
||||
ctx.Response.Redirect("/passwordResetRequired");
|
||||
return;
|
||||
|
@ -38,7 +41,7 @@ public class UserRequiredRedirectMiddleware : MiddlewareDBContext
|
|||
return;
|
||||
}
|
||||
|
||||
if (ServerConfiguration.Instance.Mail.MailEnabled)
|
||||
if (!user.EmailAddressVerified && ServerConfiguration.Instance.Mail.MailEnabled)
|
||||
{
|
||||
// The normal flow is for users to set their email during login so just force them to log out
|
||||
if (user.EmailAddress == null)
|
||||
|
@ -47,15 +50,44 @@ public class UserRequiredRedirectMiddleware : MiddlewareDBContext
|
|||
return;
|
||||
}
|
||||
|
||||
if (!user.EmailAddressVerified &&
|
||||
!ctx.Request.Path.StartsWithSegments("/login/sendVerificationEmail") &&
|
||||
!ctx.Request.Path.StartsWithSegments("/verifyEmail"))
|
||||
if (!pathContains(ctx, "/login/sendVerificationEmail", "/verifyEmail"))
|
||||
{
|
||||
ctx.Response.Redirect("/login/sendVerificationEmail");
|
||||
return;
|
||||
}
|
||||
|
||||
await this.next(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.TwoFactorRequired && !user.IsTwoFactorSetup && ServerConfiguration.Instance.TwoFactorConfiguration.TwoFactorEnabled)
|
||||
{
|
||||
if (!pathContains(ctx, "/setup2fa"))
|
||||
{
|
||||
ctx.Response.Redirect("/setup2fa");
|
||||
return;
|
||||
}
|
||||
|
||||
await this.next(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!token.Verified && ServerConfiguration.Instance.TwoFactorConfiguration.TwoFactorEnabled)
|
||||
{
|
||||
if (!pathContains(ctx, "/2fa"))
|
||||
{
|
||||
ctx.Response.Redirect("/2fa");
|
||||
return;
|
||||
}
|
||||
await this.next(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.next(ctx);
|
||||
}
|
||||
|
||||
private static bool pathContains(HttpContext ctx, params string[] pathList)
|
||||
{
|
||||
return pathList.Any(path => ctx.Request.Path.StartsWithSegments(path));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue