2016-01-12 17:20:16 +00:00
|
|
|
/*
|
2024-09-09 13:57:16 +00:00
|
|
|
Copyright 2024 New Vector Ltd.
|
|
|
|
Copyright 2019-2022 The Matrix.org Foundation C.I.C.
|
2016-01-12 17:20:16 +00:00
|
|
|
Copyright 2015, 2016 OpenMarket Ltd
|
|
|
|
|
2024-09-09 13:57:16 +00:00
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
|
|
|
Please see LICENSE files in the repository root for full details.
|
2016-01-12 17:20:16 +00:00
|
|
|
*/
|
|
|
|
|
2021-08-19 06:59:27 +00:00
|
|
|
import { createClient, IRequestTokenResponse, MatrixClient } from "matrix-js-sdk/src/matrix";
|
2021-10-22 22:23:32 +00:00
|
|
|
|
2017-05-25 10:39:08 +00:00
|
|
|
import { _t } from "./languageHandler";
|
2016-01-12 17:20:16 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Allows a user to reset their password on a homeserver.
|
|
|
|
*
|
|
|
|
* This involves getting an email token from the identity server to "prove" that
|
|
|
|
* the client owns the given email address, which is then passed to the password
|
|
|
|
* API on the homeserver in question with the new password.
|
|
|
|
*/
|
2019-12-20 00:45:24 +00:00
|
|
|
export default class PasswordReset {
|
2021-08-19 06:59:27 +00:00
|
|
|
private client: MatrixClient;
|
|
|
|
private clientSecret: string;
|
2022-11-22 06:58:37 +00:00
|
|
|
private password = "";
|
|
|
|
private sessionId = "";
|
|
|
|
private logoutDevices = false;
|
|
|
|
private sendAttempt = 0;
|
2021-08-19 06:59:27 +00:00
|
|
|
|
2016-01-12 17:20:16 +00:00
|
|
|
/**
|
|
|
|
* Configure the endpoints for password resetting.
|
|
|
|
* @param {string} homeserverUrl The URL to the HS which has the account to reset.
|
|
|
|
* @param {string} identityUrl The URL to the IS which has linked the email -> mxid mapping.
|
|
|
|
*/
|
2022-12-16 12:29:59 +00:00
|
|
|
public constructor(homeserverUrl: string, identityUrl: string) {
|
2021-03-19 02:50:34 +00:00
|
|
|
this.client = createClient({
|
2016-01-12 17:20:16 +00:00
|
|
|
baseUrl: homeserverUrl,
|
2017-07-01 13:31:59 +00:00
|
|
|
idBaseUrl: identityUrl,
|
2016-01-12 17:20:16 +00:00
|
|
|
});
|
2016-01-18 17:50:27 +00:00
|
|
|
this.clientSecret = this.client.generateClientSecret();
|
2019-08-16 17:11:24 +00:00
|
|
|
}
|
|
|
|
|
2022-11-22 06:58:37 +00:00
|
|
|
/**
|
|
|
|
* Request a password reset token.
|
|
|
|
* This will trigger a side-effect of sending an email to the provided email address.
|
|
|
|
*/
|
|
|
|
public requestResetToken(emailAddress: string): Promise<IRequestTokenResponse> {
|
|
|
|
this.sendAttempt++;
|
|
|
|
return this.client.requestPasswordEmailToken(emailAddress, this.clientSecret, this.sendAttempt).then(
|
|
|
|
(res) => {
|
2016-01-12 17:20:16 +00:00
|
|
|
this.sessionId = res.sid;
|
|
|
|
return res;
|
|
|
|
},
|
|
|
|
function (err) {
|
2017-07-01 13:31:59 +00:00
|
|
|
if (err.errcode === "M_THREEPID_NOT_FOUND") {
|
2023-09-22 15:39:40 +00:00
|
|
|
err.message = _t("auth|reset_password_email_not_found_title");
|
2016-07-08 17:06:50 +00:00
|
|
|
} else if (err.httpStatus) {
|
2016-01-12 17:20:16 +00:00
|
|
|
err.message = err.message + ` (Status ${err.httpStatus})`;
|
|
|
|
}
|
|
|
|
throw err;
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-01-18 07:25:03 +00:00
|
|
|
public setLogoutDevices(logoutDevices: boolean): void {
|
|
|
|
this.logoutDevices = logoutDevices;
|
|
|
|
}
|
|
|
|
|
2022-11-22 06:58:37 +00:00
|
|
|
public async setNewPassword(password: string): Promise<void> {
|
|
|
|
this.password = password;
|
|
|
|
await this.checkEmailLinkClicked();
|
|
|
|
}
|
|
|
|
|
2016-01-12 17:20:16 +00:00
|
|
|
/**
|
|
|
|
* Checks if the email link has been clicked by attempting to change the password
|
|
|
|
* for the mxid linked to the email.
|
|
|
|
* @return {Promise} Resolves if the password was reset. Rejects with an object
|
|
|
|
* with a "message" property which contains a human-readable message detailing why
|
|
|
|
* the reset failed, e.g. "There is no mapped matrix user ID for the given email address".
|
|
|
|
*/
|
2021-08-19 07:47:26 +00:00
|
|
|
public async checkEmailLinkClicked(): Promise<void> {
|
2019-09-24 13:47:08 +00:00
|
|
|
const creds = {
|
|
|
|
sid: this.sessionId,
|
|
|
|
client_secret: this.clientSecret,
|
|
|
|
};
|
|
|
|
|
|
|
|
try {
|
|
|
|
await this.client.setPassword(
|
|
|
|
{
|
2020-05-29 14:23:59 +00:00
|
|
|
// Note: Though this sounds like a login type for identity servers only, it
|
|
|
|
// has a dual purpose of being used for homeservers too.
|
2019-09-24 13:47:08 +00:00
|
|
|
type: "m.login.email.identity",
|
|
|
|
threepid_creds: creds,
|
2022-04-22 17:15:38 +00:00
|
|
|
},
|
|
|
|
this.password,
|
|
|
|
this.logoutDevices,
|
|
|
|
);
|
2022-11-22 06:58:37 +00:00
|
|
|
} catch (err: any) {
|
2016-01-12 17:20:16 +00:00
|
|
|
if (err.httpStatus === 401) {
|
2023-09-22 15:39:40 +00:00
|
|
|
err.message = _t("settings|general|add_email_failed_verification");
|
2017-07-01 13:31:59 +00:00
|
|
|
} else if (err.httpStatus === 404) {
|
2023-09-22 15:39:40 +00:00
|
|
|
err.message = _t("auth|reset_password_email_not_associated");
|
2017-07-01 13:31:59 +00:00
|
|
|
} else if (err.httpStatus) {
|
2016-01-12 17:20:16 +00:00
|
|
|
err.message += ` (Status ${err.httpStatus})`;
|
|
|
|
}
|
|
|
|
throw err;
|
2019-09-24 13:47:08 +00:00
|
|
|
}
|
2016-01-12 17:20:16 +00:00
|
|
|
}
|
|
|
|
}
|