Device manager - security recommendations section (PSG-639) (#9179)
* display inactive status on device tile * unify DeviceSecurityVariation type, add correct icon to inactive ui * move types into type file * move DeviceSecurityVariation into types * add security recommendations section * add view all stubbed buttons * undeo debug * test security recs * remove debug * use css for card spacingpull/28788/head^2
							parent
							
								
									9eaf48b176
								
							
						
					
					
						commit
						0c5ad457f0
					
				|  | @ -31,6 +31,7 @@ | |||
| @import "./components/views/settings/devices/_DeviceSecurityCard.pcss"; | ||||
| @import "./components/views/settings/devices/_DeviceTile.pcss"; | ||||
| @import "./components/views/settings/devices/_FilteredDeviceList.pcss"; | ||||
| @import "./components/views/settings/devices/_SecurityRecommendations.pcss"; | ||||
| @import "./components/views/settings/devices/_SelectableDeviceTile.pcss"; | ||||
| @import "./components/views/settings/shared/_SettingsSubsection.pcss"; | ||||
| @import "./components/views/spaces/_QuickThemeSwitcher.pcss"; | ||||
|  |  | |||
|  | @ -0,0 +1,19 @@ | |||
| /* | ||||
| 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_SecurityRecommendations_spacing { | ||||
|     height: $spacing-16; | ||||
| } | ||||
|  | @ -20,7 +20,7 @@ import React from 'react'; | |||
| import { Icon as VerifiedIcon } from '../../../../../res/img/e2e/verified.svg'; | ||||
| import { Icon as UnverifiedIcon } from '../../../../../res/img/e2e/warning.svg'; | ||||
| import { Icon as InactiveIcon } from '../../../../../res/img/element-icons/settings/inactive.svg'; | ||||
| import { DeviceSecurityVariation } from './filter'; | ||||
| import { DeviceSecurityVariation } from './types'; | ||||
| interface Props { | ||||
|     variation: DeviceSecurityVariation; | ||||
|     heading: string; | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ import TooltipTarget from "../../elements/TooltipTarget"; | |||
| import { Alignment } from "../../elements/Tooltip"; | ||||
| import Heading from "../../typography/Heading"; | ||||
| import { INACTIVE_DEVICE_AGE_MS, isDeviceInactive } from "./filter"; | ||||
| import { DeviceWithVerification } from "./useOwnDevices"; | ||||
| import { DeviceWithVerification } from "./types"; | ||||
| export interface DeviceTileProps { | ||||
|     device: DeviceWithVerification; | ||||
|     children?: React.ReactNode; | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ import React from 'react'; | |||
| 
 | ||||
| import DeviceTile from './DeviceTile'; | ||||
| import { filterDevicesBySecurityRecommendation } from './filter'; | ||||
| import { DevicesDictionary, DeviceWithVerification } from './useOwnDevices'; | ||||
| import { DevicesDictionary, DeviceWithVerification } from './types'; | ||||
| 
 | ||||
| interface Props { | ||||
|     devices: DevicesDictionary; | ||||
|  |  | |||
|  | @ -0,0 +1,100 @@ | |||
| /* | ||||
| 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 React from 'react'; | ||||
| 
 | ||||
| import { _t } from '../../../../languageHandler'; | ||||
| import AccessibleButton from '../../elements/AccessibleButton'; | ||||
| import SettingsSubsection from '../shared/SettingsSubsection'; | ||||
| import DeviceSecurityCard from './DeviceSecurityCard'; | ||||
| import { filterDevicesBySecurityRecommendation, INACTIVE_DEVICE_AGE_MS } from './filter'; | ||||
| import { DevicesDictionary, DeviceSecurityVariation } from './types'; | ||||
| 
 | ||||
| interface Props { | ||||
|     devices: DevicesDictionary; | ||||
| } | ||||
| const MS_DAY = 24 * 60 * 60 * 1000; | ||||
| 
 | ||||
| const SecurityRecommendations: React.FC<Props> = ({ devices }) => { | ||||
|     const devicesArray = Object.values(devices); | ||||
| 
 | ||||
|     const unverifiedDevicesCount = filterDevicesBySecurityRecommendation( | ||||
|         devicesArray, | ||||
|         [DeviceSecurityVariation.Unverified], | ||||
|     ).length; | ||||
|     const inactiveDevicesCount = filterDevicesBySecurityRecommendation( | ||||
|         devicesArray, | ||||
|         [DeviceSecurityVariation.Inactive], | ||||
|     ).length; | ||||
| 
 | ||||
|     if (!(unverifiedDevicesCount | inactiveDevicesCount)) { | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     const inactiveAgeDays = INACTIVE_DEVICE_AGE_MS / MS_DAY; | ||||
| 
 | ||||
|     // TODO(kerrya) stubbed until PSG-640/652
 | ||||
|     const noop = () => {}; | ||||
| 
 | ||||
|     return <SettingsSubsection | ||||
|         heading={_t('Security recommendations')} | ||||
|         description={_t('Improve your account security by following these recommendations')} | ||||
|         data-testid='security-recommendations-section' | ||||
|     > | ||||
|         { | ||||
|             !!unverifiedDevicesCount && | ||||
|             <DeviceSecurityCard | ||||
|                 variation={DeviceSecurityVariation.Unverified} | ||||
|                 heading={_t('Unverified sessions')} | ||||
|                 description={_t( | ||||
|                     `Verify your sessions for enhanced secure messaging` + | ||||
|                     ` or sign out from those you don't recognize or use anymore.`, | ||||
|                 )} | ||||
|             > | ||||
|                 <AccessibleButton | ||||
|                     kind='link_inline' | ||||
|                     onClick={noop} | ||||
|                 > | ||||
|                     { _t('View all') + ` (${unverifiedDevicesCount})` } | ||||
|                 </AccessibleButton> | ||||
|             </DeviceSecurityCard> | ||||
|         } | ||||
|         { | ||||
|             !!inactiveDevicesCount && | ||||
|             <> | ||||
|                 { !!unverifiedDevicesCount && <div className='mx_SecurityRecommendations_spacing' /> } | ||||
|                 <DeviceSecurityCard | ||||
|                     variation={DeviceSecurityVariation.Inactive} | ||||
|                     heading={_t('Inactive sessions')} | ||||
|                     description={_t( | ||||
|                         `Consider signing out from old sessions ` + | ||||
|                         `(%(inactiveAgeDays)s days or older) you don't use anymore`, | ||||
|                         { inactiveAgeDays }, | ||||
|                     )} | ||||
|                 > | ||||
|                     <AccessibleButton | ||||
|                         kind='link_inline' | ||||
|                         onClick={noop} | ||||
|                     > | ||||
|                         { _t('View all') + ` (${inactiveDevicesCount})` } | ||||
|                     </AccessibleButton> | ||||
|                 </DeviceSecurityCard> | ||||
|             </> | ||||
|         } | ||||
|     </SettingsSubsection>; | ||||
| }; | ||||
| 
 | ||||
| export default SecurityRecommendations; | ||||
|  | @ -14,13 +14,7 @@ See the License for the specific language governing permissions and | |||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| import { DeviceWithVerification } from "./useOwnDevices"; | ||||
| 
 | ||||
| export enum DeviceSecurityVariation { | ||||
|     Verified = 'Verified', | ||||
|     Unverified = 'Unverified', | ||||
|     Inactive = 'Inactive', | ||||
| } | ||||
| import { DeviceWithVerification, DeviceSecurityVariation } from "./types"; | ||||
| 
 | ||||
| type DeviceFilterCondition = (device: DeviceWithVerification) => boolean; | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,26 @@ | |||
| /* | ||||
| 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 { IMyDevice } from "matrix-js-sdk/src/matrix"; | ||||
| 
 | ||||
| export type DeviceWithVerification = IMyDevice & { isVerified: boolean | null }; | ||||
| export type DevicesDictionary = Record<DeviceWithVerification['device_id'], DeviceWithVerification>; | ||||
| 
 | ||||
| export enum DeviceSecurityVariation { | ||||
|     Verified = 'Verified', | ||||
|     Unverified = 'Unverified', | ||||
|     Inactive = 'Inactive', | ||||
| } | ||||
|  | @ -20,8 +20,7 @@ import { CrossSigningInfo } from "matrix-js-sdk/src/crypto/CrossSigning"; | |||
| import { logger } from "matrix-js-sdk/src/logger"; | ||||
| 
 | ||||
| import MatrixClientContext from "../../../../contexts/MatrixClientContext"; | ||||
| 
 | ||||
| export type DeviceWithVerification = IMyDevice & { isVerified: boolean | null }; | ||||
| import { DevicesDictionary } from "./types"; | ||||
| 
 | ||||
| const isDeviceVerified = ( | ||||
|     matrixClient: MatrixClient, | ||||
|  | @ -56,11 +55,11 @@ const fetchDevicesWithVerification = async (matrixClient: MatrixClient): Promise | |||
| 
 | ||||
|     return devicesDict; | ||||
| }; | ||||
| 
 | ||||
| export enum OwnDevicesError { | ||||
|     Unsupported = 'Unsupported', | ||||
|     Default = 'Default', | ||||
| } | ||||
| export type DevicesDictionary = Record<DeviceWithVerification['device_id'], DeviceWithVerification>; | ||||
| type DevicesState = { | ||||
|     devices: DevicesDictionary; | ||||
|     currentDeviceId: string; | ||||
|  |  | |||
|  | @ -23,7 +23,8 @@ import DeviceTile from '../../devices/DeviceTile'; | |||
| import DeviceSecurityCard from '../../devices/DeviceSecurityCard'; | ||||
| import SettingsSubsection from '../../shared/SettingsSubsection'; | ||||
| import FilteredDeviceList from '../../devices/FilteredDeviceList'; | ||||
| import { DeviceSecurityVariation } from '../../devices/filter'; | ||||
| import { DeviceSecurityVariation } from '../../devices/types'; | ||||
| import SecurityRecommendations from '../../devices/SecurityRecommendations'; | ||||
| import SettingsTab from '../SettingsTab'; | ||||
| 
 | ||||
| const SessionManagerTab: React.FC = () => { | ||||
|  | @ -43,6 +44,7 @@ const SessionManagerTab: React.FC = () => { | |||
|     }; | ||||
| 
 | ||||
|     return <SettingsTab heading={_t('Sessions')}> | ||||
|         <SecurityRecommendations devices={devices} /> | ||||
|         <SettingsSubsection | ||||
|             heading={_t('Current session')} | ||||
|             data-testid='current-session-section' | ||||
|  |  | |||
|  | @ -1708,6 +1708,13 @@ | |||
|     "Inactive for %(inactiveAgeDays)s+ days": "Inactive for %(inactiveAgeDays)s+ days", | ||||
|     "Verified": "Verified", | ||||
|     "Unverified": "Unverified", | ||||
|     "Security recommendations": "Security recommendations", | ||||
|     "Improve your account security by following these recommendations": "Improve your account security by following these recommendations", | ||||
|     "Unverified sessions": "Unverified sessions", | ||||
|     "Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore.": "Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore.", | ||||
|     "View all": "View all", | ||||
|     "Inactive sessions": "Inactive sessions", | ||||
|     "Consider signing out from old sessions (%(inactiveAgeDays)s days or older) you don't use anymore": "Consider signing out from old sessions (%(inactiveAgeDays)s days or older) you don't use anymore", | ||||
|     "Unable to remove contact information": "Unable to remove contact information", | ||||
|     "Remove %(email)s?": "Remove %(email)s?", | ||||
|     "Invalid Email Address": "Invalid Email Address", | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ import { render } from '@testing-library/react'; | |||
| import React from 'react'; | ||||
| 
 | ||||
| import DeviceSecurityCard from '../../../../../src/components/views/settings/devices/DeviceSecurityCard'; | ||||
| import { DeviceSecurityVariation } from '../../../../../src/components/views/settings/devices/filter'; | ||||
| import { DeviceSecurityVariation } from '../../../../../src/components/views/settings/devices/types'; | ||||
| 
 | ||||
| describe('<DeviceSecurityCard />', () => { | ||||
|     const defaultProps = { | ||||
|  |  | |||
|  | @ -0,0 +1,72 @@ | |||
| /* | ||||
| 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 React from 'react'; | ||||
| import { render } from '@testing-library/react'; | ||||
| 
 | ||||
| import SecurityRecommendations from '../../../../../src/components/views/settings/devices/SecurityRecommendations'; | ||||
| 
 | ||||
| const MS_DAY = 24 * 60 * 60 * 1000; | ||||
| describe('<SecurityRecommendations />', () => { | ||||
|     const unverifiedNoMetadata = { device_id: 'unverified-no-metadata', isVerified: false }; | ||||
|     const verifiedNoMetadata = { device_id: 'verified-no-metadata', isVerified: true }; | ||||
|     const hundredDaysOld = { device_id: '100-days-old', isVerified: true, last_seen_ts: Date.now() - (MS_DAY * 100) }; | ||||
|     const hundredDaysOldUnverified = { | ||||
|         device_id: 'unverified-100-days-old', | ||||
|         isVerified: false, | ||||
|         last_seen_ts: Date.now() - (MS_DAY * 100), | ||||
|     }; | ||||
| 
 | ||||
|     const defaultProps = { | ||||
|         devices: {}, | ||||
|     }; | ||||
|     const getComponent = (props = {}) => | ||||
|         (<SecurityRecommendations {...defaultProps} {...props} />); | ||||
| 
 | ||||
|     it('renders null when no devices', () => { | ||||
|         const { container } = render(getComponent()); | ||||
|         expect(container.firstChild).toBeNull(); | ||||
|     }); | ||||
| 
 | ||||
|     it('renders unverified devices section when user has unverified devices', () => { | ||||
|         const devices = { | ||||
|             [unverifiedNoMetadata.device_id]: unverifiedNoMetadata, | ||||
|             [verifiedNoMetadata.device_id]: verifiedNoMetadata, | ||||
|             [hundredDaysOldUnverified.device_id]: hundredDaysOldUnverified, | ||||
|         }; | ||||
|         const { container } = render(getComponent({ devices })); | ||||
|         expect(container).toMatchSnapshot(); | ||||
|     }); | ||||
| 
 | ||||
|     it('renders inactive devices section when user has inactive devices', () => { | ||||
|         const devices = { | ||||
|             [verifiedNoMetadata.device_id]: verifiedNoMetadata, | ||||
|             [hundredDaysOldUnverified.device_id]: hundredDaysOldUnverified, | ||||
|         }; | ||||
|         const { container } = render(getComponent({ devices })); | ||||
|         expect(container).toMatchSnapshot(); | ||||
|     }); | ||||
| 
 | ||||
|     it('renders both cards when user has both unverified and inactive devices', () => { | ||||
|         const devices = { | ||||
|             [verifiedNoMetadata.device_id]: verifiedNoMetadata, | ||||
|             [hundredDaysOld.device_id]: hundredDaysOld, | ||||
|             [unverifiedNoMetadata.device_id]: unverifiedNoMetadata, | ||||
|         }; | ||||
|         const { container } = render(getComponent({ devices })); | ||||
|         expect(container).toMatchSnapshot(); | ||||
|     }); | ||||
| }); | ||||
|  | @ -0,0 +1,280 @@ | |||
| // Jest Snapshot v1, https://goo.gl/fbAQLP | ||||
| 
 | ||||
| exports[`<SecurityRecommendations /> renders both cards when user has both unverified and inactive devices 1`] = ` | ||||
| <div> | ||||
|   <div | ||||
|     class="mx_SettingsSubsection" | ||||
|     data-testid="security-recommendations-section" | ||||
|   > | ||||
|     <h3 | ||||
|       class="mx_Heading_h3 mx_SettingsSubsection_heading" | ||||
|     > | ||||
|       Security recommendations | ||||
|     </h3> | ||||
|     <div | ||||
|       class="mx_SettingsSubsection_description" | ||||
|     > | ||||
|       Improve your account security by following these recommendations | ||||
|     </div> | ||||
|     <div | ||||
|       class="mx_SettingsSubsection_content" | ||||
|     > | ||||
|       <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 sessions | ||||
|           </p> | ||||
|           <p | ||||
|             class="mx_DeviceSecurityCard_description" | ||||
|           > | ||||
|             Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore. | ||||
|           </p> | ||||
|           <div | ||||
|             class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" | ||||
|             role="button" | ||||
|             tabindex="0" | ||||
|           > | ||||
|             View all (1) | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div | ||||
|         class="mx_SecurityRecommendations_spacing" | ||||
|       /> | ||||
|       <div | ||||
|         class="mx_DeviceSecurityCard" | ||||
|       > | ||||
|         <div | ||||
|           class="mx_DeviceSecurityCard_icon Inactive" | ||||
|         > | ||||
|           <div | ||||
|             height="16" | ||||
|             width="16" | ||||
|           /> | ||||
|         </div> | ||||
|         <div | ||||
|           class="mx_DeviceSecurityCard_content" | ||||
|         > | ||||
|           <p | ||||
|             class="mx_DeviceSecurityCard_heading" | ||||
|           > | ||||
|             Inactive sessions | ||||
|           </p> | ||||
|           <p | ||||
|             class="mx_DeviceSecurityCard_description" | ||||
|           > | ||||
|             Consider signing out from old sessions (90 days or older) you don't use anymore | ||||
|           </p> | ||||
|           <div | ||||
|             class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" | ||||
|             role="button" | ||||
|             tabindex="0" | ||||
|           > | ||||
|             View all (1) | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
| `; | ||||
| 
 | ||||
| exports[`<SecurityRecommendations /> renders inactive devices section when user has inactive devices 1`] = ` | ||||
| <div> | ||||
|   <div | ||||
|     class="mx_SettingsSubsection" | ||||
|     data-testid="security-recommendations-section" | ||||
|   > | ||||
|     <h3 | ||||
|       class="mx_Heading_h3 mx_SettingsSubsection_heading" | ||||
|     > | ||||
|       Security recommendations | ||||
|     </h3> | ||||
|     <div | ||||
|       class="mx_SettingsSubsection_description" | ||||
|     > | ||||
|       Improve your account security by following these recommendations | ||||
|     </div> | ||||
|     <div | ||||
|       class="mx_SettingsSubsection_content" | ||||
|     > | ||||
|       <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 sessions | ||||
|           </p> | ||||
|           <p | ||||
|             class="mx_DeviceSecurityCard_description" | ||||
|           > | ||||
|             Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore. | ||||
|           </p> | ||||
|           <div | ||||
|             class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" | ||||
|             role="button" | ||||
|             tabindex="0" | ||||
|           > | ||||
|             View all (1) | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div | ||||
|         class="mx_SecurityRecommendations_spacing" | ||||
|       /> | ||||
|       <div | ||||
|         class="mx_DeviceSecurityCard" | ||||
|       > | ||||
|         <div | ||||
|           class="mx_DeviceSecurityCard_icon Inactive" | ||||
|         > | ||||
|           <div | ||||
|             height="16" | ||||
|             width="16" | ||||
|           /> | ||||
|         </div> | ||||
|         <div | ||||
|           class="mx_DeviceSecurityCard_content" | ||||
|         > | ||||
|           <p | ||||
|             class="mx_DeviceSecurityCard_heading" | ||||
|           > | ||||
|             Inactive sessions | ||||
|           </p> | ||||
|           <p | ||||
|             class="mx_DeviceSecurityCard_description" | ||||
|           > | ||||
|             Consider signing out from old sessions (90 days or older) you don't use anymore | ||||
|           </p> | ||||
|           <div | ||||
|             class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" | ||||
|             role="button" | ||||
|             tabindex="0" | ||||
|           > | ||||
|             View all (1) | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
| `; | ||||
| 
 | ||||
| exports[`<SecurityRecommendations /> renders unverified devices section when user has unverified devices 1`] = ` | ||||
| <div> | ||||
|   <div | ||||
|     class="mx_SettingsSubsection" | ||||
|     data-testid="security-recommendations-section" | ||||
|   > | ||||
|     <h3 | ||||
|       class="mx_Heading_h3 mx_SettingsSubsection_heading" | ||||
|     > | ||||
|       Security recommendations | ||||
|     </h3> | ||||
|     <div | ||||
|       class="mx_SettingsSubsection_description" | ||||
|     > | ||||
|       Improve your account security by following these recommendations | ||||
|     </div> | ||||
|     <div | ||||
|       class="mx_SettingsSubsection_content" | ||||
|     > | ||||
|       <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 sessions | ||||
|           </p> | ||||
|           <p | ||||
|             class="mx_DeviceSecurityCard_description" | ||||
|           > | ||||
|             Verify your sessions for enhanced secure messaging or sign out from those you don't recognize or use anymore. | ||||
|           </p> | ||||
|           <div | ||||
|             class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" | ||||
|             role="button" | ||||
|             tabindex="0" | ||||
|           > | ||||
|             View all (2) | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div | ||||
|         class="mx_SecurityRecommendations_spacing" | ||||
|       /> | ||||
|       <div | ||||
|         class="mx_DeviceSecurityCard" | ||||
|       > | ||||
|         <div | ||||
|           class="mx_DeviceSecurityCard_icon Inactive" | ||||
|         > | ||||
|           <div | ||||
|             height="16" | ||||
|             width="16" | ||||
|           /> | ||||
|         </div> | ||||
|         <div | ||||
|           class="mx_DeviceSecurityCard_content" | ||||
|         > | ||||
|           <p | ||||
|             class="mx_DeviceSecurityCard_heading" | ||||
|           > | ||||
|             Inactive sessions | ||||
|           </p> | ||||
|           <p | ||||
|             class="mx_DeviceSecurityCard_description" | ||||
|           > | ||||
|             Consider signing out from old sessions (90 days or older) you don't use anymore | ||||
|           </p> | ||||
|           <div | ||||
|             class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" | ||||
|             role="button" | ||||
|             tabindex="0" | ||||
|           > | ||||
|             View all (1) | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
| `; | ||||
|  | @ -15,9 +15,11 @@ limitations under the License. | |||
| */ | ||||
| 
 | ||||
| import { | ||||
|     DeviceSecurityVariation, | ||||
|     filterDevicesBySecurityRecommendation, | ||||
| } from "../../../../../src/components/views/settings/devices/filter"; | ||||
| import { | ||||
|     DeviceSecurityVariation, | ||||
| } from "../../../../../src/components/views/settings/devices/types"; | ||||
| 
 | ||||
| const MS_DAY = 86400000; | ||||
| describe('filterDevicesBySecurityRecommendation()', () => { | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Kerry
						Kerry