+
Email change requested
+
Hello {{ To.Name }},
+
Someone requested that the email address on your OpenShock account be changed to {{ NewEmail }}.
+
The change is not yet applied. It will only take effect once the new address is verified via the link sent to it.
+
If this was you, no action is needed.
+
If this was not you, sign in immediately and change your password — your account may be compromised.
+
Thank you,
OpenShock Team
+
+
+
diff --git a/Common/Constants/Constants.cs b/Common/Constants/Constants.cs
index d9ee0a83..e8ffbbcd 100644
--- a/Common/Constants/Constants.cs
+++ b/Common/Constants/Constants.cs
@@ -7,6 +7,8 @@ public static class Duration
public static readonly TimeSpan PasswordResetRequestLifetime = TimeSpan.FromHours(1);
+ public static readonly TimeSpan EmailChangeRequestLifetime = TimeSpan.FromHours(1);
+
public static readonly TimeSpan NameChangeCooldown = TimeSpan.FromDays(7);
public static readonly TimeSpan LoginSessionLifetime = TimeSpan.FromDays(30);
diff --git a/Common/Errors/AccountError.cs b/Common/Errors/AccountError.cs
index 51c2968b..0f76aab9 100644
--- a/Common/Errors/AccountError.cs
+++ b/Common/Errors/AccountError.cs
@@ -30,4 +30,19 @@ public static class AccountError
public static OpenShockProblem AccountDeactivated => new OpenShockProblem("Account.Deactivated", "Your account has been deactivated", HttpStatusCode.Unauthorized);
public static OpenShockProblem AccountOAuthOnly => new OpenShockProblem("Account.OAuthOnly", "This account is only accessible via OAuth", HttpStatusCode.Unauthorized);
+
+ public static OpenShockProblem PasswordNotSet => new OpenShockProblem("Account.Password.NotSet",
+ "This account has no password set. Initiate a password set flow via POST /password/set instead.", HttpStatusCode.Conflict);
+
+ public static OpenShockProblem EmailChangeAlreadyInUse => new OpenShockProblem("Account.Email.AlreadyInUse",
+ "This email address is already in use", HttpStatusCode.Conflict);
+
+ public static OpenShockProblem EmailChangeUnchanged => new OpenShockProblem("Account.Email.Unchanged",
+ "The new email address is the same as the current one", HttpStatusCode.BadRequest);
+
+ public static OpenShockProblem EmailChangeTooMany => new OpenShockProblem("Account.Email.TooManyRequests",
+ "You have too many pending email change requests", HttpStatusCode.TooManyRequests);
+
+ public static OpenShockProblem EmailChangeNotFound => new OpenShockProblem("Account.Email.VerifyNotFound",
+ "There is no email change request matching the supplied token", HttpStatusCode.BadRequest);
}
\ No newline at end of file
diff --git a/Common/Migrations/20260521205924_AddUserSecurityStamp.Designer.cs b/Common/Migrations/20260521205924_AddUserSecurityStamp.Designer.cs
new file mode 100644
index 00000000..08d179d9
--- /dev/null
+++ b/Common/Migrations/20260521205924_AddUserSecurityStamp.Designer.cs
@@ -0,0 +1,1477 @@
+//