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

Device manager - logout current session (PSG-743) #9275

Merged
merged 7 commits into from
Sep 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ limitations under the License.

display: grid;
grid-gap: $spacing-16;
justify-content: left;

&:last-child {
padding-bottom: 0;
Expand All @@ -46,7 +47,7 @@ limitations under the License.
margin: 0;
}

.mxDeviceDetails_metadataTable {
.mx_DeviceDetails_metadataTable {
font-size: $font-12px;
color: $secondary-content;

Expand Down
14 changes: 12 additions & 2 deletions res/css/views/elements/_AccessibleButton.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -138,15 +138,25 @@ limitations under the License.
}

&.mx_AccessibleButton_kind_link,
&.mx_AccessibleButton_kind_link_inline {
color: $accent;
&.mx_AccessibleButton_kind_link_inline,
&.mx_AccessibleButton_kind_danger_inline {
font-size: inherit;
font-weight: normal;
line-height: inherit;
padding: 0;
}

&.mx_AccessibleButton_kind_link,
&.mx_AccessibleButton_kind_link_inline {
color: $accent;
}

&.mx_AccessibleButton_kind_danger_inline {
color: $alert;
}

&.mx_AccessibleButton_kind_link_inline,
&.mx_AccessibleButton_kind_danger_inline {
display: inline;
}

Expand Down
1 change: 1 addition & 0 deletions src/components/views/elements/AccessibleButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type AccessibleButtonKind = | 'primary'
| 'danger'
| 'danger_outline'
| 'danger_sm'
| 'danger_inline'
| 'link'
| 'link_inline'
| 'link_sm'
Expand Down
13 changes: 11 additions & 2 deletions src/components/views/settings/devices/CurrentDeviceSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@ interface Props {
device?: DeviceWithVerification;
isLoading: boolean;
onVerifyCurrentDevice: () => void;
onSignOutCurrentDevice: () => void;
}

const CurrentDeviceSection: React.FC<Props> = ({
device, isLoading, onVerifyCurrentDevice,
device,
isLoading,
onVerifyCurrentDevice,
onSignOutCurrentDevice,
}) => {
const [isExpanded, setIsExpanded] = useState(false);

Expand All @@ -51,7 +55,12 @@ const CurrentDeviceSection: React.FC<Props> = ({
onClick={() => setIsExpanded(!isExpanded)}
/>
</DeviceTile>
{ isExpanded && <DeviceDetails device={device} /> }
{ isExpanded &&
<DeviceDetails
device={device}
onSignOutDevice={onSignOutCurrentDevice}
/>
}
<br />
<DeviceVerificationStatusCard device={device} onVerifyDevice={onVerifyCurrentDevice} />
</>
Expand Down
16 changes: 15 additions & 1 deletion src/components/views/settings/devices/DeviceDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@ import React from 'react';

import { formatDate } from '../../../../DateUtils';
import { _t } from '../../../../languageHandler';
import AccessibleButton from '../../elements/AccessibleButton';
import Heading from '../../typography/Heading';
import { DeviceVerificationStatusCard } from './DeviceVerificationStatusCard';
import { DeviceWithVerification } from './types';

interface Props {
device: DeviceWithVerification;
onVerifyDevice?: () => void;
// @TODO(kerry) optional while signout only implemented
// for current device (PSG-744)
Comment on lines +29 to +30
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the deal with this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm implementing signing out of current session separately to signing out of other sessions since the code paths are very different. This component is generic and used by both current and other sessions, so while I haven't added signout code to the other sessions this is an optional prop and sign out is not rendered when it's falsy.

I'm working on the other sessions half right now, so this will go away in my next PR

onSignOutDevice?: () => void;
}

interface MetadataTable {
Expand All @@ -35,6 +39,7 @@ interface MetadataTable {
const DeviceDetails: React.FC<Props> = ({
device,
onVerifyDevice,
onSignOutDevice,
}) => {
const metadata: MetadataTable[] = [
{
Expand Down Expand Up @@ -64,7 +69,7 @@ const DeviceDetails: React.FC<Props> = ({
<section className='mx_DeviceDetails_section'>
<p className='mx_DeviceDetails_sectionHeading'>{ _t('Session details') }</p>
{ metadata.map(({ heading, values }, index) => <table
className='mxDeviceDetails_metadataTable'
className='mx_DeviceDetails_metadataTable'
key={index}
>
{ heading &&
Expand All @@ -82,6 +87,15 @@ const DeviceDetails: React.FC<Props> = ({
</table>,
) }
</section>
{ !!onSignOutDevice && <section className='mx_DeviceDetails_section'>
<AccessibleButton
onClick={onSignOutDevice}
kind='danger_inline'
data-testid='device-detail-sign-out-cta'
>
{ _t('Sign out of this session') }
</AccessibleButton>
</section> }
</div>;
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/views/settings/devices/useOwnDevices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { IMyDevice, MatrixClient } from "matrix-js-sdk/src/matrix";
import { CrossSigningInfo } from "matrix-js-sdk/src/crypto/CrossSigning";
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
import { User } from "matrix-js-sdk/src/models/user";
import { MatrixError } from "matrix-js-sdk/src/matrix";
import { MatrixError } from "matrix-js-sdk/src/http-api";
import { logger } from "matrix-js-sdk/src/logger";

import MatrixClientContext from "../../../../contexts/MatrixClientContext";
Expand Down
11 changes: 11 additions & 0 deletions src/components/views/settings/tabs/user/SessionManagerTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import SettingsTab from '../SettingsTab';
import Modal from '../../../../../Modal';
import SetupEncryptionDialog from '../../../dialogs/security/SetupEncryptionDialog';
import VerificationRequestDialog from '../../../dialogs/VerificationRequestDialog';
import LogoutDialog from '../../../dialogs/LogoutDialog';

const SessionManagerTab: React.FC = () => {
const {
Expand Down Expand Up @@ -90,6 +91,15 @@ const SessionManagerTab: React.FC = () => {
});
}, [requestDeviceVerification, refreshDevices, currentUserMember]);

const onSignOutCurrentDevice = () => {
if (!currentDevice) {
return;
}
Modal.createDialog(LogoutDialog,
/* props= */{}, /* className= */undefined,
/* isPriority= */false, /* isStatic= */true);
};

useEffect(() => () => {
clearTimeout(scrollIntoViewTimeoutRef.current);
}, [scrollIntoViewTimeoutRef]);
Expand All @@ -104,6 +114,7 @@ const SessionManagerTab: React.FC = () => {
device={currentDevice}
isLoading={isLoading}
onVerifyCurrentDevice={onVerifyCurrentDevice}
onSignOutCurrentDevice={onSignOutCurrentDevice}
/>
{
shouldShowOtherSessions &&
Expand Down
1 change: 1 addition & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1712,6 +1712,7 @@
"Device": "Device",
"IP address": "IP address",
"Session details": "Session details",
"Sign out of this session": "Sign out of this session",
"Toggle device details": "Toggle device details",
"Inactive for %(inactiveAgeDays)s+ days": "Inactive for %(inactiveAgeDays)s+ days",
"Verified": "Verified",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe('<CurrentDeviceSection />', () => {
const defaultProps = {
device: alicesVerifiedDevice,
onVerifyCurrentDevice: jest.fn(),
onSignOutCurrentDevice: jest.fn(),
isLoading: false,
};
const getComponent = (props = {}): React.ReactElement =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ HTMLCollection [
Session details
</p>
<table
class="mxDeviceDetails_metadataTable"
class="mx_DeviceDetails_metadataTable"
>
<tbody>
<tr>
Expand Down Expand Up @@ -78,7 +78,7 @@ HTMLCollection [
</tbody>
</table>
<table
class="mxDeviceDetails_metadataTable"
class="mx_DeviceDetails_metadataTable"
>
<thead>
<tr>
Expand All @@ -101,6 +101,18 @@ HTMLCollection [
</tbody>
</table>
</section>
<section
class="mx_DeviceDetails_section"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_inline"
data-testid="device-detail-sign-out-cta"
role="button"
tabindex="0"
>
Sign out of this session
</div>
</section>
</div>,
]
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ exports[`<DeviceDetails /> renders a verified device 1`] = `
Session details
</p>
<table
class="mxDeviceDetails_metadataTable"
class="mx_DeviceDetails_metadataTable"
>
<tbody>
<tr>
Expand Down Expand Up @@ -78,7 +78,7 @@ exports[`<DeviceDetails /> renders a verified device 1`] = `
</tbody>
</table>
<table
class="mxDeviceDetails_metadataTable"
class="mx_DeviceDetails_metadataTable"
>
<thead>
<tr>
Expand Down Expand Up @@ -155,7 +155,7 @@ exports[`<DeviceDetails /> renders device with metadata 1`] = `
Session details
</p>
<table
class="mxDeviceDetails_metadataTable"
class="mx_DeviceDetails_metadataTable"
>
<tbody>
<tr>
Expand Down Expand Up @@ -185,7 +185,7 @@ exports[`<DeviceDetails /> renders device with metadata 1`] = `
</tbody>
</table>
<table
class="mxDeviceDetails_metadataTable"
class="mx_DeviceDetails_metadataTable"
>
<thead>
<tr>
Expand Down Expand Up @@ -264,7 +264,7 @@ exports[`<DeviceDetails /> renders device without metadata 1`] = `
Session details
</p>
<table
class="mxDeviceDetails_metadataTable"
class="mx_DeviceDetails_metadataTable"
>
<tbody>
<tr>
Expand Down Expand Up @@ -292,7 +292,7 @@ exports[`<DeviceDetails /> renders device without metadata 1`] = `
</tbody>
</table>
<table
class="mxDeviceDetails_metadataTable"
class="mx_DeviceDetails_metadataTable"
>
<thead>
<tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {
mockClientMethodsUser,
} from '../../../../../test-utils';
import Modal from '../../../../../../src/Modal';
import LogoutDialog from '../../../../../../src/components/views/dialogs/LogoutDialog';

jest.useFakeTimers();

Expand All @@ -53,7 +54,7 @@ describe('<SessionManagerTab />', () => {
const mockCrossSigningInfo = {
checkDeviceTrust: jest.fn(),
};
const mockVerificationRequest = { cancel: jest.fn() } as unknown as VerificationRequest;
const mockVerificationRequest = { cancel: jest.fn(), on: jest.fn() } as unknown as VerificationRequest;
const mockClient = getMockClientWithEventEmitter({
...mockClientMethodsUser(aliceId),
getStoredCrossSigningForUser: jest.fn().mockReturnValue(mockCrossSigningInfo),
Expand Down Expand Up @@ -374,4 +375,29 @@ describe('<SessionManagerTab />', () => {
expect(mockClient.getDevices).toHaveBeenCalled();
});
});

describe('Sign out', () => {
it('Signs out of current device', async () => {
const modalSpy = jest.spyOn(Modal, 'createDialog');

mockClient.getDevices.mockResolvedValue({ devices: [alicesDevice] });
const { getByTestId } = render(getComponent());

await act(async () => {
await flushPromisesWithFakeTimers();
});

// open device detail
const tile1 = getByTestId(`device-tile-${alicesDevice.device_id}`);
const toggle1 = tile1.querySelector('[aria-label="Toggle device details"]') as Element;
fireEvent.click(toggle1);

const signOutButton = getByTestId('device-detail-sign-out-cta');
expect(signOutButton).toMatchSnapshot();
fireEvent.click(signOutButton);

// logout dialog opened
expect(modalSpy).toHaveBeenCalledWith(LogoutDialog, {}, undefined, false, true);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<SessionManagerTab /> Sign out Signs out of current device 1`] = `
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_danger_inline"
data-testid="device-detail-sign-out-cta"
role="button"
tabindex="0"
>
Sign out of this session
</div>
`;

exports[`<SessionManagerTab /> goes to filtered list from security recommendations 1`] = `
<div
class="mx_FilteredDeviceList_header"
Expand Down