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
This commit is contained in:
parent
c7a3209b84
commit
16c3efead5
11 changed files with 210 additions and 109 deletions
|
@ -26,10 +26,10 @@ import Spinner from '../../elements/Spinner';
|
|||
import ToggleSwitch from '../../elements/ToggleSwitch';
|
||||
import { DeviceDetailHeading } from './DeviceDetailHeading';
|
||||
import { DeviceVerificationStatusCard } from './DeviceVerificationStatusCard';
|
||||
import { DeviceWithVerification } from './types';
|
||||
import { ExtendedDevice } from './types';
|
||||
|
||||
interface Props {
|
||||
device: DeviceWithVerification;
|
||||
device: ExtendedDevice;
|
||||
pusher?: IPusher | undefined;
|
||||
localNotificationSettings?: LocalNotificationSettings | undefined;
|
||||
isSigningOut: boolean;
|
||||
|
@ -41,6 +41,7 @@ interface Props {
|
|||
}
|
||||
|
||||
interface MetadataTable {
|
||||
id: string;
|
||||
heading?: string;
|
||||
values: { label: string, value?: string | React.ReactNode }[];
|
||||
}
|
||||
|
@ -58,6 +59,7 @@ const DeviceDetails: React.FC<Props> = ({
|
|||
}) => {
|
||||
const metadata: MetadataTable[] = [
|
||||
{
|
||||
id: 'session',
|
||||
values: [
|
||||
{ label: _t('Session ID'), value: device.device_id },
|
||||
{
|
||||
|
@ -67,12 +69,28 @@ const DeviceDetails: React.FC<Props> = ({
|
|||
],
|
||||
},
|
||||
{
|
||||
id: 'application',
|
||||
heading: _t('Application'),
|
||||
values: [
|
||||
{ label: _t('Name'), value: device.clientName },
|
||||
{ label: _t('Version'), value: device.clientVersion },
|
||||
{ label: _t('URL'), value: device.url },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'device',
|
||||
heading: _t('Device'),
|
||||
values: [
|
||||
{ label: _t('IP address'), value: device.last_seen_ip },
|
||||
],
|
||||
},
|
||||
];
|
||||
].map(section =>
|
||||
// filter out falsy values
|
||||
({ ...section, values: section.values.filter(row => !!row.value) }))
|
||||
.filter(section =>
|
||||
// then filter out sections with no values
|
||||
section.values.length,
|
||||
);
|
||||
|
||||
const showPushNotificationSection = !!pusher || !!localNotificationSettings;
|
||||
|
||||
|
@ -101,9 +119,10 @@ const DeviceDetails: React.FC<Props> = ({
|
|||
</section>
|
||||
<section className='mx_DeviceDetails_section'>
|
||||
<p className='mx_DeviceDetails_sectionHeading'>{ _t('Session details') }</p>
|
||||
{ metadata.map(({ heading, values }, index) => <table
|
||||
{ metadata.map(({ heading, values, id }, index) => <table
|
||||
className='mx_DeviceDetails_metadataTable'
|
||||
key={index}
|
||||
data-testid={`device-detail-metadata-${id}`}
|
||||
>
|
||||
{ heading &&
|
||||
<thead>
|
||||
|
|
|
@ -17,7 +17,13 @@ limitations under the License.
|
|||
import { IMyDevice } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
export type DeviceWithVerification = IMyDevice & { isVerified: boolean | null };
|
||||
export type DevicesDictionary = Record<DeviceWithVerification['device_id'], DeviceWithVerification>;
|
||||
export type ExtendedDeviceInfo = {
|
||||
clientName?: string;
|
||||
clientVersion?: string;
|
||||
url?: string;
|
||||
};
|
||||
export type ExtendedDevice = DeviceWithVerification & ExtendedDeviceInfo;
|
||||
export type DevicesDictionary = Record<DeviceWithVerification['device_id'], ExtendedDevice>;
|
||||
|
||||
export enum DeviceSecurityVariation {
|
||||
Verified = 'Verified',
|
||||
|
|
|
@ -33,7 +33,8 @@ import { LocalNotificationSettings } from "matrix-js-sdk/src/@types/local_notifi
|
|||
|
||||
import MatrixClientContext from "../../../../contexts/MatrixClientContext";
|
||||
import { _t } from "../../../../languageHandler";
|
||||
import { DevicesDictionary, DeviceWithVerification } from "./types";
|
||||
import { getDeviceClientInformation } from "../../../../utils/device/clientInformation";
|
||||
import { DevicesDictionary, DeviceWithVerification, ExtendedDeviceInfo } from "./types";
|
||||
import { useEventEmitter } from "../../../../hooks/useEventEmitter";
|
||||
|
||||
const isDeviceVerified = (
|
||||
|
@ -62,6 +63,16 @@ const isDeviceVerified = (
|
|||
}
|
||||
};
|
||||
|
||||
const parseDeviceExtendedInformation = (matrixClient: MatrixClient, device: IMyDevice): ExtendedDeviceInfo => {
|
||||
const { name, version, url } = getDeviceClientInformation(matrixClient, device.device_id);
|
||||
|
||||
return {
|
||||
clientName: name,
|
||||
clientVersion: version,
|
||||
url,
|
||||
};
|
||||
};
|
||||
|
||||
const fetchDevicesWithVerification = async (
|
||||
matrixClient: MatrixClient,
|
||||
userId: string,
|
||||
|
@ -75,6 +86,7 @@ const fetchDevicesWithVerification = async (
|
|||
[device.device_id]: {
|
||||
...device,
|
||||
isVerified: isDeviceVerified(matrixClient, crossSigningInfo, device),
|
||||
...parseDeviceExtendedInformation(matrixClient, device),
|
||||
},
|
||||
}), {});
|
||||
|
||||
|
|
|
@ -1717,6 +1717,9 @@
|
|||
"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",
|
||||
"Session ID": "Session ID",
|
||||
"Last activity": "Last activity",
|
||||
"Application": "Application",
|
||||
"Version": "Version",
|
||||
"URL": "URL",
|
||||
"Device": "Device",
|
||||
"IP address": "IP address",
|
||||
"Session details": "Session details",
|
||||
|
|
|
@ -19,6 +19,12 @@ import { MatrixClient } from "matrix-js-sdk/src/client";
|
|||
import BasePlatform from "../../BasePlatform";
|
||||
import { IConfigOptions } from "../../IConfigOptions";
|
||||
|
||||
export type DeviceClientInformation = {
|
||||
name?: string;
|
||||
version?: string;
|
||||
url?: string;
|
||||
};
|
||||
|
||||
const formatUrl = (): string | undefined => {
|
||||
// don't record url for electron clients
|
||||
if (window.electron) {
|
||||
|
@ -34,7 +40,7 @@ const formatUrl = (): string | undefined => {
|
|||
].join("");
|
||||
};
|
||||
|
||||
const getClientInformationEventType = (deviceId: string): string =>
|
||||
export const getClientInformationEventType = (deviceId: string): string =>
|
||||
`io.element.matrix_client_information.${deviceId}`;
|
||||
|
||||
/**
|
||||
|
@ -58,3 +64,23 @@ export const recordClientInformation = async (
|
|||
url,
|
||||
});
|
||||
};
|
||||
|
||||
const sanitizeContentString = (value: unknown): string | undefined =>
|
||||
value && typeof value === 'string' ? value : undefined;
|
||||
|
||||
export const getDeviceClientInformation = (matrixClient: MatrixClient, deviceId: string): DeviceClientInformation => {
|
||||
const event = matrixClient.getAccountData(getClientInformationEventType(deviceId));
|
||||
|
||||
if (!event) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const { name, version, url } = event.getContent();
|
||||
|
||||
return {
|
||||
name: sanitizeContentString(name),
|
||||
version: sanitizeContentString(version),
|
||||
url: sanitizeContentString(url),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue