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

Commit 180fcaa

Browse files
turt2livet3chguy
andauthored
Support Matrix 1.1 (drop legacy r0 versions) (#9819)
Co-authored-by: Michael Telatynski <[email protected]>
1 parent f9e79fd commit 180fcaa

32 files changed

+709
-437
lines changed

cypress/e2e/read-receipts/read-receipts.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ describe("Read receipts", () => {
288288
cy.intercept({
289289
method: "POST",
290290
url: new RegExp(
291-
`http://localhost:\\d+/_matrix/client/r0/rooms/${uriEncodedOtherRoomId}/receipt/m\\.read/.+`,
291+
`http://localhost:\\d+/_matrix/client/v3/rooms/${uriEncodedOtherRoomId}/receipt/m\\.read/.+`,
292292
),
293293
}).as("receiptRequest");
294294

@@ -321,7 +321,7 @@ describe("Read receipts", () => {
321321

322322
cy.intercept({
323323
method: "POST",
324-
url: new RegExp(`http://localhost:\\d+/_matrix/client/r0/rooms/${uriEncodedOtherRoomId}/read_markers`),
324+
url: new RegExp(`http://localhost:\\d+/_matrix/client/v3/rooms/${uriEncodedOtherRoomId}/read_markers`),
325325
}).as("readMarkersRequest");
326326

327327
cy.findByRole("button", { name: "Jump to first unread message." }).click();
@@ -341,7 +341,7 @@ describe("Read receipts", () => {
341341

342342
cy.intercept({
343343
method: "POST",
344-
url: new RegExp(`http://localhost:\\d+/_matrix/client/r0/rooms/${uriEncodedOtherRoomId}/read_markers`),
344+
url: new RegExp(`http://localhost:\\d+/_matrix/client/v3/rooms/${uriEncodedOtherRoomId}/read_markers`),
345345
}).as("readMarkersRequest");
346346

347347
cy.findByRole("button", { name: "Scroll to most recent messages" }).click();

cypress/e2e/timeline/timeline.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -704,14 +704,14 @@ describe("Timeline", () => {
704704
});
705705

706706
it("should render url previews", () => {
707-
cy.intercept("**/_matrix/media/r0/thumbnail/matrix.org/2022-08-16_yaiSVSRIsNFfxDnV?*", {
707+
cy.intercept("**/_matrix/media/v3/thumbnail/matrix.org/2022-08-16_yaiSVSRIsNFfxDnV?*", {
708708
statusCode: 200,
709709
fixture: "riot.png",
710710
headers: {
711711
"Content-Type": "image/png",
712712
},
713713
}).as("mxc");
714-
cy.intercept("**/_matrix/media/r0/preview_url?url=https%3A%2F%2Fcall.element.io%2F&ts=*", {
714+
cy.intercept("**/_matrix/media/v3/preview_url?url=https%3A%2F%2Fcall.element.io%2F&ts=*", {
715715
statusCode: 200,
716716
body: {
717717
"og:title": "Element Call",

cypress/support/login.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ declare global {
6262
Cypress.Commands.add(
6363
"loginUser",
6464
(homeserver: HomeserverInstance, username: string, password: string): Chainable<UserCredentials> => {
65-
const url = `${homeserver.baseUrl}/_matrix/client/r0/login`;
65+
const url = `${homeserver.baseUrl}/_matrix/client/v3/login`;
6666
return cy
6767
.request<{
6868
access_token: string;

src/AddThreepid.ts

Lines changed: 131 additions & 166 deletions
Large diffs are not rendered by default.

src/Lifecycle.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { decryptAES, encryptAES, IEncryptedPayload } from "matrix-js-sdk/src/cry
2424
import { QueryDict } from "matrix-js-sdk/src/utils";
2525
import { logger } from "matrix-js-sdk/src/logger";
2626
import { SSOAction } from "matrix-js-sdk/src/@types/auth";
27+
import { MINIMUM_MATRIX_VERSION } from "matrix-js-sdk/src/version-support";
2728

2829
import { IMatrixClientCreds, MatrixClientPeg } from "./MatrixClientPeg";
2930
import SecurityCustomisations from "./customisations/Security";
@@ -66,6 +67,7 @@ import { SdkContextClass } from "./contexts/SDKContext";
6667
import { messageForLoginError } from "./utils/ErrorUtils";
6768
import { completeOidcLogin } from "./utils/oidc/authorize";
6869
import { persistOidcAuthenticatedSettings } from "./utils/oidc/persistOidcSettings";
70+
import GenericToast from "./components/views/toasts/GenericToast";
6971

7072
const HOMESERVER_URL_KEY = "mx_hs_url";
7173
const ID_SERVER_URL_KEY = "mx_is_url";
@@ -584,13 +586,43 @@ export async function restoreFromLocalStorage(opts?: { ignoreGuest?: boolean }):
584586
},
585587
false,
586588
);
589+
checkServerVersions();
587590
return true;
588591
} else {
589592
logger.log("No previous session found.");
590593
return false;
591594
}
592595
}
593596

597+
async function checkServerVersions(): Promise<void> {
598+
MatrixClientPeg.get()
599+
?.getVersions()
600+
.then((response) => {
601+
if (!response.versions.includes(MINIMUM_MATRIX_VERSION)) {
602+
const toastKey = "LEGACY_SERVER";
603+
ToastStore.sharedInstance().addOrReplaceToast({
604+
key: toastKey,
605+
title: _t("Your server is unsupported"),
606+
props: {
607+
description: _t(
608+
"This server is using an older version of Matrix. Upgrade to Matrix %(version)s to use %(brand)s without errors.",
609+
{
610+
version: MINIMUM_MATRIX_VERSION,
611+
brand: SdkConfig.get().brand,
612+
},
613+
),
614+
acceptLabel: _t("OK"),
615+
onAccept: () => {
616+
ToastStore.sharedInstance().dismissToast(toastKey);
617+
},
618+
},
619+
component: GenericToast,
620+
priority: 98,
621+
});
622+
}
623+
});
624+
}
625+
594626
async function handleLoadSessionFailure(e: unknown): Promise<boolean> {
595627
logger.error("Unable to load session", e);
596628

src/components/structures/auth/ForgotPassword.tsx

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ limitations under the License.
1818

1919
import React, { ReactNode } from "react";
2020
import { logger } from "matrix-js-sdk/src/logger";
21-
import { createClient } from "matrix-js-sdk/src/matrix";
2221
import { sleep } from "matrix-js-sdk/src/utils";
2322

2423
import { _t, _td } from "../../../languageHandler";
@@ -81,7 +80,6 @@ interface State {
8180
serverIsAlive: boolean;
8281
serverDeadError: string;
8382

84-
serverSupportsControlOfDevicesLogout: boolean;
8583
logoutDevices: boolean;
8684
}
8785

@@ -104,26 +102,18 @@ export default class ForgotPassword extends React.Component<Props, State> {
104102
// be seeing.
105103
serverIsAlive: true,
106104
serverDeadError: "",
107-
serverSupportsControlOfDevicesLogout: false,
108105
logoutDevices: false,
109106
};
110107
this.reset = new PasswordReset(this.props.serverConfig.hsUrl, this.props.serverConfig.isUrl);
111108
}
112109

113-
public componentDidMount(): void {
114-
this.checkServerCapabilities(this.props.serverConfig);
115-
}
116-
117110
public componentDidUpdate(prevProps: Readonly<Props>): void {
118111
if (
119112
prevProps.serverConfig.hsUrl !== this.props.serverConfig.hsUrl ||
120113
prevProps.serverConfig.isUrl !== this.props.serverConfig.isUrl
121114
) {
122115
// Do a liveliness check on the new URLs
123116
this.checkServerLiveliness(this.props.serverConfig);
124-
125-
// Do capabilities check on new URLs
126-
this.checkServerCapabilities(this.props.serverConfig);
127117
}
128118
}
129119

@@ -146,19 +136,6 @@ export default class ForgotPassword extends React.Component<Props, State> {
146136
}
147137
}
148138

149-
private async checkServerCapabilities(serverConfig: ValidatedServerConfig): Promise<void> {
150-
const tempClient = createClient({
151-
baseUrl: serverConfig.hsUrl,
152-
});
153-
154-
const serverSupportsControlOfDevicesLogout = await tempClient.doesServerSupportLogoutDevices();
155-
156-
this.setState({
157-
logoutDevices: !serverSupportsControlOfDevicesLogout,
158-
serverSupportsControlOfDevicesLogout,
159-
});
160-
}
161-
162139
private async onPhaseEmailInputSubmit(): Promise<void> {
163140
this.phase = Phase.SendingEmail;
164141

@@ -376,16 +353,10 @@ export default class ForgotPassword extends React.Component<Props, State> {
376353
description: (
377354
<div>
378355
<p>
379-
{!this.state.serverSupportsControlOfDevicesLogout
380-
? _t(
381-
"Resetting your password on this homeserver will cause all of your devices to be " +
382-
"signed out. This will delete the message encryption keys stored on them, " +
383-
"making encrypted chat history unreadable.",
384-
)
385-
: _t(
386-
"Signing out your devices will delete the message encryption keys stored on them, " +
387-
"making encrypted chat history unreadable.",
388-
)}
356+
{_t(
357+
"Signing out your devices will delete the message encryption keys stored on them, " +
358+
"making encrypted chat history unreadable.",
359+
)}
389360
</p>
390361
<p>
391362
{_t(
@@ -446,16 +417,14 @@ export default class ForgotPassword extends React.Component<Props, State> {
446417
autoComplete="new-password"
447418
/>
448419
</div>
449-
{this.state.serverSupportsControlOfDevicesLogout ? (
450-
<div className="mx_AuthBody_fieldRow">
451-
<StyledCheckbox
452-
onChange={() => this.setState({ logoutDevices: !this.state.logoutDevices })}
453-
checked={this.state.logoutDevices}
454-
>
455-
{_t("Sign out of all devices")}
456-
</StyledCheckbox>
457-
</div>
458-
) : null}
420+
<div className="mx_AuthBody_fieldRow">
421+
<StyledCheckbox
422+
onChange={() => this.setState({ logoutDevices: !this.state.logoutDevices })}
423+
checked={this.state.logoutDevices}
424+
>
425+
{_t("Sign out of all devices")}
426+
</StyledCheckbox>
427+
</div>
459428
{this.state.errorText && <ErrorMessage message={this.state.errorText} />}
460429
<button type="submit" className="mx_Login_submit">
461430
{submitButtonChild}

src/components/views/settings/ChangePassword.tsx

Lines changed: 5 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ limitations under the License.
1818
import React from "react";
1919
import { MatrixClient } from "matrix-js-sdk/src/matrix";
2020

21-
import type ExportE2eKeysDialog from "../../../async-components/views/dialogs/security/ExportE2eKeysDialog";
2221
import Field from "../elements/Field";
2322
import { MatrixClientPeg } from "../../../MatrixClientPeg";
2423
import AccessibleButton from "../elements/AccessibleButton";
@@ -29,7 +28,6 @@ import Modal from "../../../Modal";
2928
import PassphraseField from "../auth/PassphraseField";
3029
import { PASSWORD_MIN_SCORE } from "../auth/RegistrationForm";
3130
import SetEmailDialog from "../dialogs/SetEmailDialog";
32-
import QuestionDialog from "../dialogs/QuestionDialog";
3331

3432
const FIELD_OLD_PASSWORD = "field_old_password";
3533
const FIELD_NEW_PASSWORD = "field_new_password";
@@ -43,11 +41,7 @@ enum Phase {
4341
}
4442

4543
interface IProps {
46-
onFinished: (outcome: {
47-
didSetEmail?: boolean;
48-
/** Was one or more other devices logged out whilst changing the password */
49-
didLogoutOutOtherDevices: boolean;
50-
}) => void;
44+
onFinished: (outcome: { didSetEmail?: boolean }) => void;
5145
onError: (error: Error) => void;
5246
rowClassName?: string;
5347
buttonClassName?: string;
@@ -95,58 +89,10 @@ export default class ChangePassword extends React.Component<IProps, IState> {
9589
private async onChangePassword(oldPassword: string, newPassword: string): Promise<void> {
9690
const cli = MatrixClientPeg.safeGet();
9791

98-
// if the server supports it then don't sign user out of all devices
99-
const serverSupportsControlOfDevicesLogout = await cli.doesServerSupportLogoutDevices();
100-
const userHasOtherDevices = (await cli.getDevices()).devices.length > 1;
101-
102-
if (userHasOtherDevices && !serverSupportsControlOfDevicesLogout && this.props.confirm) {
103-
// warn about logging out all devices
104-
const { finished } = Modal.createDialog(QuestionDialog, {
105-
title: _t("Warning!"),
106-
description: (
107-
<div>
108-
<p>
109-
{_t(
110-
"Changing your password on this homeserver will cause all of your other devices to be " +
111-
"signed out. This will delete the message encryption keys stored on them, and may make " +
112-
"encrypted chat history unreadable.",
113-
)}
114-
</p>
115-
<p>
116-
{_t(
117-
"If you want to retain access to your chat history in encrypted rooms you should first " +
118-
"export your room keys and re-import them afterwards.",
119-
)}
120-
</p>
121-
<p>
122-
{_t(
123-
"You can also ask your homeserver admin to upgrade the server to change this behaviour.",
124-
)}
125-
</p>
126-
</div>
127-
),
128-
button: _t("Continue"),
129-
extraButtons: [
130-
<button key="exportRoomKeys" className="mx_Dialog_primary" onClick={this.onExportE2eKeysClicked}>
131-
{_t("Export E2E room keys")}
132-
</button>,
133-
],
134-
});
135-
136-
const [confirmed] = await finished;
137-
if (!confirmed) return;
138-
}
139-
140-
this.changePassword(cli, oldPassword, newPassword, serverSupportsControlOfDevicesLogout, userHasOtherDevices);
92+
this.changePassword(cli, oldPassword, newPassword);
14193
}
14294

143-
private changePassword(
144-
cli: MatrixClient,
145-
oldPassword: string,
146-
newPassword: string,
147-
serverSupportsControlOfDevicesLogout: boolean,
148-
userHasOtherDevices: boolean,
149-
): void {
95+
private changePassword(cli: MatrixClient, oldPassword: string, newPassword: string): void {
15096
const authDict = {
15197
type: "m.login.password",
15298
identifier: {
@@ -163,23 +109,17 @@ export default class ChangePassword extends React.Component<IProps, IState> {
163109
phase: Phase.Uploading,
164110
});
165111

166-
const logoutDevices = serverSupportsControlOfDevicesLogout ? false : undefined;
167-
168-
// undefined or true mean all devices signed out
169-
const didLogoutOutOtherDevices = !serverSupportsControlOfDevicesLogout && userHasOtherDevices;
170-
171-
cli.setPassword(authDict, newPassword, logoutDevices)
112+
cli.setPassword(authDict, newPassword, false)
172113
.then(
173114
() => {
174115
if (this.props.shouldAskForEmail) {
175116
return this.optionallySetEmail().then((confirmed) => {
176117
this.props.onFinished({
177118
didSetEmail: confirmed,
178-
didLogoutOutOtherDevices,
179119
});
180120
});
181121
} else {
182-
this.props.onFinished({ didLogoutOutOtherDevices });
122+
this.props.onFinished({});
183123
}
184124
},
185125
(err) => {
@@ -229,17 +169,6 @@ export default class ChangePassword extends React.Component<IProps, IState> {
229169
return modal.finished.then(([confirmed]) => !!confirmed);
230170
}
231171

232-
private onExportE2eKeysClicked = (): void => {
233-
Modal.createDialogAsync(
234-
import("../../../async-components/views/dialogs/security/ExportE2eKeysDialog") as unknown as Promise<
235-
typeof ExportE2eKeysDialog
236-
>,
237-
{
238-
matrixClient: MatrixClientPeg.safeGet(),
239-
},
240-
);
241-
};
242-
243172
private markFieldValid(fieldID: FieldType, valid?: boolean): void {
244173
const { fieldValid } = this.state;
245174
fieldValid[fieldID] = valid;

src/components/views/settings/account/PhoneNumbers.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ export default class PhoneNumbers extends React.Component<IProps, IState> {
210210
?.haveMsisdnToken(token)
211211
.then(([finished] = []) => {
212212
let newPhoneNumber = this.state.newPhoneNumber;
213-
if (finished) {
213+
if (finished !== false) {
214214
const msisdns = [...this.props.msisdns, { address, medium: ThreepidMedium.Phone }];
215215
this.props.onMsisdnsChange(msisdns);
216216
newPhoneNumber = "";

0 commit comments

Comments
 (0)