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:
parent
1c58395bca
commit
e497f6bf9b
|
@ -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}}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue