diff --git a/res/css/_components.pcss b/res/css/_components.pcss index bbc6a3eadc..9805f6eae1 100644 --- a/res/css/_components.pcss +++ b/res/css/_components.pcss @@ -30,6 +30,7 @@ @import "./components/views/location/_ZoomButtons.pcss"; @import "./components/views/messages/_MBeaconBody.pcss"; @import "./components/views/messages/shared/_MediaProcessingError.pcss"; +@import "./components/views/settings/devices/_CurrentDeviceSection.pcss"; @import "./components/views/settings/devices/_DeviceDetailHeading.pcss"; @import "./components/views/settings/devices/_DeviceDetails.pcss"; @import "./components/views/settings/devices/_DeviceExpandDetailsButton.pcss"; diff --git a/res/css/components/views/settings/devices/_CurrentDeviceSection.pcss b/res/css/components/views/settings/devices/_CurrentDeviceSection.pcss new file mode 100644 index 0000000000..552270db1d --- /dev/null +++ b/res/css/components/views/settings/devices/_CurrentDeviceSection.pcss @@ -0,0 +1,20 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_CurrentDeviceSection_deviceDetails { + // align with text of session tile + margin-left: 56px; +} diff --git a/res/css/components/views/settings/devices/_DeviceDetails.pcss b/res/css/components/views/settings/devices/_DeviceDetails.pcss index 8c4aac6cbf..9b34fa378a 100644 --- a/res/css/components/views/settings/devices/_DeviceDetails.pcss +++ b/res/css/components/views/settings/devices/_DeviceDetails.pcss @@ -19,8 +19,6 @@ limitations under the License. flex-direction: column; box-sizing: border-box; - width: 100%; - margin-top: $spacing-16; padding: $spacing-24; border-radius: 8px; diff --git a/res/css/components/views/settings/devices/_FilteredDeviceList.pcss b/res/css/components/views/settings/devices/_FilteredDeviceList.pcss index d34270e8ad..9f9bd0cc71 100644 --- a/res/css/components/views/settings/devices/_FilteredDeviceList.pcss +++ b/res/css/components/views/settings/devices/_FilteredDeviceList.pcss @@ -50,3 +50,8 @@ limitations under the License. flex-direction: row; gap: $spacing-8; } + +.mx_FilteredDeviceList_deviceDetails { + // align with text of session tile + margin-left: 88px; +} diff --git a/src/components/views/settings/devices/CurrentDeviceSection.tsx b/src/components/views/settings/devices/CurrentDeviceSection.tsx index 9044f882ec..46c6f3e7d1 100644 --- a/src/components/views/settings/devices/CurrentDeviceSection.tsx +++ b/src/components/views/settings/devices/CurrentDeviceSection.tsx @@ -124,11 +124,16 @@ const CurrentDeviceSection: React.FC<Props> = ({ onVerifyDevice={onVerifyCurrentDevice} onSignOutDevice={onSignOutCurrentDevice} saveDeviceName={saveDeviceName} + className="mx_CurrentDeviceSection_deviceDetails" /> ) : ( <> <br /> - <DeviceVerificationStatusCard device={device} onVerifyDevice={onVerifyCurrentDevice} /> + <DeviceVerificationStatusCard + device={device} + onVerifyDevice={onVerifyCurrentDevice} + isCurrentDevice + /> </> )} </> diff --git a/src/components/views/settings/devices/DeviceDetails.tsx b/src/components/views/settings/devices/DeviceDetails.tsx index 7e47f83504..1793fc8b5e 100644 --- a/src/components/views/settings/devices/DeviceDetails.tsx +++ b/src/components/views/settings/devices/DeviceDetails.tsx @@ -15,6 +15,7 @@ limitations under the License. */ import React from "react"; +import classNames from "classnames"; import { IPusher } from "matrix-js-sdk/src/@types/PushRules"; import { PUSHER_ENABLED } from "matrix-js-sdk/src/@types/event"; import { LocalNotificationSettings } from "matrix-js-sdk/src/@types/local_notifications"; @@ -38,6 +39,8 @@ interface Props { saveDeviceName: (deviceName: string) => Promise<void>; setPushNotifications?: (deviceId: string, enabled: boolean) => Promise<void> | undefined; supportsMSC3881?: boolean | undefined; + className?: string; + isCurrentDevice?: boolean; } interface MetadataTable { @@ -56,6 +59,8 @@ const DeviceDetails: React.FC<Props> = ({ saveDeviceName, setPushNotifications, supportsMSC3881, + className, + isCurrentDevice, }) => { const metadata: MetadataTable[] = [ { @@ -113,10 +118,10 @@ const DeviceDetails: React.FC<Props> = ({ } return ( - <div className="mx_DeviceDetails" data-testid={`device-detail-${device.device_id}`}> + <div className={classNames("mx_DeviceDetails", className)} data-testid={`device-detail-${device.device_id}`}> <section className="mx_DeviceDetails_section"> <DeviceDetailHeading device={device} saveDeviceName={saveDeviceName} /> - <DeviceVerificationStatusCard device={device} onVerifyDevice={onVerifyDevice} /> + <DeviceVerificationStatusCard device={device} onVerifyDevice={onVerifyDevice} isCurrentDevice /> </section> <section className="mx_DeviceDetails_section"> <p className="mx_DeviceDetails_sectionHeading">{_t("Session details")}</p> diff --git a/src/components/views/settings/devices/DeviceVerificationStatusCard.tsx b/src/components/views/settings/devices/DeviceVerificationStatusCard.tsx index 6f7d71ff27..2c7af18512 100644 --- a/src/components/views/settings/devices/DeviceVerificationStatusCard.tsx +++ b/src/components/views/settings/devices/DeviceVerificationStatusCard.tsx @@ -22,25 +22,30 @@ import DeviceSecurityCard from "./DeviceSecurityCard"; import { DeviceSecurityLearnMore } from "./DeviceSecurityLearnMore"; import { DeviceSecurityVariation, ExtendedDevice } from "./types"; -interface Props { +export interface DeviceVerificationStatusCardProps { device: ExtendedDevice; + isCurrentDevice?: boolean; onVerifyDevice?: () => void; } const getCardProps = ( device: ExtendedDevice, + isCurrentDevice?: boolean, ): { variation: DeviceSecurityVariation; heading: string; description: React.ReactNode; } => { if (device.isVerified) { + const descriptionText = isCurrentDevice + ? _t("Your current session is ready for secure messaging.") + : _t("This session is ready for secure messaging."); return { variation: DeviceSecurityVariation.Verified, heading: _t("Verified session"), description: ( <> - {_t("This session is ready for secure messaging.")} + {descriptionText} <DeviceSecurityLearnMore variation={DeviceSecurityVariation.Verified} /> </> ), @@ -59,20 +64,27 @@ const getCardProps = ( }; } + const descriptionText = isCurrentDevice + ? _t("Verify your current session for enhanced secure messaging.") + : _t("Verify or sign out from this session for best security and reliability."); return { variation: DeviceSecurityVariation.Unverified, heading: _t("Unverified session"), description: ( <> - {_t("Verify or sign out from this session for best security and reliability.")} + {descriptionText} <DeviceSecurityLearnMore variation={DeviceSecurityVariation.Unverified} /> </> ), }; }; -export const DeviceVerificationStatusCard: React.FC<Props> = ({ device, onVerifyDevice }) => { - const securityCardProps = getCardProps(device); +export const DeviceVerificationStatusCard: React.FC<DeviceVerificationStatusCardProps> = ({ + device, + isCurrentDevice, + onVerifyDevice, +}) => { + const securityCardProps = getCardProps(device, isCurrentDevice); return ( <DeviceSecurityCard {...securityCardProps}> diff --git a/src/components/views/settings/devices/FilteredDeviceList.tsx b/src/components/views/settings/devices/FilteredDeviceList.tsx index 026add74a4..c31fb8ca30 100644 --- a/src/components/views/settings/devices/FilteredDeviceList.tsx +++ b/src/components/views/settings/devices/FilteredDeviceList.tsx @@ -213,6 +213,7 @@ const DeviceListItem: React.FC<{ saveDeviceName={saveDeviceName} setPushNotifications={setPushNotifications} supportsMSC3881={supportsMSC3881} + className="mx_FilteredDeviceList_deviceDetails" /> )} </li> diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 43247b0bd1..13ee074d58 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1817,9 +1817,11 @@ "Mobile session": "Mobile session", "Web session": "Web session", "Unknown session type": "Unknown session type", - "Verified session": "Verified session", + "Your current session is ready for secure messaging.": "Your current session is ready for secure messaging.", "This session is ready for secure messaging.": "This session is ready for secure messaging.", + "Verified session": "Verified session", "This session doesn't support encryption and thus can't be verified.": "This session doesn't support encryption and thus can't be verified.", + "Verify your current session for enhanced secure messaging.": "Verify your current session for enhanced secure messaging.", "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", "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.", diff --git a/test/components/views/settings/devices/DeviceVerificationStatusCard-test.tsx b/test/components/views/settings/devices/DeviceVerificationStatusCard-test.tsx new file mode 100644 index 0000000000..51af424816 --- /dev/null +++ b/test/components/views/settings/devices/DeviceVerificationStatusCard-test.tsx @@ -0,0 +1,96 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { render } from "@testing-library/react"; +import React from "react"; + +import { + DeviceVerificationStatusCard, + DeviceVerificationStatusCardProps, +} from "../../../../../src/components/views/settings/devices/DeviceVerificationStatusCard"; +import { ExtendedDevice } from "../../../../../src/components/views/settings/devices/types"; +import { DeviceType } from "../../../../../src/utils/device/parseUserAgent"; + +describe("<DeviceVerificationStatusCard />", () => { + const deviceId = "test-device"; + const unverifiedDevice: ExtendedDevice = { + device_id: deviceId, + isVerified: false, + deviceType: DeviceType.Unknown, + }; + const verifiedDevice: ExtendedDevice = { + ...unverifiedDevice, + isVerified: true, + }; + const unverifiableDevice: ExtendedDevice = { + ...unverifiedDevice, + isVerified: null, + }; + const defaultProps = { + device: unverifiedDevice, + onVerifyDevice: jest.fn(), + }; + const getComponent = (props: Partial<DeviceVerificationStatusCardProps> = {}) => ( + <DeviceVerificationStatusCard {...defaultProps} {...props} /> + ); + + const verifyButtonTestId = `verification-status-button-${deviceId}`; + + describe("for the current device", () => { + // current device uses different copy + it("renders an unverified device", () => { + const { getByText } = render(getComponent({ isCurrentDevice: true })); + expect(getByText("Verify your current session for enhanced secure messaging.")).toBeTruthy(); + }); + + it("renders an unverifiable device", () => { + const { getByText } = render( + getComponent({ + device: unverifiableDevice, + isCurrentDevice: true, + }), + ); + expect(getByText("This session doesn't support encryption and thus can't be verified.")).toBeTruthy(); + }); + + it("renders a verified device", () => { + const { getByText } = render( + getComponent({ + device: verifiedDevice, + isCurrentDevice: true, + }), + ); + expect(getByText("Your current session is ready for secure messaging.")).toBeTruthy(); + }); + }); + + it("renders an unverified device", () => { + const { container } = render(getComponent()); + expect(container).toMatchSnapshot(); + }); + + it("renders an unverifiable device", () => { + const { container, queryByTestId } = render(getComponent({ device: unverifiableDevice })); + expect(container).toMatchSnapshot(); + expect(queryByTestId(verifyButtonTestId)).toBeFalsy(); + }); + + it("renders a verified device", () => { + const { container, queryByTestId } = render(getComponent({ device: verifiedDevice })); + expect(container).toMatchSnapshot(); + expect(queryByTestId(verifyButtonTestId)).toBeFalsy(); + }); +}); diff --git a/test/components/views/settings/devices/__snapshots__/CurrentDeviceSection-test.tsx.snap b/test/components/views/settings/devices/__snapshots__/CurrentDeviceSection-test.tsx.snap index 739f559ad4..907e6396dd 100644 --- a/test/components/views/settings/devices/__snapshots__/CurrentDeviceSection-test.tsx.snap +++ b/test/components/views/settings/devices/__snapshots__/CurrentDeviceSection-test.tsx.snap @@ -3,7 +3,7 @@ exports[`<CurrentDeviceSection /> displays device details on toggle click 1`] = ` HTMLCollection [ <div - class="mx_DeviceDetails" + class="mx_DeviceDetails mx_CurrentDeviceSection_deviceDetails" data-testid="device-detail-alices_device" > <section @@ -49,7 +49,7 @@ HTMLCollection [ <p class="mx_DeviceSecurityCard_description" > - Verify or sign out from this session for best security and reliability. + Verify your current session for enhanced secure messaging. <div class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" role="button" @@ -272,7 +272,7 @@ exports[`<CurrentDeviceSection /> renders device and correct security card when <p class="mx_DeviceSecurityCard_description" > - Verify or sign out from this session for best security and reliability. + Verify your current session for enhanced secure messaging. <div class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" role="button" @@ -415,7 +415,7 @@ exports[`<CurrentDeviceSection /> renders device and correct security card when <p class="mx_DeviceSecurityCard_description" > - Verify or sign out from this session for best security and reliability. + Verify your current session for enhanced secure messaging. <div class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" role="button" diff --git a/test/components/views/settings/devices/__snapshots__/DeviceDetails-test.tsx.snap b/test/components/views/settings/devices/__snapshots__/DeviceDetails-test.tsx.snap index ff25c3a2c8..f39be8aaeb 100644 --- a/test/components/views/settings/devices/__snapshots__/DeviceDetails-test.tsx.snap +++ b/test/components/views/settings/devices/__snapshots__/DeviceDetails-test.tsx.snap @@ -49,7 +49,7 @@ exports[`<DeviceDetails /> renders a verified device 1`] = ` <p class="mx_DeviceSecurityCard_description" > - This session is ready for secure messaging. + Your current session is ready for secure messaging. <div class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" role="button" @@ -158,7 +158,7 @@ exports[`<DeviceDetails /> renders device with metadata 1`] = ` <p class="mx_DeviceSecurityCard_description" > - Verify or sign out from this session for best security and reliability. + Verify your current session for enhanced secure messaging. <div class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" role="button" @@ -367,7 +367,7 @@ exports[`<DeviceDetails /> renders device without metadata 1`] = ` <p class="mx_DeviceSecurityCard_description" > - Verify or sign out from this session for best security and reliability. + Verify your current session for enhanced secure messaging. <div class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" role="button" diff --git a/test/components/views/settings/devices/__snapshots__/DeviceVerificationStatusCard-test.tsx.snap b/test/components/views/settings/devices/__snapshots__/DeviceVerificationStatusCard-test.tsx.snap new file mode 100644 index 0000000000..6e42937c28 --- /dev/null +++ b/test/components/views/settings/devices/__snapshots__/DeviceVerificationStatusCard-test.tsx.snap @@ -0,0 +1,127 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`<DeviceVerificationStatusCard /> renders a verified device 1`] = ` +<div> + <div + class="mx_DeviceSecurityCard" + > + <div + class="mx_DeviceSecurityCard_icon Verified" + > + <div + height="16" + width="16" + /> + </div> + <div + class="mx_DeviceSecurityCard_content" + > + <p + class="mx_DeviceSecurityCard_heading" + > + Verified session + </p> + <p + class="mx_DeviceSecurityCard_description" + > + This session is ready for secure messaging. + <div + class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" + role="button" + tabindex="0" + > + Learn more + </div> + </p> + </div> + </div> +</div> +`; + +exports[`<DeviceVerificationStatusCard /> renders an unverifiable device 1`] = ` +<div> + <div + class="mx_DeviceSecurityCard" + > + <div + class="mx_DeviceSecurityCard_icon Unverified" + > + <div + height="16" + width="16" + /> + </div> + <div + class="mx_DeviceSecurityCard_content" + > + <p + class="mx_DeviceSecurityCard_heading" + > + Unverified session + </p> + <p + class="mx_DeviceSecurityCard_description" + > + This session doesn't support encryption and thus can't be verified. + <div + class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" + role="button" + tabindex="0" + > + Learn more + </div> + </p> + </div> + </div> +</div> +`; + +exports[`<DeviceVerificationStatusCard /> renders an unverified device 1`] = ` +<div> + <div + class="mx_DeviceSecurityCard" + > + <div + class="mx_DeviceSecurityCard_icon Unverified" + > + <div + height="16" + width="16" + /> + </div> + <div + class="mx_DeviceSecurityCard_content" + > + <p + class="mx_DeviceSecurityCard_heading" + > + Unverified session + </p> + <p + class="mx_DeviceSecurityCard_description" + > + Verify or sign out from this session for best security and reliability. + <div + class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" + role="button" + tabindex="0" + > + Learn more + </div> + </p> + <div + class="mx_DeviceSecurityCard_actions" + > + <div + class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary" + data-testid="verification-status-button-test-device" + role="button" + tabindex="0" + > + Verify session + </div> + </div> + </div> + </div> +</div> +`; diff --git a/test/components/views/settings/tabs/user/__snapshots__/SessionManagerTab-test.tsx.snap b/test/components/views/settings/tabs/user/__snapshots__/SessionManagerTab-test.tsx.snap index 166f54a32e..6e3fe80299 100644 --- a/test/components/views/settings/tabs/user/__snapshots__/SessionManagerTab-test.tsx.snap +++ b/test/components/views/settings/tabs/user/__snapshots__/SessionManagerTab-test.tsx.snap @@ -167,7 +167,7 @@ exports[`<SessionManagerTab /> current session section renders current session s <p class="mx_DeviceSecurityCard_description" > - This session is ready for secure messaging. + Your current session is ready for secure messaging. <div class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" role="button" @@ -296,7 +296,7 @@ exports[`<SessionManagerTab /> current session section renders current session s <p class="mx_DeviceSecurityCard_description" > - Verify or sign out from this session for best security and reliability. + Verify your current session for enhanced secure messaging. <div class="mx_AccessibleButton mx_LearnMore_button mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" role="button"