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

Commit 16c3efe

Browse files
author
Kerry
authored
Device manager - display client information in device details (PSG-682) (#9315)
* record device client inforamtion events on app start * matrix-client-information -> matrix_client_information * fix types * remove another unused export * add docs link * display device client information in device details * update snapshots * integration-ish test client information in metadata * tests * fix tests * export helper * DeviceClientInformation type
1 parent c7a3209 commit 16c3efe

File tree

11 files changed

+210
-109
lines changed

11 files changed

+210
-109
lines changed

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

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ import Spinner from '../../elements/Spinner';
2626
import ToggleSwitch from '../../elements/ToggleSwitch';
2727
import { DeviceDetailHeading } from './DeviceDetailHeading';
2828
import { DeviceVerificationStatusCard } from './DeviceVerificationStatusCard';
29-
import { DeviceWithVerification } from './types';
29+
import { ExtendedDevice } from './types';
3030

3131
interface Props {
32-
device: DeviceWithVerification;
32+
device: ExtendedDevice;
3333
pusher?: IPusher | undefined;
3434
localNotificationSettings?: LocalNotificationSettings | undefined;
3535
isSigningOut: boolean;
@@ -41,6 +41,7 @@ interface Props {
4141
}
4242

4343
interface MetadataTable {
44+
id: string;
4445
heading?: string;
4546
values: { label: string, value?: string | React.ReactNode }[];
4647
}
@@ -58,6 +59,7 @@ const DeviceDetails: React.FC<Props> = ({
5859
}) => {
5960
const metadata: MetadataTable[] = [
6061
{
62+
id: 'session',
6163
values: [
6264
{ label: _t('Session ID'), value: device.device_id },
6365
{
@@ -67,12 +69,28 @@ const DeviceDetails: React.FC<Props> = ({
6769
],
6870
},
6971
{
72+
id: 'application',
73+
heading: _t('Application'),
74+
values: [
75+
{ label: _t('Name'), value: device.clientName },
76+
{ label: _t('Version'), value: device.clientVersion },
77+
{ label: _t('URL'), value: device.url },
78+
],
79+
},
80+
{
81+
id: 'device',
7082
heading: _t('Device'),
7183
values: [
7284
{ label: _t('IP address'), value: device.last_seen_ip },
7385
],
7486
},
75-
];
87+
].map(section =>
88+
// filter out falsy values
89+
({ ...section, values: section.values.filter(row => !!row.value) }))
90+
.filter(section =>
91+
// then filter out sections with no values
92+
section.values.length,
93+
);
7694

7795
const showPushNotificationSection = !!pusher || !!localNotificationSettings;
7896

@@ -101,9 +119,10 @@ const DeviceDetails: React.FC<Props> = ({
101119
</section>
102120
<section className='mx_DeviceDetails_section'>
103121
<p className='mx_DeviceDetails_sectionHeading'>{ _t('Session details') }</p>
104-
{ metadata.map(({ heading, values }, index) => <table
122+
{ metadata.map(({ heading, values, id }, index) => <table
105123
className='mx_DeviceDetails_metadataTable'
106124
key={index}
125+
data-testid={`device-detail-metadata-${id}`}
107126
>
108127
{ heading &&
109128
<thead>

src/components/views/settings/devices/types.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@ limitations under the License.
1717
import { IMyDevice } from "matrix-js-sdk/src/matrix";
1818

1919
export type DeviceWithVerification = IMyDevice & { isVerified: boolean | null };
20-
export type DevicesDictionary = Record<DeviceWithVerification['device_id'], DeviceWithVerification>;
20+
export type ExtendedDeviceInfo = {
21+
clientName?: string;
22+
clientVersion?: string;
23+
url?: string;
24+
};
25+
export type ExtendedDevice = DeviceWithVerification & ExtendedDeviceInfo;
26+
export type DevicesDictionary = Record<DeviceWithVerification['device_id'], ExtendedDevice>;
2127

2228
export enum DeviceSecurityVariation {
2329
Verified = 'Verified',

src/components/views/settings/devices/useOwnDevices.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ import { LocalNotificationSettings } from "matrix-js-sdk/src/@types/local_notifi
3333

3434
import MatrixClientContext from "../../../../contexts/MatrixClientContext";
3535
import { _t } from "../../../../languageHandler";
36-
import { DevicesDictionary, DeviceWithVerification } from "./types";
36+
import { getDeviceClientInformation } from "../../../../utils/device/clientInformation";
37+
import { DevicesDictionary, DeviceWithVerification, ExtendedDeviceInfo } from "./types";
3738
import { useEventEmitter } from "../../../../hooks/useEventEmitter";
3839

3940
const isDeviceVerified = (
@@ -62,6 +63,16 @@ const isDeviceVerified = (
6263
}
6364
};
6465

66+
const parseDeviceExtendedInformation = (matrixClient: MatrixClient, device: IMyDevice): ExtendedDeviceInfo => {
67+
const { name, version, url } = getDeviceClientInformation(matrixClient, device.device_id);
68+
69+
return {
70+
clientName: name,
71+
clientVersion: version,
72+
url,
73+
};
74+
};
75+
6576
const fetchDevicesWithVerification = async (
6677
matrixClient: MatrixClient,
6778
userId: string,
@@ -75,6 +86,7 @@ const fetchDevicesWithVerification = async (
7586
[device.device_id]: {
7687
...device,
7788
isVerified: isDeviceVerified(matrixClient, crossSigningInfo, device),
89+
...parseDeviceExtendedInformation(matrixClient, device),
7890
},
7991
}), {});
8092

src/i18n/strings/en_EN.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,6 +1717,9 @@
17171717
"Please be aware that session names are also visible to people you communicate with": "Please be aware that session names are also visible to people you communicate with",
17181718
"Session ID": "Session ID",
17191719
"Last activity": "Last activity",
1720+
"Application": "Application",
1721+
"Version": "Version",
1722+
"URL": "URL",
17201723
"Device": "Device",
17211724
"IP address": "IP address",
17221725
"Session details": "Session details",

src/utils/device/clientInformation.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ import { MatrixClient } from "matrix-js-sdk/src/client";
1919
import BasePlatform from "../../BasePlatform";
2020
import { IConfigOptions } from "../../IConfigOptions";
2121

22+
export type DeviceClientInformation = {
23+
name?: string;
24+
version?: string;
25+
url?: string;
26+
};
27+
2228
const formatUrl = (): string | undefined => {
2329
// don't record url for electron clients
2430
if (window.electron) {
@@ -34,7 +40,7 @@ const formatUrl = (): string | undefined => {
3440
].join("");
3541
};
3642

37-
const getClientInformationEventType = (deviceId: string): string =>
43+
export const getClientInformationEventType = (deviceId: string): string =>
3844
`io.element.matrix_client_information.${deviceId}`;
3945

4046
/**
@@ -58,3 +64,23 @@ export const recordClientInformation = async (
5864
url,
5965
});
6066
};
67+
68+
const sanitizeContentString = (value: unknown): string | undefined =>
69+
value && typeof value === 'string' ? value : undefined;
70+
71+
export const getDeviceClientInformation = (matrixClient: MatrixClient, deviceId: string): DeviceClientInformation => {
72+
const event = matrixClient.getAccountData(getClientInformationEventType(deviceId));
73+
74+
if (!event) {
75+
return {};
76+
}
77+
78+
const { name, version, url } = event.getContent();
79+
80+
return {
81+
name: sanitizeContentString(name),
82+
version: sanitizeContentString(version),
83+
url: sanitizeContentString(url),
84+
};
85+
};
86+

test/DeviceListener-test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ import { isSecretStorageBeingAccessed } from "../src/SecurityManager";
2929
import dis from "../src/dispatcher/dispatcher";
3030
import { Action } from "../src/dispatcher/actions";
3131
import SettingsStore from "../src/settings/SettingsStore";
32-
import { mockPlatformPeg } from "./test-utils";
3332
import { SettingLevel } from "../src/settings/SettingLevel";
33+
import { mockPlatformPeg } from "./test-utils";
3434

3535
// don't litter test console with logs
3636
jest.mock("matrix-js-sdk/src/logger");

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ describe('<DeviceDetails />', () => {
5858
display_name: 'My Device',
5959
last_seen_ip: '123.456.789',
6060
last_seen_ts: now - 60000000,
61+
clientName: 'Element Web',
6162
};
6263
const { container } = render(getComponent({ device }));
6364
expect(container).toMatchSnapshot();

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

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ HTMLCollection [
7676
</p>
7777
<table
7878
class="mx_DeviceDetails_metadataTable"
79+
data-testid="device-detail-metadata-session"
7980
>
8081
<tbody>
8182
<tr>
@@ -90,39 +91,6 @@ HTMLCollection [
9091
alices_device
9192
</td>
9293
</tr>
93-
<tr>
94-
<td
95-
class="mxDeviceDetails_metadataLabel"
96-
>
97-
Last activity
98-
</td>
99-
<td
100-
class="mxDeviceDetails_metadataValue"
101-
/>
102-
</tr>
103-
</tbody>
104-
</table>
105-
<table
106-
class="mx_DeviceDetails_metadataTable"
107-
>
108-
<thead>
109-
<tr>
110-
<th>
111-
Device
112-
</th>
113-
</tr>
114-
</thead>
115-
<tbody>
116-
<tr>
117-
<td
118-
class="mxDeviceDetails_metadataLabel"
119-
>
120-
IP address
121-
</td>
122-
<td
123-
class="mxDeviceDetails_metadataValue"
124-
/>
125-
</tr>
12694
</tbody>
12795
</table>
12896
</section>

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

Lines changed: 30 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ exports[`<DeviceDetails /> renders a verified device 1`] = `
6464
</p>
6565
<table
6666
class="mx_DeviceDetails_metadataTable"
67+
data-testid="device-detail-metadata-session"
6768
>
6869
<tbody>
6970
<tr>
@@ -78,39 +79,6 @@ exports[`<DeviceDetails /> renders a verified device 1`] = `
7879
my-device
7980
</td>
8081
</tr>
81-
<tr>
82-
<td
83-
class="mxDeviceDetails_metadataLabel"
84-
>
85-
Last activity
86-
</td>
87-
<td
88-
class="mxDeviceDetails_metadataValue"
89-
/>
90-
</tr>
91-
</tbody>
92-
</table>
93-
<table
94-
class="mx_DeviceDetails_metadataTable"
95-
>
96-
<thead>
97-
<tr>
98-
<th>
99-
Device
100-
</th>
101-
</tr>
102-
</thead>
103-
<tbody>
104-
<tr>
105-
<td
106-
class="mxDeviceDetails_metadataLabel"
107-
>
108-
IP address
109-
</td>
110-
<td
111-
class="mxDeviceDetails_metadataValue"
112-
/>
113-
</tr>
11482
</tbody>
11583
</table>
11684
</section>
@@ -198,6 +166,7 @@ exports[`<DeviceDetails /> renders device with metadata 1`] = `
198166
</p>
199167
<table
200168
class="mx_DeviceDetails_metadataTable"
169+
data-testid="device-detail-metadata-session"
201170
>
202171
<tbody>
203172
<tr>
@@ -228,6 +197,33 @@ exports[`<DeviceDetails /> renders device with metadata 1`] = `
228197
</table>
229198
<table
230199
class="mx_DeviceDetails_metadataTable"
200+
data-testid="device-detail-metadata-application"
201+
>
202+
<thead>
203+
<tr>
204+
<th>
205+
Application
206+
</th>
207+
</tr>
208+
</thead>
209+
<tbody>
210+
<tr>
211+
<td
212+
class="mxDeviceDetails_metadataLabel"
213+
>
214+
Name
215+
</td>
216+
<td
217+
class="mxDeviceDetails_metadataValue"
218+
>
219+
Element Web
220+
</td>
221+
</tr>
222+
</tbody>
223+
</table>
224+
<table
225+
class="mx_DeviceDetails_metadataTable"
226+
data-testid="device-detail-metadata-device"
231227
>
232228
<thead>
233229
<tr>
@@ -336,6 +332,7 @@ exports[`<DeviceDetails /> renders device without metadata 1`] = `
336332
</p>
337333
<table
338334
class="mx_DeviceDetails_metadataTable"
335+
data-testid="device-detail-metadata-session"
339336
>
340337
<tbody>
341338
<tr>
@@ -350,39 +347,6 @@ exports[`<DeviceDetails /> renders device without metadata 1`] = `
350347
my-device
351348
</td>
352349
</tr>
353-
<tr>
354-
<td
355-
class="mxDeviceDetails_metadataLabel"
356-
>
357-
Last activity
358-
</td>
359-
<td
360-
class="mxDeviceDetails_metadataValue"
361-
/>
362-
</tr>
363-
</tbody>
364-
</table>
365-
<table
366-
class="mx_DeviceDetails_metadataTable"
367-
>
368-
<thead>
369-
<tr>
370-
<th>
371-
Device
372-
</th>
373-
</tr>
374-
</thead>
375-
<tbody>
376-
<tr>
377-
<td
378-
class="mxDeviceDetails_metadataLabel"
379-
>
380-
IP address
381-
</td>
382-
<td
383-
class="mxDeviceDetails_metadataValue"
384-
/>
385-
</tr>
386350
</tbody>
387351
</table>
388352
</section>

0 commit comments

Comments
 (0)