Properly translate errors in AddThreepid.ts
(#10432)
* Properly translate errors in AddThreepid.ts Part of https://github.com/vector-im/element-web/issues/9597 * Use translated message * Avoid returning undefined ever * More usage * Introduce UserFriendlyError * Use UserFriendlyError * Add more usage instead of normal error * Use types and translatedMessage * Fix lints * Update i18n although it's wrong * Use unknown for easier creation from try/catch * Use types * Use error types * Use types * Update i18n strings * Remove generic re-label of HTTPError See https://github.com/matrix-org/matrix-react-sdk/pull/10432#discussion_r1156468143 The HTTPError already has a good label and it isn't even translated if we re-label it here in this way generically Probably best to just remove in favor of thinking about a translations in general from the `matrix-js-sdk`, see https://github.com/matrix-org/matrix-js-sdk/issues/1309 * Make error message extraction generic * Update i18n strings * Add tests for email addresses * More consistent error logging to actually see error in logs * Consistent error handling * Any is okay because we have a fallback * Check error type * Use dedicated mockResolvedValue function See https://github.com/matrix-org/matrix-react-sdk/pull/10432#discussion_r1163344034
This commit is contained in:
parent
8f8b74b32c
commit
c1e7905ddc
9 changed files with 300 additions and 132 deletions
|
@ -17,20 +17,21 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import { IAuthData, IRequestMsisdnTokenResponse, IRequestTokenResponse } from "matrix-js-sdk/src/matrix";
|
||||
import { MatrixError, HTTPError } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||
import Modal from "./Modal";
|
||||
import { _t } from "./languageHandler";
|
||||
import { _t, UserFriendlyError } from "./languageHandler";
|
||||
import IdentityAuthClient from "./IdentityAuthClient";
|
||||
import { SSOAuthEntry } from "./components/views/auth/InteractiveAuthEntryComponents";
|
||||
import InteractiveAuthDialog from "./components/views/dialogs/InteractiveAuthDialog";
|
||||
|
||||
function getIdServerDomain(): string {
|
||||
const idBaseUrl = MatrixClientPeg.get().idBaseUrl;
|
||||
const idBaseUrl = MatrixClientPeg.get().getIdentityServerUrl(true);
|
||||
if (!idBaseUrl) {
|
||||
throw new Error("Identity server not set");
|
||||
throw new UserFriendlyError("Identity server not set");
|
||||
}
|
||||
return idBaseUrl.split("://")[1];
|
||||
return idBaseUrl;
|
||||
}
|
||||
|
||||
export type Binding = {
|
||||
|
@ -67,23 +68,18 @@ export default class AddThreepid {
|
|||
* @param {string} emailAddress The email address to add
|
||||
* @return {Promise} Resolves when the email has been sent. Then call checkEmailLinkClicked().
|
||||
*/
|
||||
public addEmailAddress(emailAddress: string): Promise<IRequestTokenResponse> {
|
||||
return MatrixClientPeg.get()
|
||||
.requestAdd3pidEmailToken(emailAddress, this.clientSecret, 1)
|
||||
.then(
|
||||
(res) => {
|
||||
this.sessionId = res.sid;
|
||||
return res;
|
||||
},
|
||||
function (err) {
|
||||
if (err.errcode === "M_THREEPID_IN_USE") {
|
||||
err.message = _t("This email address is already in use");
|
||||
} else if (err.httpStatus) {
|
||||
err.message = err.message + ` (Status ${err.httpStatus})`;
|
||||
}
|
||||
throw err;
|
||||
},
|
||||
);
|
||||
public async addEmailAddress(emailAddress: string): Promise<IRequestTokenResponse> {
|
||||
try {
|
||||
const res = await MatrixClientPeg.get().requestAdd3pidEmailToken(emailAddress, this.clientSecret, 1);
|
||||
this.sessionId = res.sid;
|
||||
return res;
|
||||
} catch (err) {
|
||||
if (err instanceof MatrixError && err.errcode === "M_THREEPID_IN_USE") {
|
||||
throw new UserFriendlyError("This email address is already in use", { cause: err });
|
||||
}
|
||||
// Otherwise, just blurt out the same error
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,22 +94,23 @@ export default class AddThreepid {
|
|||
// For separate bind, request a token directly from the IS.
|
||||
const authClient = new IdentityAuthClient();
|
||||
const identityAccessToken = (await authClient.getAccessToken()) ?? undefined;
|
||||
return MatrixClientPeg.get()
|
||||
.requestEmailToken(emailAddress, this.clientSecret, 1, undefined, identityAccessToken)
|
||||
.then(
|
||||
(res) => {
|
||||
this.sessionId = res.sid;
|
||||
return res;
|
||||
},
|
||||
function (err) {
|
||||
if (err.errcode === "M_THREEPID_IN_USE") {
|
||||
err.message = _t("This email address is already in use");
|
||||
} else if (err.httpStatus) {
|
||||
err.message = err.message + ` (Status ${err.httpStatus})`;
|
||||
}
|
||||
throw err;
|
||||
},
|
||||
try {
|
||||
const res = await MatrixClientPeg.get().requestEmailToken(
|
||||
emailAddress,
|
||||
this.clientSecret,
|
||||
1,
|
||||
undefined,
|
||||
identityAccessToken,
|
||||
);
|
||||
this.sessionId = res.sid;
|
||||
return res;
|
||||
} catch (err) {
|
||||
if (err instanceof MatrixError && err.errcode === "M_THREEPID_IN_USE") {
|
||||
throw new UserFriendlyError("This email address is already in use", { cause: err });
|
||||
}
|
||||
// Otherwise, just blurt out the same error
|
||||
throw err;
|
||||
}
|
||||
} else {
|
||||
// For tangled bind, request a token via the HS.
|
||||
return this.addEmailAddress(emailAddress);
|
||||
|
@ -127,24 +124,24 @@ export default class AddThreepid {
|
|||
* @param {string} phoneNumber The national or international formatted phone number to add
|
||||
* @return {Promise} Resolves when the text message has been sent. Then call haveMsisdnToken().
|
||||
*/
|
||||
public addMsisdn(phoneCountry: string, phoneNumber: string): Promise<IRequestMsisdnTokenResponse> {
|
||||
return MatrixClientPeg.get()
|
||||
.requestAdd3pidMsisdnToken(phoneCountry, phoneNumber, this.clientSecret, 1)
|
||||
.then(
|
||||
(res) => {
|
||||
this.sessionId = res.sid;
|
||||
this.submitUrl = res.submit_url;
|
||||
return res;
|
||||
},
|
||||
function (err) {
|
||||
if (err.errcode === "M_THREEPID_IN_USE") {
|
||||
err.message = _t("This phone number is already in use");
|
||||
} else if (err.httpStatus) {
|
||||
err.message = err.message + ` (Status ${err.httpStatus})`;
|
||||
}
|
||||
throw err;
|
||||
},
|
||||
public async addMsisdn(phoneCountry: string, phoneNumber: string): Promise<IRequestMsisdnTokenResponse> {
|
||||
try {
|
||||
const res = await MatrixClientPeg.get().requestAdd3pidMsisdnToken(
|
||||
phoneCountry,
|
||||
phoneNumber,
|
||||
this.clientSecret,
|
||||
1,
|
||||
);
|
||||
this.sessionId = res.sid;
|
||||
this.submitUrl = res.submit_url;
|
||||
return res;
|
||||
} catch (err) {
|
||||
if (err instanceof MatrixError && err.errcode === "M_THREEPID_IN_USE") {
|
||||
throw new UserFriendlyError("This phone number is already in use", { cause: err });
|
||||
}
|
||||
// Otherwise, just blurt out the same error
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,22 +157,24 @@ export default class AddThreepid {
|
|||
// For separate bind, request a token directly from the IS.
|
||||
const authClient = new IdentityAuthClient();
|
||||
const identityAccessToken = (await authClient.getAccessToken()) ?? undefined;
|
||||
return MatrixClientPeg.get()
|
||||
.requestMsisdnToken(phoneCountry, phoneNumber, this.clientSecret, 1, undefined, identityAccessToken)
|
||||
.then(
|
||||
(res) => {
|
||||
this.sessionId = res.sid;
|
||||
return res;
|
||||
},
|
||||
function (err) {
|
||||
if (err.errcode === "M_THREEPID_IN_USE") {
|
||||
err.message = _t("This phone number is already in use");
|
||||
} else if (err.httpStatus) {
|
||||
err.message = err.message + ` (Status ${err.httpStatus})`;
|
||||
}
|
||||
throw err;
|
||||
},
|
||||
try {
|
||||
const res = await MatrixClientPeg.get().requestMsisdnToken(
|
||||
phoneCountry,
|
||||
phoneNumber,
|
||||
this.clientSecret,
|
||||
1,
|
||||
undefined,
|
||||
identityAccessToken,
|
||||
);
|
||||
this.sessionId = res.sid;
|
||||
return res;
|
||||
} catch (err) {
|
||||
if (err instanceof MatrixError && err.errcode === "M_THREEPID_IN_USE") {
|
||||
throw new UserFriendlyError("This phone number is already in use", { cause: err });
|
||||
}
|
||||
// Otherwise, just blurt out the same error
|
||||
throw err;
|
||||
}
|
||||
} else {
|
||||
// For tangled bind, request a token via the HS.
|
||||
return this.addMsisdn(phoneCountry, phoneNumber);
|
||||
|
@ -195,7 +194,7 @@ export default class AddThreepid {
|
|||
const authClient = new IdentityAuthClient();
|
||||
const identityAccessToken = await authClient.getAccessToken();
|
||||
if (!identityAccessToken) {
|
||||
throw new Error("No identity access token found");
|
||||
throw new UserFriendlyError("No identity access token found");
|
||||
}
|
||||
await MatrixClientPeg.get().bindThreePid({
|
||||
sid: this.sessionId,
|
||||
|
@ -210,10 +209,10 @@ export default class AddThreepid {
|
|||
// The spec has always required this to use UI auth but synapse briefly
|
||||
// implemented it without, so this may just succeed and that's OK.
|
||||
return [true];
|
||||
} catch (e) {
|
||||
if (e.httpStatus !== 401 || !e.data || !e.data.flows) {
|
||||
} catch (err) {
|
||||
if (!(err instanceof MatrixError) || err.httpStatus !== 401 || !err.data || !err.data.flows) {
|
||||
// doesn't look like an interactive-auth failure
|
||||
throw e;
|
||||
throw err;
|
||||
}
|
||||
|
||||
const dialogAesthetics = {
|
||||
|
@ -235,7 +234,7 @@ export default class AddThreepid {
|
|||
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||
title: _t("Add Email Address"),
|
||||
matrixClient: MatrixClientPeg.get(),
|
||||
authData: e.data,
|
||||
authData: err.data,
|
||||
makeRequest: this.makeAddThreepidOnlyRequest,
|
||||
aestheticsForStagePhases: {
|
||||
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
|
||||
|
@ -256,11 +255,13 @@ export default class AddThreepid {
|
|||
);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.httpStatus === 401) {
|
||||
err.message = _t("Failed to verify email address: make sure you clicked the link in the email");
|
||||
} else if (err.httpStatus) {
|
||||
err.message += ` (Status ${err.httpStatus})`;
|
||||
if (err instanceof HTTPError && err.httpStatus === 401) {
|
||||
throw new UserFriendlyError(
|
||||
"Failed to verify email address: make sure you clicked the link in the email",
|
||||
{ cause: err },
|
||||
);
|
||||
}
|
||||
// Otherwise, just blurt out the same error
|
||||
throw err;
|
||||
}
|
||||
return [];
|
||||
|
@ -308,7 +309,7 @@ export default class AddThreepid {
|
|||
await authClient.getAccessToken(),
|
||||
);
|
||||
} else {
|
||||
throw new Error("The add / bind with MSISDN flow is misconfigured");
|
||||
throw new UserFriendlyError("The add / bind with MSISDN flow is misconfigured");
|
||||
}
|
||||
if (result.errcode) {
|
||||
throw result;
|
||||
|
@ -329,10 +330,10 @@ export default class AddThreepid {
|
|||
// The spec has always required this to use UI auth but synapse briefly
|
||||
// implemented it without, so this may just succeed and that's OK.
|
||||
return;
|
||||
} catch (e) {
|
||||
if (e.httpStatus !== 401 || !e.data || !e.data.flows) {
|
||||
} catch (err) {
|
||||
if (!(err instanceof MatrixError) || err.httpStatus !== 401 || !err.data || !err.data.flows) {
|
||||
// doesn't look like an interactive-auth failure
|
||||
throw e;
|
||||
throw err;
|
||||
}
|
||||
|
||||
const dialogAesthetics = {
|
||||
|
@ -354,7 +355,7 @@ export default class AddThreepid {
|
|||
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
||||
title: _t("Add Phone Number"),
|
||||
matrixClient: MatrixClientPeg.get(),
|
||||
authData: e.data,
|
||||
authData: err.data,
|
||||
makeRequest: this.makeAddThreepidOnlyRequest,
|
||||
aestheticsForStagePhases: {
|
||||
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue