Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update email change flow #22

Merged
merged 1 commit into from
Aug 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Bulwark.Auth.sln
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
README.md = README.md
updateVersion.sh = updateVersion.sh
.releaserc = .releaserc
docker-compose.yaml = docker-compose.yaml
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bulwark.Auth", "src\Bulwark.Auth\Bulwark.Auth.csproj", "{5701FC78-6876-4EB9-8E32-D8EFC12FF9EB}"
Expand Down
11 changes: 11 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
services:
mongodb:
image: "mongo:latest"
ports:
- 27017:27017
mailhog:
image: "mailhog/mailhog:latest"
ports:
- 1025:1025
- 8025:8025

11 changes: 6 additions & 5 deletions src/Bulwark.Auth.Core/AccountService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,17 @@ public async Task Delete(string email, string accessToken)
/// <param name="newEmail"></param>
/// <param name="accessToken"></param>
/// <exception cref="BulwarkAccountException"></exception>
public async Task ChangeEmail(string oldEmail, string newEmail,
public async Task<VerificationToken> ChangeEmail(string oldEmail, string newEmail,
string accessToken)
{
try
{
var token = await ValidAccessToken(oldEmail, accessToken);
if (token != null)
{
await _accountRepository.ChangeEmail(oldEmail, newEmail);
}
if (token == null) throw new BulwarkTokenException("Invalid access token");
var verificationModel = await _accountRepository.ChangeEmail(oldEmail, newEmail);

return new VerificationToken(verificationModel.Token,
verificationModel.Created);
}
catch (BulwarkDbDuplicateException exception)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Bulwark.Auth.Core/IAccountService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Task<VerificationToken> Create(string email,
string password);
Task Verify(string email, string verificationToken);
Task Delete(string email, string accessToken);
Task ChangeEmail(string oldEmail, string newEmail,
Task<VerificationToken> ChangeEmail(string oldEmail, string newEmail,
string accessToken);
Task ChangePassword(string email, string newPassword,
string accessToken);
Expand Down
2 changes: 1 addition & 1 deletion src/Bulwark.Auth.Repositories/IAccountRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public interface IAccountRepository
Task Delete(string email);
Task Disable(string email);
Task Enable(string email);
Task ChangeEmail(string oldEmail, string newEmail);
Task<VerificationModel> ChangeEmail(string oldEmail, string newEmail);
Task ChangePassword(string email, string newPassword);
Task LinkSocial(string email, SocialProvider provider);
Task<ForgotModel> ForgotPassword(string email);
Expand Down
12 changes: 10 additions & 2 deletions src/Bulwark.Auth.Repositories/MongoDbAccount.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,20 @@ public async Task Enable(string email)
/// <returns></returns>
/// <exception cref="BulwarkDbException"></exception>
/// <exception cref="BulwarkDbDuplicateException"></exception>
public async Task ChangeEmail(string email, string newEmail)
public async Task<VerificationModel> ChangeEmail(string email, string newEmail)
{
try
{
var update = Builders<AccountModel>.Update
.Set(p => p.Email, newEmail)
.Set(p => p.IsVerified, false)
.Set(p => p.Modified, DateTime.Now);


var verification = new VerificationModel(newEmail,
Guid.NewGuid().ToString());

await _verificationCollection.InsertOneAsync(verification);

var result = await _accountCollection.
UpdateOneAsync(a => a.Email == email, update);

Expand All @@ -188,6 +194,8 @@ public async Task ChangeEmail(string email, string newEmail)
throw
new BulwarkDbException($"Email: {email} could not be found");
}

return verification;
}
catch(MongoWriteException exception)
{
Expand Down
4 changes: 3 additions & 1 deletion src/Bulwark.Auth/Bulwark.Auth.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Templates\" />
<Folder Include="Templates\Email\" />
<Content Remove="Templates\Email\MagicLink.cshtml" />
<AdditionalFiles Include="Templates\Email\ChangeEmail.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</AdditionalFiles>
<AdditionalFiles Include="Templates\Email\MagicLink.cshtml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</AdditionalFiles>
Expand Down
34 changes: 31 additions & 3 deletions src/Bulwark.Auth/Controllers/AccountsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,48 @@ public async Task<ActionResult> DeleteAccount(Delete payload)
[Route("email")]
public async Task<ActionResult> ChangeEmail(ChangeEmail payload)
{
var subject = "Please verify your account";
const string templateDir = "Templates/Email/ChangeEmail.cshtml";

try
{
EmailValidator.Validate(payload.NewEmail);
await _accountService.ChangeEmail(payload.Email,
var verificationToken = await _accountService.ChangeEmail(payload.Email,
payload.NewEmail, payload.AccessToken);
if (Environment.GetEnvironmentVariable("SERVICE_MODE")?.ToLower() == "test")
{
subject = verificationToken.Value;
}

var verificationEmail = _email
.To(payload.Email)
.Subject(subject)
.UsingTemplateFromFile(templateDir,
new
{
payload.Email,
VerificationToken = verificationToken.Value,
VerificationUrl = Environment.GetEnvironmentVariable("VERIFICATION_URL"),
WebsiteName = Environment.GetEnvironmentVariable("WEBSITE_NAME")
});

var emailResponse = await verificationEmail.SendAsync();
if (!emailResponse.Successful)
{
return Problem(
title: "Email successfully changed but failed to send verification email",
detail: string.Join( ",", emailResponse.ErrorMessages),
statusCode: StatusCodes.Status400BadRequest);
}
return NoContent();
}
catch (Exception exception)
{
return Problem(
title: "Bad Input",
title: "Cannot change email",
detail: exception.Message,
statusCode: StatusCodes.Status400BadRequest
);
);
}
}

Expand Down
12 changes: 12 additions & 0 deletions src/Bulwark.Auth/Templates/Email/ChangeEmail.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Hello,

Your email on your account has been changed. Please click the link below to verify and
enable the account with the new email.

@[email protected]&[email protected]

Please don't reply to this email - This message is from an automated system.

Best regards,

@Model.WebsiteName
1 change: 1 addition & 0 deletions tests/Bulwark.Auth.Repository.Tests/MongoDbAccountTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ public async void ChangeEmailTest()
await _accountRepository.ChangeEmail(user, newEmail);
var account = await _accountRepository.GetAccount(newEmail);
Assert.True(account.Email == newEmail);
Assert.False(account.IsVerified);
}
catch (System.Exception exception)
{
Expand Down
Loading