UX: Allow resetting password when confirming session (#25708)

This is particularly useful in scenarios where 2FA is enforced and users have forgotten their password.
This commit is contained in:
Penar Musaraj 2024-02-16 12:18:07 -05:00 committed by GitHub
parent 1c58395bca
commit e497f6bf9b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 67 additions and 7 deletions

View File

@ -6,7 +6,7 @@ import { inject as service } from "@ember/service";
import DButton from "discourse/components/d-button";
import UserLink from "discourse/components/user-link";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { extractError, popupAjaxError } from "discourse/lib/ajax-error";
import {
getPasskeyCredential,
isWebauthnSupported,
@ -19,6 +19,7 @@ export default class ConfirmSession extends Component {
@service siteSettings;
@tracked errorMessage;
@tracked resetEmailSent = null;
passwordLabel = I18n.t("user.password.title");
instructions = I18n.t("user.confirm_access.instructions");
@ -82,6 +83,32 @@ export default class ConfirmSession extends Component {
}
}
@action
async sendPasswordResetEmail() {
try {
const result = await ajax("/session/forgot_password.json", {
data: { login: this.currentUser.username },
type: "POST",
});
if (result.success) {
this.errorMessage = null;
this.resetEmailSent = I18n.t(
"user.confirm_access.password_reset_email_sent"
);
} else {
this.errorMessage = I18n.t(
"user.confirm_access.cannot_send_password_reset_email"
);
}
} catch (e) {
this.errorMessage = extractError(
e,
I18n.t("user.confirm_access.cannot_send_password_reset_email")
);
}
}
<template>
{{#if this.errorMessage}}
<div class="alert alert-error">
@ -119,12 +146,24 @@ export default class ConfirmSession extends Component {
@label="user.password.confirm"
/>
</div>
<div class="confirm-session__reset">
<DButton
@label="user.confirm_access.forgot_password"
@action={{this.sendPasswordResetEmail}}
@class="btn-link btn-flat confirm-session__reset-btn"
/>
{{#if this.resetEmailSent}}
<span class="confirm-session__reset-email-sent">
{{this.resetEmailSent}}
</span>
{{/if}}
</div>
{{#if this.canUsePasskeys}}
<div class="confirm-session__passkey">
<DButton
class="btn-flat"
@action={{this.confirmWithPasskey}}
@label="user.passkeys.confirm_button"
@icon="user"
/>
</div>
{{/if}}

View File

@ -21,6 +21,10 @@ acceptance("User Preferences - Security", function (needs) {
server.get("/u/trusted-session.json", () => {
return helper.response({ failed: "FAILED" });
});
server.post("/session/forgot_password.json", () => {
return helper.response({ success: "Ok" });
});
});
test("recently connected devices", async function (assert) {
@ -144,6 +148,16 @@ acceptance("User Preferences - Security", function (needs) {
.dom(".dialog-body .confirm-session__passkey")
.exists("dialog includes a passkey button");
assert
.dom(".dialog-body .confirm-session__reset")
.exists("dialog includes a link to reset the password");
await click(".dialog-body .confirm-session__reset-btn");
assert
.dom(".confirm-session__reset-email-sent")
.exists("shows reset email confirmation message");
await click(".dialog-close");
const dropdown = selectKit(".passkey-options-dropdown");

View File

@ -713,22 +713,26 @@
.confirm-session {
&__instructions {
margin-bottom: 1.5em;
margin-bottom: 0.5em;
}
form {
margin: 1.5em 0;
}
&__passkey .btn {
padding-left: 0.25em;
padding-right: 0.25em;
&__passkey {
margin-top: 1em;
}
&__fine-print {
font-size: var(--font-down-1);
color: var(--primary-medium);
max-width: 500px;
max-width: 600px;
}
&__reset {
font-size: var(--font-down-1);
color: var(--primary-medium);
}
}

View File

@ -1869,6 +1869,9 @@ en:
incorrect_password: "The entered password is incorrect."
incorrect_passkey: "That passkey is incorrect."
logged_in_as: "You are logged in as: "
forgot_password: "Forgot your password?"
password_reset_email_sent: "Password reset email sent."
cannot_send_password_reset_email: "Could not send password reset email."
instructions: "Please confirm your identity in order to complete this action."
fine_print: "We are asking you to confirm your identity because this is a potentially sensitive action. Once authenticated, you will only be asked to re-authenticate again after a few hours of inactivity."
password: