Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit e5ce6d7

Browse files
authored
New password reset flow (#9581)
1 parent 3f74ac3 commit e5ce6d7

File tree

23 files changed

+1151
-350
lines changed

23 files changed

+1151
-350
lines changed

res/css/_components.pcss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
@import "./structures/_BackdropPanel.pcss";
5050
@import "./structures/_CompatibilityPage.pcss";
5151
@import "./structures/_ContextualMenu.pcss";
52+
@import "./structures/_ErrorMessage.pcss";
5253
@import "./structures/_FileDropTarget.pcss";
5354
@import "./structures/_FilePanel.pcss";
5455
@import "./structures/_GenericDropdownMenu.pcss";
@@ -157,6 +158,7 @@
157158
@import "./views/dialogs/_UntrustedDeviceDialog.pcss";
158159
@import "./views/dialogs/_UploadConfirmDialog.pcss";
159160
@import "./views/dialogs/_UserSettingsDialog.pcss";
161+
@import "./views/dialogs/_VerifyEMailDialog.pcss";
160162
@import "./views/dialogs/_WidgetCapabilitiesPromptDialog.pcss";
161163
@import "./views/dialogs/security/_AccessSecretStorageDialog.pcss";
162164
@import "./views/dialogs/security/_CreateCrossSigningDialog.pcss";

res/css/compound/_Icon.pcss

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,30 @@ limitations under the License.
2525
padding: 1px;
2626
}
2727

28+
.mx_Icon_accent {
29+
color: $accent;
30+
}
31+
2832
.mx_Icon_8 {
29-
height: 8px;
3033
flex: 0 0 8px;
34+
height: 8px;
3135
width: 8px;
3236
}
3337

3438
.mx_Icon_16 {
35-
height: 16px;
3639
flex: 0 0 16px;
40+
height: 16px;
3741
width: 16px;
3842
}
3943

4044
.mx_Icon_24 {
41-
height: 24px;
4245
flex: 0 0 24px;
46+
height: 24px;
4347
width: 24px;
4448
}
49+
50+
.mx_Icon_32 {
51+
flex: 0 0 32px;
52+
height: 32px;
53+
width: 32px;
54+
}

res/css/structures/_ErrorMessage.pcss

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
Copyright 2022 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
.mx_ErrorMessage {
18+
align-items: center;
19+
color: $alert;
20+
display: flex;
21+
font-size: $font-12px;
22+
gap: $spacing-8;
23+
line-height: 1.2em;
24+
min-height: 2.4em;
25+
}

res/css/structures/auth/_Login.pcss

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ limitations under the License.
1717

1818
.mx_Login_submit {
1919
@mixin mx_DialogButton;
20+
font-size: 15px;
21+
font-weight: 600;
2022
width: 100%;
2123
margin-top: 24px;
2224
margin-bottom: 24px;
@@ -87,7 +89,7 @@ limitations under the License.
8789

8890
div.mx_AccessibleButton_kind_link.mx_Login_forgot {
8991
display: block;
90-
margin: 0 auto;
92+
margin-top: 24px;
9193

9294
&.mx_AccessibleButton_disabled {
9395
cursor: not-allowed;

res/css/views/auth/_AuthBody.pcss

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,17 @@ limitations under the License.
1717

1818
.mx_AuthBody {
1919
width: 500px;
20-
font-size: $font-12px;
21-
color: $authpage-secondary-color;
20+
font-size: $font-14px;
21+
color: $primary-content;
2222
background-color: $background;
2323
border-radius: 0 4px 4px 0;
24-
padding: 25px 60px;
24+
padding: 50px 32px;
2525
box-sizing: border-box;
26+
min-height: 600px;
27+
28+
b {
29+
font-weight: 600;
30+
}
2631

2732
&.mx_AuthBody_flex {
2833
display: flex;
@@ -32,7 +37,8 @@ limitations under the License.
3237
h1 {
3338
font-size: $font-24px;
3439
font-weight: $font-semi-bold;
35-
margin-top: 8px;
40+
margin-bottom: $spacing-20;
41+
margin-top: $spacing-24;
3642
color: $authpage-primary-color;
3743
}
3844

@@ -52,6 +58,23 @@ limitations under the License.
5258
@mixin mx_Dialog_link;
5359
}
5460

61+
fieldset {
62+
display: block;
63+
}
64+
65+
.mx_AuthBody_icon {
66+
width: 40px;
67+
}
68+
69+
.mx_AuthBody_lockIcon {
70+
height: 29px;
71+
}
72+
73+
.mx_AuthBody_text {
74+
margin-bottom: $spacing-48;
75+
margin-top: 0;
76+
}
77+
5578
input[type="text"],
5679
input[type="password"] {
5780
color: $authpage-primary-color;
@@ -76,6 +99,16 @@ limitations under the License.
7699
color: $alert;
77100
}
78101

102+
.mx_Login_submit {
103+
height: 33px;
104+
margin-top: $spacing-16;
105+
}
106+
107+
.mx_ErrorMessage {
108+
margin-bottom: 12px;
109+
margin-top: 2px;
110+
}
111+
79112
.mx_Field input {
80113
box-sizing: border-box;
81114
}
@@ -101,6 +134,43 @@ limitations under the License.
101134
}
102135
}
103136

137+
.mx_AuthBody_did-not-receive {
138+
align-items: center;
139+
color: $secondary-content;
140+
display: flex;
141+
gap: $spacing-8;
142+
margin-bottom: 10px;
143+
margin-top: $spacing-24;
144+
}
145+
146+
.mx_AuthBody_did-not-receive--centered {
147+
justify-content: center;
148+
}
149+
150+
.mx_AuthBody_resend-button {
151+
align-items: center;
152+
border-radius: 8px;
153+
color: $accent;
154+
display: flex;
155+
gap: $spacing-4;
156+
padding: 4px;
157+
158+
&:hover {
159+
background-color: $system;
160+
}
161+
}
162+
163+
.mx_AuthBody_emailPromptIcon {
164+
width: 57px;
165+
}
166+
167+
.mx_AuthBody_emailPromptIcon--shifted {
168+
margin-bottom: -17px; // Prevent layout jump by relative positioning.
169+
position: relative;
170+
top: -17px; // This icon is higher than the other icons. Shift up to prevent icon jumping.
171+
width: 57px;
172+
}
173+
104174
.mx_AuthBody_fieldRow {
105175
display: flex;
106176
margin-bottom: 10px;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
Copyright 2022 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
.mx_VerifyEMailDialog {
18+
.mx_Dialog {
19+
color: $primary-content;
20+
font-size: 14px;
21+
padding: 16px;
22+
text-align: center;
23+
width: 485px;
24+
25+
h1 {
26+
font-size: $font-24px;
27+
font-weight: 600;
28+
}
29+
30+
.mx_VerifyEMailDialog_text-light {
31+
color: $secondary-content;
32+
line-height: 20px;
33+
}
34+
}
35+
}

res/css/views/elements/_AccessibleButton.pcss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ limitations under the License.
2424
&.mx_AccessibleButton_kind_primary_outline,
2525
&.mx_AccessibleButton_kind_primary_sm,
2626
&.mx_AccessibleButton_kind_link,
27+
&.mx_AccessibleButton_kind_link_accent,
2728
&.mx_AccessibleButton_kind_link_inline,
2829
&.mx_AccessibleButton_kind_danger_inline,
2930
&.mx_AccessibleButton_kind_content_inline,

res/img/element-icons/Checkbox.svg

Lines changed: 3 additions & 0 deletions
Loading

res/img/element-icons/Email-icon.svg

Lines changed: 3 additions & 0 deletions
Loading

res/img/element-icons/lock.svg

Lines changed: 1 addition & 3 deletions
Loading

res/img/element-icons/retry.svg

Lines changed: 6 additions & 2 deletions
Loading

src/PasswordReset.ts

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import { createClient, IRequestTokenResponse, MatrixClient } from 'matrix-js-sdk
1919

2020
import { _t } from './languageHandler';
2121

22+
const CHECK_EMAIL_VERIFIED_POLL_INTERVAL = 2000;
23+
2224
/**
2325
* Allows a user to reset their password on a homeserver.
2426
*
@@ -29,9 +31,10 @@ import { _t } from './languageHandler';
2931
export default class PasswordReset {
3032
private client: MatrixClient;
3133
private clientSecret: string;
32-
private password: string;
33-
private sessionId: string;
34-
private logoutDevices: boolean;
34+
private password = "";
35+
private sessionId = "";
36+
private logoutDevices = false;
37+
private sendAttempt = 0;
3538

3639
/**
3740
* Configure the endpoints for password resetting.
@@ -54,14 +57,40 @@ export default class PasswordReset {
5457
* @param {boolean} logoutDevices Should all devices be signed out after the reset? Defaults to `true`.
5558
* @return {Promise} Resolves when the email has been sent. Then call checkEmailLinkClicked().
5659
*/
57-
public resetPassword(
60+
public async resetPassword(
5861
emailAddress: string,
5962
newPassword: string,
6063
logoutDevices = true,
6164
): Promise<IRequestTokenResponse> {
6265
this.password = newPassword;
6366
this.logoutDevices = logoutDevices;
64-
return this.client.requestPasswordEmailToken(emailAddress, this.clientSecret, 1).then((res) => {
67+
this.sendAttempt++;
68+
69+
try {
70+
const result = await this.client.requestPasswordEmailToken(
71+
emailAddress,
72+
this.clientSecret,
73+
this.sendAttempt,
74+
);
75+
this.sessionId = result.sid;
76+
return result;
77+
} catch (err: any) {
78+
if (err.errcode === 'M_THREEPID_NOT_FOUND') {
79+
err.message = _t('This email address was not found');
80+
} else if (err.httpStatus) {
81+
err.message = err.message + ` (Status ${err.httpStatus})`;
82+
}
83+
throw err;
84+
}
85+
}
86+
87+
/**
88+
* Request a password reset token.
89+
* This will trigger a side-effect of sending an email to the provided email address.
90+
*/
91+
public requestResetToken(emailAddress: string): Promise<IRequestTokenResponse> {
92+
this.sendAttempt++;
93+
return this.client.requestPasswordEmailToken(emailAddress, this.clientSecret, this.sendAttempt).then((res) => {
6594
this.sessionId = res.sid;
6695
return res;
6796
}, function(err) {
@@ -74,6 +103,29 @@ export default class PasswordReset {
74103
});
75104
}
76105

106+
public async setNewPassword(password: string): Promise<void> {
107+
this.password = password;
108+
await this.checkEmailLinkClicked();
109+
}
110+
111+
public async retrySetNewPassword(password: string): Promise<void> {
112+
this.password = password;
113+
return new Promise((resolve) => {
114+
this.tryCheckEmailLinkClicked(resolve);
115+
});
116+
}
117+
118+
private tryCheckEmailLinkClicked(resolve: Function): void {
119+
this.checkEmailLinkClicked()
120+
.then(() => resolve())
121+
.catch(() => {
122+
setTimeout(
123+
() => this.tryCheckEmailLinkClicked(resolve),
124+
CHECK_EMAIL_VERIFIED_POLL_INTERVAL,
125+
);
126+
});
127+
}
128+
77129
/**
78130
* Checks if the email link has been clicked by attempting to change the password
79131
* for the mxid linked to the email.
@@ -98,7 +150,7 @@ export default class PasswordReset {
98150
threepid_creds: creds,
99151
threepidCreds: creds,
100152
}, this.password, this.logoutDevices);
101-
} catch (err) {
153+
} catch (err: any) {
102154
if (err.httpStatus === 401) {
103155
err.message = _t('Failed to verify email address: make sure you clicked the link in the email');
104156
} else if (err.httpStatus === 404) {

0 commit comments

Comments
 (0)