Skip to content

Commit

Permalink
Ability for users to request a password reset token via email
Browse files Browse the repository at this point in the history
Closes ...uh, what? we never had an issue for this?
  • Loading branch information
jvyden committed Nov 3, 2023
1 parent 8d41ab4 commit b035cd7
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 0 deletions.
26 changes: 26 additions & 0 deletions Refresh.GameServer/Endpoints/ApiV3/AuthenticationApiEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,32 @@ public ApiOkResponse ResetPassword(RequestContext context, GameDatabaseContext d

return new ApiOkResponse();
}

[ApiV3Endpoint("sendPasswordResetEmail", HttpMethods.Put), Authentication(false)]
[RateLimitSettings(86400 / 2, 5, 86400, "resetPassword")]
public ApiOkResponse SendPasswordResetEmail(RequestContext context,
GameDatabaseContext database,
ApiSendPasswordResetEmailRequest body,
SmtpService smtpService)
{
GameUser? user = database.GetUserByEmailAddress(body.EmailAddress);
if (user == null)
{
context.Logger.LogWarning(RefreshContext.PasswordReset, "Couldn't find a user by the email '{0}', not sending email", body.EmailAddress);
// return a fake success on purpose
return new ApiOkResponse();
}

context.Logger.LogInfo(RefreshContext.PasswordReset, "Sending a password reset request email to {0}.", user.Username);
context.Logger.LogTrace(RefreshContext.PasswordReset, "Generating a reset token for {0}", user.Username);

Token token = database.GenerateTokenForUser(user, TokenType.PasswordReset, TokenGame.Website, TokenPlatform.Website);
context.Logger.LogTrace(RefreshContext.PasswordReset, "Reset token: {0}", token.TokenData);
smtpService.SendPasswordResetRequest(user, token.TokenData);

context.Logger.LogTrace(RefreshContext.PasswordReset, "Email sent, token will expire at {0}", token.ExpiresAt);
return new ApiOkResponse();
}

[ApiV3Endpoint("logout", HttpMethods.Put), MinimumRole(GameUserRole.Restricted)]
[DocSummary("Tells the server to revoke the token used to make this request. Useful for logout behavior.")]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Refresh.GameServer.Endpoints.ApiV3.DataTypes.Request.Authentication;

#nullable disable

[JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
public class ApiSendPasswordResetEmailRequest
{
public string EmailAddress { get; set; }
}
1 change: 1 addition & 0 deletions Refresh.GameServer/RefreshContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ public enum RefreshContext
Startup,
Worker,
Discord,
PasswordReset,
}
20 changes: 20 additions & 0 deletions Refresh.GameServer/Services/SmtpService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,24 @@ public bool SendEmailVerificationRequest(GameUser user, string code)
The {this._gameConfig.InstanceName} Team
""");
}

public bool SendPasswordResetRequest(GameUser user, string token)
{
if (user.EmailAddress == null)
throw new InvalidOperationException("Cannot send verification request for user with no email");

return this.SendEmail(user.EmailAddress, $"Password Reset Request for {this._gameConfig.InstanceName}",
$"""
Hi {user.Username} (id: {user.UserId.ToString()}),
We've received a request to reset your password on your account for {this._gameConfig.InstanceName}.
To reset your password, continue via your browser by clicking the following link: {this._gameConfig.WebExternalUrl}/resetPassword?token={token}
If you didn't initiate this request, please disregard this message.
Best regards,
The {this._gameConfig.InstanceName} Team
""");
}
}

0 comments on commit b035cd7

Please sign in to comment.