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

Commit 5c0e5eb

Browse files
hughnst3chguy
andauthored
Support for MSC3882 revision 1 (#10443)
Co-authored-by: Michael Telatynski <[email protected]>
1 parent 700af09 commit 5c0e5eb

File tree

8 files changed

+114
-9
lines changed

8 files changed

+114
-9
lines changed

src/components/views/settings/devices/LoginWithQRSection.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,21 @@ limitations under the License.
1515
*/
1616

1717
import React from "react";
18+
import {
19+
IMSC3882GetLoginTokenCapability,
20+
IServerVersions,
21+
UNSTABLE_MSC3882_CAPABILITY,
22+
} from "matrix-js-sdk/src/matrix";
1823

19-
import type { IServerVersions } from "matrix-js-sdk/src/matrix";
2024
import { _t } from "../../../../languageHandler";
2125
import AccessibleButton from "../../elements/AccessibleButton";
2226
import SettingsSubsection from "../shared/SettingsSubsection";
2327

2428
interface IProps {
2529
onShowQr: () => void;
2630
versions?: IServerVersions;
31+
// we can't use the capabilities type from the js-sdk because it isn't exported
32+
capabilities?: Record<string, any>;
2733
}
2834

2935
export default class LoginWithQRSection extends React.Component<IProps> {
@@ -33,7 +39,10 @@ export default class LoginWithQRSection extends React.Component<IProps> {
3339

3440
public render(): JSX.Element | null {
3541
// Needs server support for MSC3882 and MSC3886:
36-
const msc3882Supported = !!this.props.versions?.unstable_features?.["org.matrix.msc3882"];
42+
// in r0 of MSC3882 it is exposed as a feature flag, but in r1 it is a capability
43+
const capability = UNSTABLE_MSC3882_CAPABILITY.findIn<IMSC3882GetLoginTokenCapability>(this.props.capabilities);
44+
const msc3882Supported =
45+
!!this.props.versions?.unstable_features?.["org.matrix.msc3882"] || !!capability?.enabled;
3746
const msc3886Supported = !!this.props.versions?.unstable_features?.["org.matrix.msc3886"];
3847
const offerShowQr = msc3882Supported && msc3886Supported;
3948

src/components/views/settings/tabs/user/SecurityUserSettingsTab.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ interface IState {
8282
invitedRoomIds: Set<string>;
8383
showLoginWithQR: Mode | null;
8484
versions?: IServerVersions;
85+
// we can't use the capabilities type from the js-sdk because it isn't exported
86+
capabilities?: Record<string, any>;
8587
}
8688

8789
export default class SecurityUserSettingsTab extends React.Component<IProps, IState> {
@@ -116,6 +118,9 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
116118
MatrixClientPeg.get()
117119
.getVersions()
118120
.then((versions) => this.setState({ versions }));
121+
MatrixClientPeg.get()
122+
.getCapabilities()
123+
.then((capabilities) => this.setState({ capabilities }));
119124
}
120125

121126
public componentWillUnmount(): void {
@@ -393,7 +398,11 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
393398
</span>
394399
<DevicesPanel />
395400
</div>
396-
<LoginWithQRSection onShowQr={this.onShowQRClicked} versions={this.state.versions} />
401+
<LoginWithQRSection
402+
onShowQr={this.onShowQRClicked}
403+
versions={this.state.versions}
404+
capabilities={this.state.capabilities}
405+
/>
397406
</>
398407
);
399408

src/components/views/settings/tabs/user/SessionManagerTab.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ const SessionManagerTab: React.FC = () => {
132132
const userId = matrixClient?.getUserId();
133133
const currentUserMember = (userId && matrixClient?.getUser(userId)) || undefined;
134134
const clientVersions = useAsyncMemo(() => matrixClient.getVersions(), [matrixClient]);
135+
const capabilities = useAsyncMemo(async () => matrixClient?.getCapabilities(), [matrixClient]);
135136

136137
const onDeviceExpandToggle = (deviceId: ExtendedDevice["device_id"]): void => {
137138
if (expandedDeviceIds.includes(deviceId)) {
@@ -279,7 +280,7 @@ const SessionManagerTab: React.FC = () => {
279280
/>
280281
</SettingsSubsection>
281282
)}
282-
<LoginWithQRSection onShowQr={onShowQrClicked} versions={clientVersions} />
283+
<LoginWithQRSection onShowQr={onShowQrClicked} versions={clientVersions} capabilities={capabilities} />
283284
</SettingsTab>
284285
);
285286
};

test/components/views/settings/devices/LoginWithQR-test.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { cleanup, render, waitFor } from "@testing-library/react";
1818
import { mocked } from "jest-mock";
1919
import React from "react";
2020
import { MSC3906Rendezvous, RendezvousFailureReason } from "matrix-js-sdk/src/rendezvous";
21+
import { LoginTokenPostResponse } from "matrix-js-sdk/src/@types/auth";
2122

2223
import LoginWithQR, { Click, Mode, Phase } from "../../../../../src/components/views/auth/LoginWithQR";
2324
import type { MatrixClient } from "matrix-js-sdk/src/matrix";
@@ -87,8 +88,9 @@ describe("<LoginWithQR />", () => {
8788
jest.spyOn(MSC3906Rendezvous.prototype, "verifyNewDeviceOnExistingDevice").mockResolvedValue(undefined);
8889
client.requestLoginToken.mockResolvedValue({
8990
login_token: "token",
90-
expires_in: 1000,
91-
});
91+
expires_in: 1000, // this is as per MSC3882 r0
92+
expires_in_ms: 1000 * 1000, // this is as per MSC3882 r1
93+
} as LoginTokenPostResponse); // we force the type here so that it works with versions of js-sdk that don't have r1 support yet
9294
});
9395

9496
afterEach(() => {

test/components/views/settings/devices/LoginWithQRSection-test.tsx

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ limitations under the License.
1616

1717
import { render } from "@testing-library/react";
1818
import { mocked } from "jest-mock";
19-
import { IServerVersions, MatrixClient } from "matrix-js-sdk/src/matrix";
19+
import { IServerVersions, MatrixClient, UNSTABLE_MSC3882_CAPABILITY } from "matrix-js-sdk/src/matrix";
2020
import React from "react";
2121

2222
import LoginWithQRSection from "../../../../../src/components/views/settings/devices/LoginWithQRSection";
@@ -69,6 +69,23 @@ describe("<LoginWithQRSection />", () => {
6969
const { container } = render(getComponent({ versions: makeVersions({ "org.matrix.msc3882": true }) }));
7070
expect(container).toMatchSnapshot();
7171
});
72+
73+
it("only MSC3882 r1 enabled", async () => {
74+
const { container } = render(
75+
getComponent({ capabilities: { [UNSTABLE_MSC3882_CAPABILITY.name]: { enabled: true } } }),
76+
);
77+
expect(container).toMatchSnapshot();
78+
});
79+
80+
it("MSC3886 + MSC3882 r1 disabled", async () => {
81+
const { container } = render(
82+
getComponent({
83+
versions: makeVersions({ "org.matrix.msc3886": true }),
84+
capabilities: { [UNSTABLE_MSC3882_CAPABILITY.name]: { enabled: false } },
85+
}),
86+
);
87+
expect(container).toMatchSnapshot();
88+
});
7289
});
7390

7491
describe("should render panel", () => {
@@ -83,5 +100,19 @@ describe("<LoginWithQRSection />", () => {
83100
);
84101
expect(container).toMatchSnapshot();
85102
});
103+
104+
it("MSC3882 r1 + MSC3886", async () => {
105+
const { container } = render(
106+
getComponent({
107+
versions: makeVersions({
108+
"org.matrix.msc3886": true,
109+
}),
110+
capabilities: {
111+
[UNSTABLE_MSC3882_CAPABILITY.name]: { enabled: true },
112+
},
113+
}),
114+
);
115+
expect(container).toMatchSnapshot();
116+
});
86117
});
87118
});

test/components/views/settings/devices/__snapshots__/LoginWithQRSection-test.tsx.snap

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3+
exports[`<LoginWithQRSection /> should not render MSC3886 + MSC3882 r1 disabled 1`] = `<div />`;
4+
35
exports[`<LoginWithQRSection /> should not render no support at all 1`] = `<div />`;
46

57
exports[`<LoginWithQRSection /> should not render only MSC3882 enabled 1`] = `<div />`;
68

9+
exports[`<LoginWithQRSection /> should not render only MSC3882 r1 enabled 1`] = `<div />`;
10+
711
exports[`<LoginWithQRSection /> should render panel MSC3882 + MSC3886 1`] = `
812
<div>
913
<div
@@ -41,3 +45,41 @@ exports[`<LoginWithQRSection /> should render panel MSC3882 + MSC3886 1`] = `
4145
</div>
4246
</div>
4347
`;
48+
49+
exports[`<LoginWithQRSection /> should render panel MSC3882 r1 + MSC3886 1`] = `
50+
<div>
51+
<div
52+
class="mx_SettingsSubsection"
53+
>
54+
<div
55+
class="mx_SettingsSubsectionHeading"
56+
>
57+
<h3
58+
class="mx_Heading_h3 mx_SettingsSubsectionHeading_heading"
59+
>
60+
Sign in with QR code
61+
</h3>
62+
</div>
63+
<div
64+
class="mx_SettingsSubsection_content"
65+
>
66+
<div
67+
class="mx_LoginWithQRSection"
68+
>
69+
<p
70+
class="mx_SettingsTab_subsectionText"
71+
>
72+
You can use this device to sign in a new device with a QR code. You will need to scan the QR code shown on this device with your device that's signed out.
73+
</p>
74+
<div
75+
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
76+
role="button"
77+
tabindex="0"
78+
>
79+
Show QR code
80+
</div>
81+
</div>
82+
</div>
83+
</div>
84+
</div>
85+
`;

test/components/views/settings/tabs/user/SecurityUserSettingsTab-test.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616
import { fireEvent, render } from "@testing-library/react";
17+
import { UNSTABLE_MSC3882_CAPABILITY } from "matrix-js-sdk/src/matrix";
1718
import React from "react";
1819

1920
import SecurityUserSettingsTab from "../../../../../../src/components/views/settings/tabs/user/SecurityUserSettingsTab";
@@ -45,10 +46,14 @@ describe("<SecurityUserSettingsTab />", () => {
4546
getIgnoredUsers: jest.fn(),
4647
getVersions: jest.fn().mockResolvedValue({
4748
unstable_features: {
48-
"org.matrix.msc3882": true,
4949
"org.matrix.msc3886": true,
5050
},
5151
}),
52+
getCapabilities: jest.fn().mockResolvedValue({
53+
[UNSTABLE_MSC3882_CAPABILITY.name]: {
54+
enabled: true,
55+
},
56+
}),
5257
});
5358

5459
const getComponent = () => (

test/components/views/settings/tabs/user/SessionManagerTab-test.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
PUSHER_DEVICE_ID,
3030
PUSHER_ENABLED,
3131
IAuthData,
32+
UNSTABLE_MSC3882_CAPABILITY,
3233
} from "matrix-js-sdk/src/matrix";
3334

3435
import { clearAllModals } from "../../../../../test-utils";
@@ -97,6 +98,7 @@ describe("<SessionManagerTab />", () => {
9798
setPusher: jest.fn(),
9899
setLocalNotificationSettings: jest.fn(),
99100
getVersions: jest.fn().mockResolvedValue({}),
101+
getCapabilities: jest.fn().mockResolvedValue({}),
100102
});
101103

102104
const defaultProps = {};
@@ -1375,10 +1377,14 @@ describe("<SessionManagerTab />", () => {
13751377
mockClient.getVersions.mockResolvedValue({
13761378
versions: [],
13771379
unstable_features: {
1378-
"org.matrix.msc3882": true,
13791380
"org.matrix.msc3886": true,
13801381
},
13811382
});
1383+
mockClient.getCapabilities.mockResolvedValue({
1384+
[UNSTABLE_MSC3882_CAPABILITY.name]: {
1385+
enabled: true,
1386+
},
1387+
});
13821388
});
13831389

13841390
it("renders qr code login section", async () => {

0 commit comments

Comments
 (0)