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

Commit

Permalink
Device manager - add verify current session button (PSG-527) (#9252)
Browse files Browse the repository at this point in the history
* add verify current session button

* i18n

* strict type issues
  • Loading branch information
Kerry authored Sep 8, 2022
1 parent 8bc03aa commit 6190477
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ import { DeviceWithVerification } from './types';
interface Props {
device?: DeviceWithVerification;
isLoading: boolean;
onVerifyCurrentDevice: () => void;
}

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

Expand All @@ -52,7 +53,7 @@ const CurrentDeviceSection: React.FC<Props> = ({
</DeviceTile>
{ isExpanded && <DeviceDetails device={device} /> }
<br />
<DeviceVerificationStatusCard device={device} />
<DeviceVerificationStatusCard device={device} onVerifyDevice={onVerifyCurrentDevice} />
</>
}
</SettingsSubsection>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
import React from 'react';

import { _t } from '../../../../languageHandler';
import AccessibleButton from '../../elements/AccessibleButton';
import DeviceSecurityCard from './DeviceSecurityCard';
import {
DeviceSecurityVariation,
Expand All @@ -25,12 +26,14 @@ import {

interface Props {
device: DeviceWithVerification;
onVerifyDevice?: () => void;
}

export const DeviceVerificationStatusCard: React.FC<Props> = ({
device,
onVerifyDevice,
}) => {
const securityCardProps = device?.isVerified ? {
const securityCardProps = device.isVerified ? {
variation: DeviceSecurityVariation.Verified,
heading: _t('Verified session'),
description: _t('This session is ready for secure messaging.'),
Expand All @@ -41,5 +44,15 @@ export const DeviceVerificationStatusCard: React.FC<Props> = ({
};
return <DeviceSecurityCard
{...securityCardProps}
/>;
>
{ !device.isVerified && !!onVerifyDevice &&
<AccessibleButton
kind='primary'
onClick={onVerifyDevice}
data-testid={`verification-status-button-${device.device_id}`}
>
{ _t('Verify session') }
</AccessibleButton>
}
</DeviceSecurityCard>;
};
41 changes: 22 additions & 19 deletions src/components/views/settings/devices/useOwnDevices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import { useContext, useEffect, useState } from "react";
import { useCallback, useContext, useEffect, useState } from "react";
import { IMyDevice, MatrixClient } from "matrix-js-sdk/src/matrix";
import { CrossSigningInfo } from "matrix-js-sdk/src/crypto/CrossSigning";
import { logger } from "matrix-js-sdk/src/logger";
Expand Down Expand Up @@ -64,6 +64,7 @@ type DevicesState = {
devices: DevicesDictionary;
currentDeviceId: string;
isLoading: boolean;
refreshDevices: () => Promise<void>;
error?: OwnDevicesError;
};
export const useOwnDevices = (): DevicesState => {
Expand All @@ -75,30 +76,32 @@ export const useOwnDevices = (): DevicesState => {
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<OwnDevicesError>();

useEffect(() => {
const getDevicesAsync = async () => {
setIsLoading(true);
try {
const devices = await fetchDevicesWithVerification(matrixClient);
setDevices(devices);
setIsLoading(false);
} catch (error) {
if (error.httpStatus == 404) {
// 404 probably means the HS doesn't yet support the API.
setError(OwnDevicesError.Unsupported);
} else {
logger.error("Error loading sessions:", error);
setError(OwnDevicesError.Default);
}
setIsLoading(false);
const refreshDevices = useCallback(async () => {
setIsLoading(true);
try {
const devices = await fetchDevicesWithVerification(matrixClient);
setDevices(devices);
setIsLoading(false);
} catch (error) {
if (error.httpStatus == 404) {
// 404 probably means the HS doesn't yet support the API.
setError(OwnDevicesError.Unsupported);
} else {
logger.error("Error loading sessions:", error);
setError(OwnDevicesError.Default);
}
};
getDevicesAsync();
setIsLoading(false);
}
}, [matrixClient]);

useEffect(() => {
refreshDevices();
}, [refreshDevices]);

return {
devices,
currentDeviceId,
refreshDevices,
isLoading,
error,
};
Expand Down
20 changes: 19 additions & 1 deletion src/components/views/settings/tabs/user/SessionManagerTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,16 @@ import CurrentDeviceSection from '../../devices/CurrentDeviceSection';
import SecurityRecommendations from '../../devices/SecurityRecommendations';
import { DeviceSecurityVariation, DeviceWithVerification } from '../../devices/types';
import SettingsTab from '../SettingsTab';
import Modal from '../../../../../Modal';
import SetupEncryptionDialog from '../../../dialogs/security/SetupEncryptionDialog';

const SessionManagerTab: React.FC = () => {
const { devices, currentDeviceId, isLoading } = useOwnDevices();
const {
devices,
currentDeviceId,
isLoading,
refreshDevices,
} = useOwnDevices();
const [filter, setFilter] = useState<DeviceSecurityVariation>();
const [expandedDeviceIds, setExpandedDeviceIds] = useState<DeviceWithVerification['device_id'][]>([]);
const filteredDeviceListRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -57,6 +64,16 @@ const SessionManagerTab: React.FC = () => {
const { [currentDeviceId]: currentDevice, ...otherDevices } = devices;
const shouldShowOtherSessions = Object.keys(otherDevices).length > 0;

const onVerifyCurrentDevice = () => {
if (!currentDevice) {
return;
}
Modal.createDialog(
SetupEncryptionDialog as unknown as React.ComponentType,
{ onFinished: refreshDevices },
);
};

useEffect(() => () => {
clearTimeout(scrollIntoViewTimeoutRef.current);
}, [scrollIntoViewTimeoutRef]);
Expand All @@ -70,6 +87,7 @@ const SessionManagerTab: React.FC = () => {
<CurrentDeviceSection
device={currentDevice}
isLoading={isLoading}
onVerifyCurrentDevice={onVerifyCurrentDevice}
/>
{
shouldShowOtherSessions &&
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1720,6 +1720,7 @@
"This session is ready for secure messaging.": "This session is ready for secure messaging.",
"Unverified session": "Unverified session",
"Verify or sign out from this session for best security and reliability.": "Verify or sign out from this session for best security and reliability.",
"Verify session": "Verify session",
"Verified sessions": "Verified sessions",
"For best security, sign out from any session that you don't recognize or use anymore.": "For best security, sign out from any session that you don't recognize or use anymore.",
"Unverified sessions": "Unverified sessions",
Expand Down Expand Up @@ -2766,7 +2767,6 @@
"Session name": "Session name",
"Session key": "Session key",
"If they don't match, the security of your communication may be compromised.": "If they don't match, the security of your communication may be compromised.",
"Verify session": "Verify session",
"Your homeserver doesn't seem to support this feature.": "Your homeserver doesn't seem to support this feature.",
"Message edits": "Message edits",
"Modal Widget": "Modal Widget",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ describe('<CurrentDeviceSection />', () => {

const defaultProps = {
device: alicesVerifiedDevice,
onVerifyCurrentDevice: jest.fn(),
isLoading: false,
};
const getComponent = (props = {}): React.ReactElement =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,18 @@ exports[`<CurrentDeviceSection /> renders device and correct security card when
>
Verify or sign out from this session for best security and reliability.
</p>
<div
class="mx_DeviceSecurityCard_actions"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
data-testid="verification-status-button-alices_device"
role="button"
tabindex="0"
>
Verify session
</div>
</div>
</div>
</div>
</div>
Expand Down Expand Up @@ -316,6 +328,18 @@ exports[`<CurrentDeviceSection /> renders device and correct security card when
>
Verify or sign out from this session for best security and reliability.
</p>
<div
class="mx_DeviceSecurityCard_actions"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
data-testid="verification-status-button-alices_device"
role="button"
tabindex="0"
>
Verify session
</div>
</div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
getMockClientWithEventEmitter,
mockClientMethodsUser,
} from '../../../../../test-utils';
import Modal from '../../../../../../src/Modal';

jest.useFakeTimers();

Expand Down Expand Up @@ -154,6 +155,21 @@ describe('<SessionManagerTab />', () => {
expect(getByTestId('current-session-section')).toMatchSnapshot();
});

it('opens encryption setup dialog when verifiying current session', async () => {
mockClient.getDevices.mockResolvedValue({ devices: [alicesDevice, alicesMobileDevice] });
const { getByTestId } = render(getComponent());
const modalSpy = jest.spyOn(Modal, 'createDialog');

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

// click verify button from current session section
fireEvent.click(getByTestId(`verification-status-button-${alicesDevice.device_id}`));

expect(modalSpy).toHaveBeenCalled();
});

it('renders current session section with a verified session', async () => {
mockClient.getDevices.mockResolvedValue({ devices: [alicesDevice, alicesMobileDevice] });
mockClient.getStoredDevice.mockImplementation(() => new DeviceInfo(alicesDevice.device_id));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,18 @@ exports[`<SessionManagerTab /> renders current session section with an unverifie
>
Verify or sign out from this session for best security and reliability.
</p>
<div
class="mx_DeviceSecurityCard_actions"
>
<div
class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
data-testid="verification-status-button-alices_device"
role="button"
tabindex="0"
>
Verify session
</div>
</div>
</div>
</div>
</div>
Expand Down

0 comments on commit 6190477

Please sign in to comment.