mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-08-05 11:28:39 +00:00
Add email verification step
This commit is contained in:
parent
cc2159d539
commit
b129ec1ab1
13 changed files with 201 additions and 1017 deletions
|
@ -86,7 +86,7 @@ public class Database : DbContext
|
||||||
string body = "An account for Project Lighthouse has been registered with this email address.\n\n" +
|
string body = "An account for Project Lighthouse has been registered with this email address.\n\n" +
|
||||||
$"You can login at {ServerSettings.Instance.ExternalUrl}.";
|
$"You can login at {ServerSettings.Instance.ExternalUrl}.";
|
||||||
|
|
||||||
SMTPHelper.SendEmail(emailAddress, "Account Created: " + username, body);
|
SMTPHelper.SendEmail(emailAddress, "Project Lighthouse Account Created: " + username, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,9 +1,13 @@
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using LBPUnion.ProjectLighthouse;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
namespace ProjectLighthouse.Migrations
|
namespace ProjectLighthouse.Migrations
|
||||||
{
|
{
|
||||||
|
[DbContext(typeof(Database))]
|
||||||
|
[Migration("20220301195426_AddEmailAddressToUser")]
|
||||||
public partial class AddEmailAddressToUser : Migration
|
public partial class AddEmailAddressToUser : Migration
|
||||||
{
|
{
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
using LBPUnion.ProjectLighthouse;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace ProjectLighthouse.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(Database))]
|
||||||
|
[Migration("20220302003658_AddEmailVerifiedToUser")]
|
||||||
|
public partial class AddEmailVerifiedToUser : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "EmailAddressVerified",
|
||||||
|
table: "Users",
|
||||||
|
type: "tinyint(1)",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "EmailAddressVerified",
|
||||||
|
table: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -710,6 +710,9 @@ namespace ProjectLighthouse.Migrations
|
||||||
b.Property<string>("EmailAddress")
|
b.Property<string>("EmailAddress")
|
||||||
.HasColumnType("longtext");
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<bool>("EmailAddressVerified")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
b.Property<int>("Game")
|
b.Property<int>("Game")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
|
27
ProjectLighthouse/Pages/CompleteEmailVerificationPage.cshtml
Normal file
27
ProjectLighthouse/Pages/CompleteEmailVerificationPage.cshtml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
@page "/verifyEmail"
|
||||||
|
@model LBPUnion.ProjectLighthouse.Pages.CompleteEmailVerificationPage
|
||||||
|
|
||||||
|
@{
|
||||||
|
Layout = "Layouts/BaseLayout";
|
||||||
|
|
||||||
|
if (Model.Error == null)
|
||||||
|
{
|
||||||
|
Model.Title = "Email Address Verified";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Model.Title = "Couldn't verify email address";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (Model.Error != null)
|
||||||
|
{
|
||||||
|
<p>@Model.Error</p>
|
||||||
|
<a href="/login/sendVerificationEmail">
|
||||||
|
<div class="ui blue button">Resend email</div>
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<p>Your email has been successfully verified. You may now close this tab.</p>
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#nullable enable
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Profiles.Email;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Pages;
|
||||||
|
|
||||||
|
public class CompleteEmailVerificationPage : BaseLayout
|
||||||
|
{
|
||||||
|
public CompleteEmailVerificationPage([NotNull] Database database) : base(database)
|
||||||
|
{}
|
||||||
|
|
||||||
|
public string? Error = null;
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnGet(string token)
|
||||||
|
{
|
||||||
|
User? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
|
if (user == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
|
EmailVerificationToken? emailVerifyToken = await this.Database.EmailVerificationTokens.FirstOrDefaultAsync(e => e.EmailToken == token);
|
||||||
|
if (emailVerifyToken == null)
|
||||||
|
{
|
||||||
|
this.Error = "Invalid verification token";
|
||||||
|
return this.Page();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Database.EmailVerificationTokens.Remove(emailVerifyToken);
|
||||||
|
|
||||||
|
user.EmailAddressVerified = true;
|
||||||
|
|
||||||
|
await this.Database.SaveChangesAsync();
|
||||||
|
|
||||||
|
return this.Page();
|
||||||
|
}
|
||||||
|
}
|
|
@ -105,6 +105,7 @@ public class LoginForm : BaseLayout
|
||||||
Logger.Log($"User {user.Username} (id: {user.UserId}) successfully logged in on web", LoggerLevelLogin.Instance);
|
Logger.Log($"User {user.Username} (id: {user.UserId}) successfully logged in on web", LoggerLevelLogin.Instance);
|
||||||
|
|
||||||
if (user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired");
|
if (user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired");
|
||||||
|
if (!user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail");
|
||||||
|
|
||||||
return this.RedirectToPage(nameof(LandingPage));
|
return this.RedirectToPage(nameof(LandingPage));
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,8 @@ public class PasswordResetPage : BaseLayout
|
||||||
|
|
||||||
await this.Database.SaveChangesAsync();
|
await this.Database.SaveChangesAsync();
|
||||||
|
|
||||||
|
if (!user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail");
|
||||||
|
|
||||||
return this.Redirect("~/");
|
return this.Redirect("~/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
ProjectLighthouse/Pages/SendVerificationEmailPage.cshtml
Normal file
14
ProjectLighthouse/Pages/SendVerificationEmailPage.cshtml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
@page "/login/sendVerificationEmail"
|
||||||
|
@model LBPUnion.ProjectLighthouse.Pages.SendVerificationEmailPage
|
||||||
|
|
||||||
|
@{
|
||||||
|
Layout = "Layouts/BaseLayout";
|
||||||
|
Model.Title = "Verify Email Address";
|
||||||
|
}
|
||||||
|
|
||||||
|
<p>An email address on your account has been set, but hasn't been verified yet.</p>
|
||||||
|
<p>To verify it, check the email sent to <a href="mailto:@Model.User.EmailAddress">@Model.User.EmailAddress</a> and click the link in the email.</p>
|
||||||
|
|
||||||
|
<a href="/login/sendVerificationEmail">
|
||||||
|
<div class="ui blue button">Resend email</div>
|
||||||
|
</a>
|
47
ProjectLighthouse/Pages/SendVerificationEmailPage.cshtml.cs
Normal file
47
ProjectLighthouse/Pages/SendVerificationEmailPage.cshtml.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#nullable enable
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Profiles.Email;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Pages;
|
||||||
|
|
||||||
|
public class SendVerificationEmailPage : BaseLayout
|
||||||
|
{
|
||||||
|
public SendVerificationEmailPage(Database database) : base(database)
|
||||||
|
{}
|
||||||
|
|
||||||
|
public async Task<IActionResult> OnGet()
|
||||||
|
{
|
||||||
|
User? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
|
if (user == null) return this.Redirect("/login");
|
||||||
|
|
||||||
|
EmailVerificationToken verifyToken = new()
|
||||||
|
{
|
||||||
|
UserId = user.UserId,
|
||||||
|
User = user,
|
||||||
|
EmailToken = HashHelper.GenerateAuthToken(),
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Database.EmailVerificationTokens.Add(verifyToken);
|
||||||
|
|
||||||
|
await this.Database.SaveChangesAsync();
|
||||||
|
|
||||||
|
string body = "Hello,\n\n" +
|
||||||
|
$"A request to verify this email for your Project Lighthouse account ({user.Username}).\n\n" +
|
||||||
|
$"To verify your account, click this link: {ServerSettings.Instance.ExternalUrl}/verifyEmail?token={verifyToken.EmailToken}";
|
||||||
|
|
||||||
|
if (SMTPHelper.SendEmail(user.EmailAddress, "Project Lighthouse Email Verification", body))
|
||||||
|
{
|
||||||
|
return this.Page();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("failed to send email");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,13 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Kettu;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Profiles.Email;
|
using LBPUnion.ProjectLighthouse.Types.Profiles.Email;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
@ -35,17 +40,39 @@ public class SetEmailForm : BaseLayout
|
||||||
emailToken.User.EmailAddress = emailAddress;
|
emailToken.User.EmailAddress = emailAddress;
|
||||||
this.Database.EmailSetTokens.Remove(emailToken);
|
this.Database.EmailSetTokens.Remove(emailToken);
|
||||||
|
|
||||||
|
User user = emailToken.User;
|
||||||
|
|
||||||
EmailVerificationToken emailVerifyToken = new()
|
EmailVerificationToken emailVerifyToken = new()
|
||||||
{
|
{
|
||||||
UserId = emailToken.UserId,
|
UserId = user.UserId,
|
||||||
User = emailToken.User,
|
User = user,
|
||||||
EmailToken = HashHelper.GenerateAuthToken(),
|
EmailToken = HashHelper.GenerateAuthToken(),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.Database.EmailVerificationTokens.Add(emailVerifyToken);
|
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.
|
||||||
|
WebToken webToken = new()
|
||||||
|
{
|
||||||
|
UserId = user.UserId,
|
||||||
|
UserToken = HashHelper.GenerateAuthToken(),
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Response.Cookies.Append
|
||||||
|
(
|
||||||
|
"LighthouseToken",
|
||||||
|
webToken.UserToken,
|
||||||
|
new CookieOptions
|
||||||
|
{
|
||||||
|
Expires = DateTimeOffset.Now.AddDays(7),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Logger.Log($"User {user.Username} (id: {user.UserId}) successfully logged in on web after setting an email address", LoggerLevelLogin.Instance);
|
||||||
|
|
||||||
|
this.Database.WebTokens.Add(webToken);
|
||||||
await this.Database.SaveChangesAsync();
|
await this.Database.SaveChangesAsync();
|
||||||
|
|
||||||
return this.Redirect("/login/verify?token=" + emailVerifyToken.EmailToken);
|
return this.Redirect("/login/sendVerificationEmail");
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,6 +18,8 @@ public class User
|
||||||
public string? EmailAddress { get; set; } = null;
|
public string? EmailAddress { get; set; } = null;
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
public bool EmailAddressVerified { get; set; } = false;
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue