diff --git a/Bulwark.Auth.sln b/Bulwark.Auth.sln
index 96d0275..92b9f5f 100644
--- a/Bulwark.Auth.sln
+++ b/Bulwark.Auth.sln
@@ -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}"
diff --git a/docker-compose.yaml b/docker-compose.yaml
new file mode 100644
index 0000000..371cf8c
--- /dev/null
+++ b/docker-compose.yaml
@@ -0,0 +1,11 @@
+services:
+ mongodb:
+ image: "mongo:latest"
+ ports:
+ - 27017:27017
+ mailhog:
+ image: "mailhog/mailhog:latest"
+ ports:
+ - 1025:1025
+ - 8025:8025
+
\ No newline at end of file
diff --git a/src/Bulwark.Auth.Core/AccountService.cs b/src/Bulwark.Auth.Core/AccountService.cs
index 0bcc0ee..7cdf686 100644
--- a/src/Bulwark.Auth.Core/AccountService.cs
+++ b/src/Bulwark.Auth.Core/AccountService.cs
@@ -97,16 +97,17 @@ public async Task Delete(string email, string accessToken)
///
///
///
- public async Task ChangeEmail(string oldEmail, string newEmail,
+ public async Task 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)
{
diff --git a/src/Bulwark.Auth.Core/IAccountService.cs b/src/Bulwark.Auth.Core/IAccountService.cs
index d3fce8c..583a75e 100644
--- a/src/Bulwark.Auth.Core/IAccountService.cs
+++ b/src/Bulwark.Auth.Core/IAccountService.cs
@@ -8,7 +8,7 @@ Task Create(string email,
string password);
Task Verify(string email, string verificationToken);
Task Delete(string email, string accessToken);
- Task ChangeEmail(string oldEmail, string newEmail,
+ Task ChangeEmail(string oldEmail, string newEmail,
string accessToken);
Task ChangePassword(string email, string newPassword,
string accessToken);
diff --git a/src/Bulwark.Auth.Repositories/IAccountRepository.cs b/src/Bulwark.Auth.Repositories/IAccountRepository.cs
index aa2a97b..80978ab 100644
--- a/src/Bulwark.Auth.Repositories/IAccountRepository.cs
+++ b/src/Bulwark.Auth.Repositories/IAccountRepository.cs
@@ -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 ChangeEmail(string oldEmail, string newEmail);
Task ChangePassword(string email, string newPassword);
Task LinkSocial(string email, SocialProvider provider);
Task ForgotPassword(string email);
diff --git a/src/Bulwark.Auth.Repositories/MongoDbAccount.cs b/src/Bulwark.Auth.Repositories/MongoDbAccount.cs
index d016525..f3f5556 100644
--- a/src/Bulwark.Auth.Repositories/MongoDbAccount.cs
+++ b/src/Bulwark.Auth.Repositories/MongoDbAccount.cs
@@ -172,14 +172,20 @@ public async Task Enable(string email)
///
///
///
- public async Task ChangeEmail(string email, string newEmail)
+ public async Task ChangeEmail(string email, string newEmail)
{
try
{
var update = Builders.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);
@@ -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)
{
diff --git a/src/Bulwark.Auth/Bulwark.Auth.csproj b/src/Bulwark.Auth/Bulwark.Auth.csproj
index d2599c1..7abf375 100644
--- a/src/Bulwark.Auth/Bulwark.Auth.csproj
+++ b/src/Bulwark.Auth/Bulwark.Auth.csproj
@@ -41,8 +41,10 @@
-
+
+ Always
+
Always
diff --git a/src/Bulwark.Auth/Controllers/AccountsController.cs b/src/Bulwark.Auth/Controllers/AccountsController.cs
index fa9ae70..506d23e 100644
--- a/src/Bulwark.Auth/Controllers/AccountsController.cs
+++ b/src/Bulwark.Auth/Controllers/AccountsController.cs
@@ -124,20 +124,48 @@ public async Task DeleteAccount(Delete payload)
[Route("email")]
public async Task 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
- );
+ );
}
}
diff --git a/src/Bulwark.Auth/Templates/Email/ChangeEmail.cshtml b/src/Bulwark.Auth/Templates/Email/ChangeEmail.cshtml
new file mode 100644
index 0000000..fbc1d2a
--- /dev/null
+++ b/src/Bulwark.Auth/Templates/Email/ChangeEmail.cshtml
@@ -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.
+
+@Model.VerificationUrl?email=@Model.Email&vt=@Model.VerificationToken
+
+Please don't reply to this email - This message is from an automated system.
+
+Best regards,
+
+@Model.WebsiteName
\ No newline at end of file
diff --git a/tests/Bulwark.Auth.Repository.Tests/MongoDbAccountTests.cs b/tests/Bulwark.Auth.Repository.Tests/MongoDbAccountTests.cs
index f21ae48..051f6b1 100644
--- a/tests/Bulwark.Auth.Repository.Tests/MongoDbAccountTests.cs
+++ b/tests/Bulwark.Auth.Repository.Tests/MongoDbAccountTests.cs
@@ -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)
{