From 9171ba28bd7a35e740a5dd09f79b2535479ca2eb Mon Sep 17 00:00:00 2001 From: Bartosz Leper Date: Wed, 21 Feb 2024 18:56:18 +0100 Subject: [PATCH] Remove the old AddDevice dialog and substitute it with the new wizard (#38393) * Remove the old AddDevice dialog Also cleans up the accompanying local storage flag. * Rename `canAddMFA` Co-authored-by: Zac Bergquist * Update a success message Co-authored-by: Zac Bergquist * review * Review --------- Co-authored-by: Zac Bergquist --- .../teleport/src/Account/Account.story.tsx | 15 +- .../teleport/src/Account/Account.test.tsx | 6 +- web/packages/teleport/src/Account/Account.tsx | 74 +- .../AddDevice/AddDevice.story.test.tsx | 40 - .../AddDevice/AddDevice.story.tsx | 116 - .../ManageDevices/AddDevice/AddDevice.tsx | 284 --- .../AddDevice.story.test.tsx.snap | 2049 ----------------- .../Account/ManageDevices/AddDevice/index.ts | 21 - .../ManageDevices/AddDevice/useAddDevice.ts | 106 - .../Account/ManageDevices/useManageDevices.ts | 47 +- web/packages/teleport/src/config.ts | 4 + .../services/storageService/storageService.ts | 5 - .../src/services/storageService/types.ts | 4 - 13 files changed, 53 insertions(+), 2718 deletions(-) delete mode 100644 web/packages/teleport/src/Account/ManageDevices/AddDevice/AddDevice.story.test.tsx delete mode 100644 web/packages/teleport/src/Account/ManageDevices/AddDevice/AddDevice.story.tsx delete mode 100644 web/packages/teleport/src/Account/ManageDevices/AddDevice/AddDevice.tsx delete mode 100644 web/packages/teleport/src/Account/ManageDevices/AddDevice/__snapshots__/AddDevice.story.test.tsx.snap delete mode 100644 web/packages/teleport/src/Account/ManageDevices/AddDevice/index.ts delete mode 100644 web/packages/teleport/src/Account/ManageDevices/AddDevice/useAddDevice.ts diff --git a/web/packages/teleport/src/Account/Account.story.tsx b/web/packages/teleport/src/Account/Account.story.tsx index 8a5a3372a6a3e..f3af94216ff2f 100644 --- a/web/packages/teleport/src/Account/Account.story.tsx +++ b/web/packages/teleport/src/Account/Account.story.tsx @@ -31,7 +31,7 @@ export const LoadedPasskeysOff = () => ( ); -export const LoadedMfaOff = () => ; +export const LoadedMfaOff = () => ; export const LoadingDevices = () => ( null, onAddDevice: () => null, - hideAddDevice: () => null, - fetchDevices: () => null, fetchDevicesAttempt: { status: 'success' }, createRestrictedTokenAttempt: { status: '' }, deviceToRemove: null, @@ -105,12 +103,11 @@ const props: AccountProps = { hideReAuthenticate: () => null, hideRemoveDevice: () => null, isReAuthenticateVisible: false, - isAddDeviceVisible: false, isRemoveDeviceVisible: false, isSso: false, - restrictNewDeviceUsage: null, + newDeviceUsage: null, canAddPasskeys: true, - canAddMFA: true, + canAddMfa: true, devices: [ { id: '1', @@ -161,8 +158,8 @@ const props: AccountProps = { residentKey: false, }, ], - onPasskeyAdded: () => {}, + onDeviceAdded: () => {}, isReauthenticationRequired: false, - passkeyWizardVisible: false, - closePasskeyWizard: () => {}, + addDeviceWizardVisible: false, + closeAddDeviceWizard: () => {}, }; diff --git a/web/packages/teleport/src/Account/Account.test.tsx b/web/packages/teleport/src/Account/Account.test.tsx index 905b3a6d6ad1d..53b40b6af9c3e 100644 --- a/web/packages/teleport/src/Account/Account.test.tsx +++ b/web/packages/teleport/src/Account/Account.test.tsx @@ -41,17 +41,21 @@ describe('passkey + mfa button state', () => { cfg.auth.allowPasswordless = defaultPasswordless; }); + // Note: the "off" and "otp" cases don't make sense with passwordless turned + // on (the auth server wouldn't start in this configuration), but we're still + // testing them for completeness. test.each` mfa | pwdless | pkEnabled | mfaEnabled ${'on'} | ${true} | ${true} | ${true} ${'on'} | ${false} | ${false} | ${true} ${'optional'} | ${true} | ${true} | ${true} ${'optional'} | ${false} | ${false} | ${true} - ${'otp'} | ${true} | ${false} | ${true} ${'otp'} | ${false} | ${false} | ${true} + ${'otp'} | ${true} | ${true} | ${true} ${'webauthn'} | ${true} | ${true} | ${true} ${'webauthn'} | ${false} | ${false} | ${true} ${'off'} | ${false} | ${false} | ${false} + ${'off'} | ${true} | ${true} | ${false} `( '2fa($mfa) with pwdless($pwdless) = passkey($pkEnabled) mfa($mfaEnabled)', async ({ mfa, pwdless, pkEnabled, mfaEnabled }) => { diff --git a/web/packages/teleport/src/Account/Account.tsx b/web/packages/teleport/src/Account/Account.tsx index 3ebadd6aca1b6..d7b2d40de58e9 100644 --- a/web/packages/teleport/src/Account/Account.tsx +++ b/web/packages/teleport/src/Account/Account.tsx @@ -23,8 +23,6 @@ import { Attempt } from 'shared/hooks/useAttemptNext'; import * as Icon from 'design/Icon'; import { Notification, NotificationItem } from 'shared/components/Notification'; -import createMfaOptions from 'shared/utils/createMfaOptions'; - import useTeleport from 'teleport/useTeleport'; import { FeatureBox } from 'teleport/components/Layout'; import ReAuthenticate from 'teleport/components/ReAuthenticate'; @@ -38,7 +36,6 @@ import { AuthDeviceList } from './ManageDevices/AuthDeviceList/AuthDeviceList'; import useManageDevices, { State as ManageDevicesState, } from './ManageDevices/useManageDevices'; -import AddDevice from './ManageDevices/AddDevice'; import { ActionButton, Header } from './Header'; import { PasswordBox } from './PasswordBox'; import { AddAuthDeviceWizard } from './ManageDevices/AddAuthDeviceWizard'; @@ -61,32 +58,14 @@ export default function AccountPage({ enterpriseComponent }: AccountPageProps) { const isSso = ctx.storeUser.isSso(); const manageDevicesState = useManageDevices(ctx); - // Note: we are using the same logic here as the `AddDevice` component uses to - // determine whether to show various options. This creates a duplication of - // logic, but this is a quick bug fix to make sure that we don't show a dialog - // that normally would require an OTP token, but is shown in a passwordless - // context and thus can't progress. - // TODO(bl-nero): When implementing a new device enrollment dialog, refactor - // this so that the options used by both components have the same source of - // truth. - const mfaOptions = createMfaOptions({ - auth2faType: cfg.getAuth2faType(), - required: true, - }); - - const canAddPasskeys = - cfg.isPasswordlessEnabled() && - mfaOptions.some(option => option.value === 'webauthn'); - - const canAddMFA = mfaOptions.some( - option => option.value === 'otp' || option.value === 'webauthn' - ); + const canAddPasskeys = cfg.isPasswordlessEnabled(); + const canAddMfa = cfg.isMfaEnabled(); return ( @@ -96,7 +75,7 @@ export default function AccountPage({ enterpriseComponent }: AccountPageProps) { export interface AccountProps extends ManageDevicesState, AccountPageProps { isSso: boolean; canAddPasskeys: boolean; - canAddMFA: boolean; + canAddMfa: boolean; } export function Account({ @@ -105,25 +84,22 @@ export function Account({ setToken, onAddDevice, onRemoveDevice, - onPasskeyAdded, + onDeviceAdded, deviceToRemove, - fetchDevices, removeDevice, fetchDevicesAttempt, createRestrictedTokenAttempt, isReAuthenticateVisible, - isAddDeviceVisible, isRemoveDeviceVisible, - passkeyWizardVisible, + addDeviceWizardVisible, hideReAuthenticate, - hideAddDevice, hideRemoveDevice, - closePasskeyWizard, + closeAddDeviceWizard, isSso, - canAddMFA, + canAddMfa, canAddPasskeys, enterpriseComponent: EnterpriseComponent, - restrictNewDeviceUsage, + newDeviceUsage, }: AccountProps) { const passkeys = devices.filter(d => d.residentKey); const mfaDevices = devices.filter(d => !d.residentKey); @@ -131,7 +107,7 @@ export function Account({ createRestrictedTokenAttempt.status === 'processing' || fetchDevicesAttempt.status !== 'success'; const disableAddPasskey = disableAddDevice || !canAddPasskeys; - const disableAddMFA = disableAddDevice || !canAddMFA; + const disableAddMfa = disableAddDevice || !canAddMfa; const [notifications, setNotifications] = useState([]); const [prevFetchStatus, setPrevFetchStatus] = useState(''); @@ -174,9 +150,13 @@ export function Account({ addNotification('info', 'Your password has been changed.'); } - function onAddPasskeySuccess() { - addNotification('info', 'Passkey successfully saved.'); - onPasskeyAdded(); + function onAddDeviceSuccess() { + const message = + newDeviceUsage === 'passwordless' + ? 'Passkey successfully saved.' + : 'MFA device successfully saved.'; + addNotification('info', message); + onDeviceAdded(); } return ( @@ -233,9 +213,9 @@ export function Account({ showIndicator={fetchDevicesAttempt.status === 'processing'} actions={ )} - {isAddDeviceVisible && ( - - )} {EnterpriseComponent && ( )} @@ -281,13 +253,13 @@ export function Account({ /> )} - {passkeyWizardVisible && ( + {addDeviceWizardVisible && ( )} diff --git a/web/packages/teleport/src/Account/ManageDevices/AddDevice/AddDevice.story.test.tsx b/web/packages/teleport/src/Account/ManageDevices/AddDevice/AddDevice.story.test.tsx deleted file mode 100644 index 34a5365829dce..0000000000000 --- a/web/packages/teleport/src/Account/ManageDevices/AddDevice/AddDevice.story.test.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Teleport - * Copyright (C) 2023 Gravitational, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import React from 'react'; -import { render, screen } from 'design/utils/testing'; - -import { LoadedWebauthn, Failed, QrCodeFailed } from './AddDevice.story'; - -test('render dialog to add a new mfa device with webauthn as preferred type', () => { - render(); - - expect(screen.getByTestId('Modal')).toMatchSnapshot(); -}); - -test('render failed state for dialog to add a new mfa device', () => { - render(); - - expect(screen.getByTestId('Modal')).toMatchSnapshot(); -}); - -test('render failed state for fetching QR Code for dialog to add a new mfa device', () => { - render(); - - expect(screen.getByTestId('Modal')).toMatchSnapshot(); -}); diff --git a/web/packages/teleport/src/Account/ManageDevices/AddDevice/AddDevice.story.tsx b/web/packages/teleport/src/Account/ManageDevices/AddDevice/AddDevice.story.tsx deleted file mode 100644 index fee9d7b5ecd85..0000000000000 --- a/web/packages/teleport/src/Account/ManageDevices/AddDevice/AddDevice.story.tsx +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Teleport - * Copyright (C) 2023 Gravitational, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import React from 'react'; - -import { State } from './useAddDevice'; -import { AddDevice } from './AddDevice'; - -export default { - title: 'Teleport/Account/Manage Devices/Add Device Dialog', -}; - -export const LoadedWebauthn = () => ; - -export const RestrictedToPasswordless = () => ( - -); - -export const RestrictedToMFA = () => ( - -); - -export const Failed = () => ( - -); - -export const QrCodeProcessing = () => ( - -); - -export const QrCodeFailed = () => ( - -); - -const props: State = { - addDeviceAttempt: { status: '' }, - fetchQrCodeAttempt: { status: 'success' }, - addTotpDevice: () => null, - addWebauthnDevice: () => null, - clearAttempt: () => null, - onClose: () => null, - auth2faType: 'on', - isPasswordlessEnabled: true, - restrictDeviceUsage: undefined, - qrCode: - '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', -}; diff --git a/web/packages/teleport/src/Account/ManageDevices/AddDevice/AddDevice.tsx b/web/packages/teleport/src/Account/ManageDevices/AddDevice/AddDevice.tsx deleted file mode 100644 index e6f08ef6f353d..0000000000000 --- a/web/packages/teleport/src/Account/ManageDevices/AddDevice/AddDevice.tsx +++ /dev/null @@ -1,284 +0,0 @@ -/** - * Teleport - * Copyright (C) 2023 Gravitational, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -import React, { useState, useMemo } from 'react'; -import { - Text, - Flex, - Image, - ButtonPrimary, - ButtonSecondary, - Link, - Indicator, -} from 'design'; -import Dialog, { - DialogHeader, - DialogTitle, - DialogContent, - DialogFooter, -} from 'design/Dialog'; -import { Danger } from 'design/Alert'; -import FieldInput from 'shared/components/FieldInput'; -import Validation from 'shared/components/Validation'; -import { - requiredToken, - requiredField, -} from 'shared/components/Validation/rules'; -import FieldSelect from 'shared/components/FieldSelect'; - -import createMfaOptions, { MfaOption } from 'shared/utils/createMfaOptions'; - -import secKeyGraphic from 'design/assets/images/sec-key-graphic.svg'; - -import { DeviceUsage } from 'teleport/services/mfa'; -import useTeleport from 'teleport/useTeleport'; - -import useAddDevice, { State, Props } from './useAddDevice'; - -const deviceUsageOpts: DeviceusageOpt[] = [ - { - value: 'mfa', - label: 'no', - }, - { - value: 'passwordless', - label: 'yes', - }, -]; - -export default function Container(props: Props) { - const ctx = useTeleport(); - const state = useAddDevice(ctx, props); - return ( - - ); -} - -export function AddDevice({ - addDeviceAttempt, - fetchQrCodeAttempt, - addTotpDevice, - addWebauthnDevice, - clearAttempt, - onClose, - qrCode, - auth2faType, - isPasswordlessEnabled, - restrictDeviceUsage, -}: State) { - const [otpToken, setOtpToken] = useState(''); - const [deviceName, setDeviceName] = useState(''); - - const mfaOptions = useMemo( - () => createMfaOptions({ auth2faType: auth2faType, required: true }), - [] - ); - - const [mfaOption, setMfaOption] = useState(mfaOptions[0]); - const [usageOption, setUsageOption] = useState(deviceUsageOpts[0]); - - const resolvedDeviceUsage = restrictDeviceUsage ?? usageOption.value; - - function onSetMfaOption(option: MfaOption) { - setOtpToken(''); - clearAttempt(); - setMfaOption(option); - } - - function onSubmit(e: React.MouseEvent) { - e.preventDefault(); - - if (mfaOption.value === 'webauthn') { - addWebauthnDevice(deviceName, resolvedDeviceUsage); - } - if (mfaOption.value === 'otp') { - addTotpDevice(otpToken, deviceName); - } - } - - let hardwareInstructions = 'Enter a name for your hardware key.'; - if (addDeviceAttempt.status === 'processing') { - hardwareInstructions = 'Follow the prompts from your browser.'; - } - - const dialogTitle = - restrictDeviceUsage === 'passwordless' - ? 'Add New Passkey' - : 'Add New Two-Factor Device'; - - return ( - - {({ validator }) => ( - ({ width: '484px' })} - disableEscapeKeyDown={false} - onClose={onClose} - open={true} - > -
- - {dialogTitle} - - {addDeviceAttempt.status === 'failed' && ( - - {addDeviceAttempt.statusText} - - )} - {fetchQrCodeAttempt.status === 'failed' && ( - - {fetchQrCodeAttempt.statusText} - - )} - - props.theme.colors.spotBackground[0]}; - `} - > - {mfaOption.value === 'otp' && ( - <> - - {fetchQrCodeAttempt.status === 'processing' && ( - - )} - {fetchQrCodeAttempt.status === 'success' && ( - - )} - - - Scan the QR Code with any authenticator app and enter the - generated code.{' '} - - We recommend{' '} - - Authy - - . - - - - )} - {mfaOption.value === 'webauthn' && ( - <> - - {hardwareInstructions} - - )} - - {restrictDeviceUsage !== 'passwordless' && ( - - { - validator.reset(); - onSetMfaOption(o); - }} - mr={3} - isDisabled={addDeviceAttempt.status === 'processing'} - elevated={true} - /> - {mfaOption.value === 'otp' && ( - setOtpToken(e.target.value)} - placeholder="123 456" - readonly={addDeviceAttempt.status === 'processing'} - /> - )} - {mfaOption.value === 'webauthn' && - isPasswordlessEnabled && - !restrictDeviceUsage && ( - setUsageOption(o)} - isDisabled={addDeviceAttempt.status === 'processing'} - elevated={true} - /> - )} - - )} - setDeviceName(e.target.value)} - readonly={addDeviceAttempt.status === 'processing'} - mb={1} - /> - - - validator.validate() && onSubmit(e)} - disabled={addDeviceAttempt.status === 'processing'} - mr={3} - > - Add device - - - Cancel - - -
-
- )} -
- ); -} - -type DeviceusageOpt = { value: DeviceUsage; label: string }; diff --git a/web/packages/teleport/src/Account/ManageDevices/AddDevice/__snapshots__/AddDevice.story.test.tsx.snap b/web/packages/teleport/src/Account/ManageDevices/AddDevice/__snapshots__/AddDevice.story.test.tsx.snap deleted file mode 100644 index 8e4d977134c0a..0000000000000 --- a/web/packages/teleport/src/Account/ManageDevices/AddDevice/__snapshots__/AddDevice.story.test.tsx.snap +++ /dev/null @@ -1,2049 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`render dialog to add a new mfa device with webauthn as preferred type 1`] = ` -.c4 { - box-sizing: border-box; - margin-bottom: 16px; - min-height: 32px; -} - -.c7 { - box-sizing: border-box; - margin-bottom: 32px; - flex: 1; -} - -.c9 { - box-sizing: border-box; - margin-bottom: 24px; - padding: 16px; - height: 256px; - border-radius: 8px; -} - -.c14 { - box-sizing: border-box; -} - -.c15 { - box-sizing: border-box; - max-width: 50%; - margin-bottom: 24px; - margin-right: 16px; - width: 100%; -} - -.c18 { - box-sizing: border-box; - margin-bottom: 24px; - width: 50%; -} - -.c19 { - box-sizing: border-box; - margin-bottom: 4px; - width: 100%; -} - -.c22 { - line-height: 1.5; - margin: 0; - display: inline-flex; - justify-content: center; - align-items: center; - box-sizing: border-box; - border: none; - border-radius: 4px; - cursor: pointer; - font-family: inherit; - font-weight: 600; - outline: none; - position: relative; - text-align: center; - text-decoration: none; - text-transform: uppercase; - transition: all 0.3s; - -webkit-font-smoothing: antialiased; - color: #000000; - background: #9F85FF; - min-height: 40px; - font-size: 12px; - padding: 0px 40px; - margin-right: 16px; - width: 45%; -} - -.c22:hover, -.c22:focus { - background: #B29DFF; -} - -.c22:active { - background: #C5B6FF; -} - -.c22:disabled { - background: rgba(255,255,255,0.12); - color: rgba(255,255,255,0.3); - cursor: auto; -} - -.c23 { - line-height: 1.5; - margin: 0; - display: inline-flex; - justify-content: center; - align-items: center; - box-sizing: border-box; - border: none; - border-radius: 4px; - cursor: pointer; - font-family: inherit; - font-weight: 600; - outline: none; - position: relative; - text-align: center; - text-decoration: none; - text-transform: uppercase; - transition: all 0.3s; - -webkit-font-smoothing: antialiased; - color: #FFFFFF; - background: rgba(255,255,255,0.07); - min-height: 40px; - font-size: 12px; - padding: 0px 40px; - width: 30%; -} - -.c23:hover, -.c23:focus { - background: rgba(255,255,255,0.13); -} - -.c23:active { - background: rgba(255,255,255,0.18); -} - -.c23:disabled { - background: rgba(255,255,255,0.12); - color: rgba(255,255,255,0.3); - cursor: auto; -} - -.c6 { - overflow: hidden; - text-overflow: ellipsis; - font-weight: 300; - font-size: 22px; - line-height: 32px; - text-transform: uppercase; - margin: 0px; - color: #FFFFFF; -} - -.c13 { - overflow: hidden; - text-overflow: ellipsis; - margin: 0px; - margin-top: 16px; -} - -.c21 { - appearance: none; - border: 1px solid rgba(255,255,255,0.54); - border-radius: 4px; - box-sizing: border-box; - display: block; - height: 40px; - font-size: 16px; - padding: 0 16px; - outline: none; - width: 100%; - background: #222C59; - color: #FFFFFF; - margin-top: 4px; -} - -.c21:hover, -.c21:focus, -.c21:active { - border: 1px solid rgba(255,255,255,0.72); -} - -.c21::-ms-clear { - display: none; -} - -.c21::placeholder { - color: rgba(255,255,255,0.54); - opacity: 1; -} - -.c21:read-only { - cursor: not-allowed; -} - -.c21:disabled { - color: rgba(255,255,255,0.36); - border-color: rgba(255,255,255,0.36); -} - -.c16 { - color: #FFFFFF; - display: block; - font-size: 12px; - width: 100%; - margin-bottom: 4px; -} - -.c20 { - color: #FFFFFF; - display: block; - font-size: 12px; - width: 100%; - margin-bottom: 0px; -} - -.c12 { - display: block; - outline: none; - height: 168px; -} - -.c5 { - display: flex; - align-items: center; -} - -.c8 { - display: flex; - flex-direction: column; -} - -.c10 { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; -} - -.c1 { - z-index: -1; - position: fixed; - right: 0; - bottom: 0; - top: 0; - left: 0; - background-color: rgba(0,0,0,0.5); - opacity: 1; - touch-action: none; -} - -.c0 { - position: fixed; - z-index: 1200; - right: 0; - bottom: 0; - top: 0; - left: 0; -} - -.c2 { - height: 100%; - outline: none; - color: black; - display: flex; - align-items: center; - justify-content: center; - opacity: 1; - will-change: opacity; - transition: opacity 225ms cubic-bezier(0.4,0,0.2,1) 0ms; -} - -.c3 { - padding: 32px; - padding-top: 24px; - background: #222C59; - color: #FFFFFF; - border-radius: 8px; - box-shadow: 0 8px 32px rgba(0,0,0,0.24); - display: flex; - flex-direction: column; - position: relative; - overflow-y: auto; - max-height: calc(100% - 96px); - width: 484px; -} - -.c17 .react-select-container { - box-sizing: border-box; - display: block; - font-size: 14px; - outline: none; - width: 100%; - color: #FFFFFF; - background-color: transparent; - margin-bottom: 0px; - border-radius: 4px; -} - -.c17 .react-select__control { - outline: none; - min-height: 40px; - height: fit-content; - border: 1px solid rgba(255,255,255,0.54); - border-radius: 4px; - background-color: transparent; - box-shadow: none; -} - -.c17 .react-select__control .react-select__dropdown-indicator { - color: rgba(255,255,255,0.54); -} - -.c17 .react-select__control:hover, -.c17 .react-select__control:focus, -.c17 .react-select__control:active { - border: 1px solid rgba(255,255,255,0.72); - background-color: rgba(255,255,255,0.07); - cursor: pointer; -} - -.c17 .react-select__control:hover .react-select__dropdown-indicator, -.c17 .react-select__control:focus .react-select__dropdown-indicator, -.c17 .react-select__control:active .react-select__dropdown-indicator { - color: #FFFFFF; -} - -.c17 .react-select__control .react-select__indicator:hover, -.c17 .react-select__control .react-select__dropdown-indicator:hover, -.c17 .react-select__control .react-select__indicator:focus, -.c17 .react-select__control .react-select__dropdown-indicator:focus, -.c17 .react-select__control .react-select__indicator:active, -.c17 .react-select__control .react-select__dropdown-indicator:active { - color: #FFFFFF; -} - -.c17 .react-select__control--is-focused { - border-color: rgba(255,255,255,0.72); - background-color: rgba(255,255,255,0.07); - cursor: pointer; -} - -.c17 .react-select__control--is-focused .react-select__dropdown-indicator { - color: #FFFFFF; -} - -.c17 .react-select__single-value { - color: #FFFFFF; -} - -.c17 .react-select__placeholder { - color: rgba(255,255,255,0.54); -} - -.c17 .react-select__multi-value { - background-color: rgba(255,255,255,0.13); -} - -.c17 .react-select__multi-value .react-select__multi-value__label { - color: #FFFFFF; - padding: 0 6px; -} - -.c17 .react-select__multi-value .react-select__multi-value__remove { - color: #FFFFFF; -} - -.c17 .react-select__multi-value .react-select__multi-value__remove:hover { - background-color: rgba(255,255,255,0.07); - color: #FF6257; -} - -.c17 .react-select__option:hover { - cursor: pointer; - background-color: rgba(255,255,255,0.07); -} - -.c17 .react-select__option--is-focused { - background-color: rgba(255,255,255,0.07); -} - -.c17 .react-select__option--is-focused:hover { - cursor: pointer; - background-color: rgba(255,255,255,0.07); -} - -.c17 .react-select__option--is-selected { - background-color: rgba(255,255,255,0.13); - color: inherit; - font-weight: 500; -} - -.c17 .react-select__option--is-selected:hover { - background-color: rgba(255,255,255,0.13); -} - -.c17 .react-select__clear-indicator { - color: rgba(255,255,255,0.72); -} - -.c17 .react-select__clear-indicator:hover, -.c17 .react-select__clear-indicator:focus { - background-color: rgba(255,255,255,0.07); -} - -.c17 .react-select__clear-indicator:hover svg, -.c17 .react-select__clear-indicator:focus svg { - color: #FF6257; -} - -.c17 .react-select__menu { - margin-top: 0px; - background-color: #4A5688; - box-shadow: 0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12); -} - -.c17 .react-select__menu .react-select__menu-list::-webkit-scrollbar-thumb { - background: rgba(255,255,255,0.13); - border-radius: 4px; -} - -.c17 .react-select__indicator-separator { - display: none; -} - -.c17 .react-select__loading-indicator { - display: none; -} - -.c17 .react-select__control--is-disabled { - color: rgba(255,255,255,0.36); - border: 1px solid rgba(255,255,255,0.36); -} - -.c17 .react-select__control--is-disabled .react-select__single-value, -.c17 .react-select__control--is-disabled .react-select__placeholder { - color: rgba(255,255,255,0.36); -} - -.c17 .react-select__control--is-disabled .react-select__indicator { - color: rgba(255,255,255,0.36); -} - -.c17 .react-select__input { - color: #FFFFFF; -} - -.c11 { - background: rgba(255,255,255,0.07); -} - -
- -`; - -exports[`render failed state for dialog to add a new mfa device 1`] = ` -.c7 { - display: flex; - align-items: center; - justify-content: center; - border-radius: 2px; - box-sizing: border-box; - box-shadow: 0 1px 4px rgba(0,0,0,0.24); - margin: 0 0 24px 0; - min-height: 40px; - padding: 8px 16px; - overflow: auto; - word-break: break-word; - line-height: 1.5; - margin-top: 8px; - background: #FF6257; - color: #000000; - width: 100%; -} - -.c7 a { - color: #FFFFFF; -} - -.c4 { - box-sizing: border-box; - margin-bottom: 16px; - min-height: 32px; -} - -.c8 { - box-sizing: border-box; - margin-bottom: 32px; - flex: 1; -} - -.c10 { - box-sizing: border-box; - margin-bottom: 24px; - padding: 16px; - height: 256px; - border-radius: 8px; -} - -.c15 { - box-sizing: border-box; -} - -.c16 { - box-sizing: border-box; - max-width: 50%; - margin-bottom: 24px; - margin-right: 16px; - width: 100%; -} - -.c19 { - box-sizing: border-box; - margin-bottom: 24px; - width: 50%; -} - -.c20 { - box-sizing: border-box; - margin-bottom: 4px; - width: 100%; -} - -.c23 { - line-height: 1.5; - margin: 0; - display: inline-flex; - justify-content: center; - align-items: center; - box-sizing: border-box; - border: none; - border-radius: 4px; - cursor: pointer; - font-family: inherit; - font-weight: 600; - outline: none; - position: relative; - text-align: center; - text-decoration: none; - text-transform: uppercase; - transition: all 0.3s; - -webkit-font-smoothing: antialiased; - color: #000000; - background: #9F85FF; - min-height: 40px; - font-size: 12px; - padding: 0px 40px; - margin-right: 16px; - width: 45%; -} - -.c23:hover, -.c23:focus { - background: #B29DFF; -} - -.c23:active { - background: #C5B6FF; -} - -.c23:disabled { - background: rgba(255,255,255,0.12); - color: rgba(255,255,255,0.3); - cursor: auto; -} - -.c24 { - line-height: 1.5; - margin: 0; - display: inline-flex; - justify-content: center; - align-items: center; - box-sizing: border-box; - border: none; - border-radius: 4px; - cursor: pointer; - font-family: inherit; - font-weight: 600; - outline: none; - position: relative; - text-align: center; - text-decoration: none; - text-transform: uppercase; - transition: all 0.3s; - -webkit-font-smoothing: antialiased; - color: #FFFFFF; - background: rgba(255,255,255,0.07); - min-height: 40px; - font-size: 12px; - padding: 0px 40px; - width: 30%; -} - -.c24:hover, -.c24:focus { - background: rgba(255,255,255,0.13); -} - -.c24:active { - background: rgba(255,255,255,0.18); -} - -.c24:disabled { - background: rgba(255,255,255,0.12); - color: rgba(255,255,255,0.3); - cursor: auto; -} - -.c6 { - overflow: hidden; - text-overflow: ellipsis; - font-weight: 300; - font-size: 22px; - line-height: 32px; - text-transform: uppercase; - margin: 0px; - color: #FFFFFF; -} - -.c14 { - overflow: hidden; - text-overflow: ellipsis; - margin: 0px; - margin-top: 16px; -} - -.c22 { - appearance: none; - border: 1px solid rgba(255,255,255,0.54); - border-radius: 4px; - box-sizing: border-box; - display: block; - height: 40px; - font-size: 16px; - padding: 0 16px; - outline: none; - width: 100%; - background: #222C59; - color: #FFFFFF; - margin-top: 4px; -} - -.c22:hover, -.c22:focus, -.c22:active { - border: 1px solid rgba(255,255,255,0.72); -} - -.c22::-ms-clear { - display: none; -} - -.c22::placeholder { - color: rgba(255,255,255,0.54); - opacity: 1; -} - -.c22:read-only { - cursor: not-allowed; -} - -.c22:disabled { - color: rgba(255,255,255,0.36); - border-color: rgba(255,255,255,0.36); -} - -.c17 { - color: #FFFFFF; - display: block; - font-size: 12px; - width: 100%; - margin-bottom: 4px; -} - -.c21 { - color: #FFFFFF; - display: block; - font-size: 12px; - width: 100%; - margin-bottom: 0px; -} - -.c13 { - display: block; - outline: none; - height: 168px; -} - -.c5 { - display: flex; - align-items: center; -} - -.c9 { - display: flex; - flex-direction: column; -} - -.c11 { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; -} - -.c1 { - z-index: -1; - position: fixed; - right: 0; - bottom: 0; - top: 0; - left: 0; - background-color: rgba(0,0,0,0.5); - opacity: 1; - touch-action: none; -} - -.c0 { - position: fixed; - z-index: 1200; - right: 0; - bottom: 0; - top: 0; - left: 0; -} - -.c2 { - height: 100%; - outline: none; - color: black; - display: flex; - align-items: center; - justify-content: center; - opacity: 1; - will-change: opacity; - transition: opacity 225ms cubic-bezier(0.4,0,0.2,1) 0ms; -} - -.c3 { - padding: 32px; - padding-top: 24px; - background: #222C59; - color: #FFFFFF; - border-radius: 8px; - box-shadow: 0 8px 32px rgba(0,0,0,0.24); - display: flex; - flex-direction: column; - position: relative; - overflow-y: auto; - max-height: calc(100% - 96px); - width: 484px; -} - -.c18 .react-select-container { - box-sizing: border-box; - display: block; - font-size: 14px; - outline: none; - width: 100%; - color: #FFFFFF; - background-color: transparent; - margin-bottom: 0px; - border-radius: 4px; -} - -.c18 .react-select__control { - outline: none; - min-height: 40px; - height: fit-content; - border: 1px solid rgba(255,255,255,0.54); - border-radius: 4px; - background-color: transparent; - box-shadow: none; -} - -.c18 .react-select__control .react-select__dropdown-indicator { - color: rgba(255,255,255,0.54); -} - -.c18 .react-select__control:hover, -.c18 .react-select__control:focus, -.c18 .react-select__control:active { - border: 1px solid rgba(255,255,255,0.72); - background-color: rgba(255,255,255,0.07); - cursor: pointer; -} - -.c18 .react-select__control:hover .react-select__dropdown-indicator, -.c18 .react-select__control:focus .react-select__dropdown-indicator, -.c18 .react-select__control:active .react-select__dropdown-indicator { - color: #FFFFFF; -} - -.c18 .react-select__control .react-select__indicator:hover, -.c18 .react-select__control .react-select__dropdown-indicator:hover, -.c18 .react-select__control .react-select__indicator:focus, -.c18 .react-select__control .react-select__dropdown-indicator:focus, -.c18 .react-select__control .react-select__indicator:active, -.c18 .react-select__control .react-select__dropdown-indicator:active { - color: #FFFFFF; -} - -.c18 .react-select__control--is-focused { - border-color: rgba(255,255,255,0.72); - background-color: rgba(255,255,255,0.07); - cursor: pointer; -} - -.c18 .react-select__control--is-focused .react-select__dropdown-indicator { - color: #FFFFFF; -} - -.c18 .react-select__single-value { - color: #FFFFFF; -} - -.c18 .react-select__placeholder { - color: rgba(255,255,255,0.54); -} - -.c18 .react-select__multi-value { - background-color: rgba(255,255,255,0.13); -} - -.c18 .react-select__multi-value .react-select__multi-value__label { - color: #FFFFFF; - padding: 0 6px; -} - -.c18 .react-select__multi-value .react-select__multi-value__remove { - color: #FFFFFF; -} - -.c18 .react-select__multi-value .react-select__multi-value__remove:hover { - background-color: rgba(255,255,255,0.07); - color: #FF6257; -} - -.c18 .react-select__option:hover { - cursor: pointer; - background-color: rgba(255,255,255,0.07); -} - -.c18 .react-select__option--is-focused { - background-color: rgba(255,255,255,0.07); -} - -.c18 .react-select__option--is-focused:hover { - cursor: pointer; - background-color: rgba(255,255,255,0.07); -} - -.c18 .react-select__option--is-selected { - background-color: rgba(255,255,255,0.13); - color: inherit; - font-weight: 500; -} - -.c18 .react-select__option--is-selected:hover { - background-color: rgba(255,255,255,0.13); -} - -.c18 .react-select__clear-indicator { - color: rgba(255,255,255,0.72); -} - -.c18 .react-select__clear-indicator:hover, -.c18 .react-select__clear-indicator:focus { - background-color: rgba(255,255,255,0.07); -} - -.c18 .react-select__clear-indicator:hover svg, -.c18 .react-select__clear-indicator:focus svg { - color: #FF6257; -} - -.c18 .react-select__menu { - margin-top: 0px; - background-color: #4A5688; - box-shadow: 0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12); -} - -.c18 .react-select__menu .react-select__menu-list::-webkit-scrollbar-thumb { - background: rgba(255,255,255,0.13); - border-radius: 4px; -} - -.c18 .react-select__indicator-separator { - display: none; -} - -.c18 .react-select__loading-indicator { - display: none; -} - -.c18 .react-select__control--is-disabled { - color: rgba(255,255,255,0.36); - border: 1px solid rgba(255,255,255,0.36); -} - -.c18 .react-select__control--is-disabled .react-select__single-value, -.c18 .react-select__control--is-disabled .react-select__placeholder { - color: rgba(255,255,255,0.36); -} - -.c18 .react-select__control--is-disabled .react-select__indicator { - color: rgba(255,255,255,0.36); -} - -.c18 .react-select__input { - color: #FFFFFF; -} - -.c12 { - background: rgba(255,255,255,0.07); -} - -
- -`; - -exports[`render failed state for fetching QR Code for dialog to add a new mfa device 1`] = ` -.c7 { - display: flex; - align-items: center; - justify-content: center; - border-radius: 2px; - box-sizing: border-box; - box-shadow: 0 1px 4px rgba(0,0,0,0.24); - margin: 0 0 24px 0; - min-height: 40px; - padding: 8px 16px; - overflow: auto; - word-break: break-word; - line-height: 1.5; - margin-top: 8px; - background: #FF6257; - color: #000000; - width: 100%; -} - -.c7 a { - color: #FFFFFF; -} - -.c4 { - box-sizing: border-box; - margin-bottom: 16px; - min-height: 32px; -} - -.c8 { - box-sizing: border-box; - margin-bottom: 32px; - flex: 1; -} - -.c10 { - box-sizing: border-box; - margin-bottom: 24px; - padding: 16px; - height: 256px; - border-radius: 8px; -} - -.c13 { - box-sizing: border-box; - height: 168px; -} - -.c18 { - box-sizing: border-box; -} - -.c19 { - box-sizing: border-box; - max-width: 50%; - margin-bottom: 24px; - margin-right: 16px; - width: 100%; -} - -.c22 { - box-sizing: border-box; - margin-bottom: 24px; - width: 50%; -} - -.c25 { - box-sizing: border-box; - margin-bottom: 4px; - width: 100%; -} - -.c26 { - line-height: 1.5; - margin: 0; - display: inline-flex; - justify-content: center; - align-items: center; - box-sizing: border-box; - border: none; - border-radius: 4px; - cursor: pointer; - font-family: inherit; - font-weight: 600; - outline: none; - position: relative; - text-align: center; - text-decoration: none; - text-transform: uppercase; - transition: all 0.3s; - -webkit-font-smoothing: antialiased; - color: #000000; - background: #9F85FF; - min-height: 40px; - font-size: 12px; - padding: 0px 40px; - margin-right: 16px; - width: 45%; -} - -.c26:hover, -.c26:focus { - background: #B29DFF; -} - -.c26:active { - background: #C5B6FF; -} - -.c26:disabled { - background: rgba(255,255,255,0.12); - color: rgba(255,255,255,0.3); - cursor: auto; -} - -.c27 { - line-height: 1.5; - margin: 0; - display: inline-flex; - justify-content: center; - align-items: center; - box-sizing: border-box; - border: none; - border-radius: 4px; - cursor: pointer; - font-family: inherit; - font-weight: 600; - outline: none; - position: relative; - text-align: center; - text-decoration: none; - text-transform: uppercase; - transition: all 0.3s; - -webkit-font-smoothing: antialiased; - color: #FFFFFF; - background: rgba(255,255,255,0.07); - min-height: 40px; - font-size: 12px; - padding: 0px 40px; - width: 30%; -} - -.c27:hover, -.c27:focus { - background: rgba(255,255,255,0.13); -} - -.c27:active { - background: rgba(255,255,255,0.18); -} - -.c27:disabled { - background: rgba(255,255,255,0.12); - color: rgba(255,255,255,0.3); - cursor: auto; -} - -.c6 { - overflow: hidden; - text-overflow: ellipsis; - font-weight: 300; - font-size: 22px; - line-height: 32px; - text-transform: uppercase; - margin: 0px; - color: #FFFFFF; -} - -.c15 { - overflow: hidden; - text-overflow: ellipsis; - font-size: 12px; - margin: 0px; - margin-top: 8px; - text-align: center; -} - -.c16 { - overflow: hidden; - text-overflow: ellipsis; - margin: 0px; - color: rgba(255,255,255,0.72); -} - -.c24 { - appearance: none; - border: 1px solid rgba(255,255,255,0.54); - border-radius: 4px; - box-sizing: border-box; - display: block; - height: 40px; - font-size: 16px; - padding: 0 16px; - outline: none; - width: 100%; - background: #222C59; - color: #FFFFFF; - margin-top: 4px; -} - -.c24:hover, -.c24:focus, -.c24:active { - border: 1px solid rgba(255,255,255,0.72); -} - -.c24::-ms-clear { - display: none; -} - -.c24::placeholder { - color: rgba(255,255,255,0.54); - opacity: 1; -} - -.c24:read-only { - cursor: not-allowed; -} - -.c24:disabled { - color: rgba(255,255,255,0.36); - border-color: rgba(255,255,255,0.36); -} - -.c20 { - color: #FFFFFF; - display: block; - font-size: 12px; - width: 100%; - margin-bottom: 4px; -} - -.c23 { - color: #FFFFFF; - display: block; - font-size: 12px; - width: 100%; - margin-bottom: 0px; -} - -.c17 { - color: #009EFF; - font-weight: normal; - background: none; - text-decoration: underline; - text-transform: none; -} - -.c5 { - display: flex; - align-items: center; -} - -.c9 { - display: flex; - flex-direction: column; -} - -.c11 { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; -} - -.c14 { - display: flex; - align-items: center; - justify-content: center; -} - -.c1 { - z-index: -1; - position: fixed; - right: 0; - bottom: 0; - top: 0; - left: 0; - background-color: rgba(0,0,0,0.5); - opacity: 1; - touch-action: none; -} - -.c0 { - position: fixed; - z-index: 1200; - right: 0; - bottom: 0; - top: 0; - left: 0; -} - -.c2 { - height: 100%; - outline: none; - color: black; - display: flex; - align-items: center; - justify-content: center; - opacity: 1; - will-change: opacity; - transition: opacity 225ms cubic-bezier(0.4,0,0.2,1) 0ms; -} - -.c3 { - padding: 32px; - padding-top: 24px; - background: #222C59; - color: #FFFFFF; - border-radius: 8px; - box-shadow: 0 8px 32px rgba(0,0,0,0.24); - display: flex; - flex-direction: column; - position: relative; - overflow-y: auto; - max-height: calc(100% - 96px); - width: 484px; -} - -.c21 .react-select-container { - box-sizing: border-box; - display: block; - font-size: 14px; - outline: none; - width: 100%; - color: #FFFFFF; - background-color: transparent; - margin-bottom: 0px; - border-radius: 4px; -} - -.c21 .react-select__control { - outline: none; - min-height: 40px; - height: fit-content; - border: 1px solid rgba(255,255,255,0.54); - border-radius: 4px; - background-color: transparent; - box-shadow: none; -} - -.c21 .react-select__control .react-select__dropdown-indicator { - color: rgba(255,255,255,0.54); -} - -.c21 .react-select__control:hover, -.c21 .react-select__control:focus, -.c21 .react-select__control:active { - border: 1px solid rgba(255,255,255,0.72); - background-color: rgba(255,255,255,0.07); - cursor: pointer; -} - -.c21 .react-select__control:hover .react-select__dropdown-indicator, -.c21 .react-select__control:focus .react-select__dropdown-indicator, -.c21 .react-select__control:active .react-select__dropdown-indicator { - color: #FFFFFF; -} - -.c21 .react-select__control .react-select__indicator:hover, -.c21 .react-select__control .react-select__dropdown-indicator:hover, -.c21 .react-select__control .react-select__indicator:focus, -.c21 .react-select__control .react-select__dropdown-indicator:focus, -.c21 .react-select__control .react-select__indicator:active, -.c21 .react-select__control .react-select__dropdown-indicator:active { - color: #FFFFFF; -} - -.c21 .react-select__control--is-focused { - border-color: rgba(255,255,255,0.72); - background-color: rgba(255,255,255,0.07); - cursor: pointer; -} - -.c21 .react-select__control--is-focused .react-select__dropdown-indicator { - color: #FFFFFF; -} - -.c21 .react-select__single-value { - color: #FFFFFF; -} - -.c21 .react-select__placeholder { - color: rgba(255,255,255,0.54); -} - -.c21 .react-select__multi-value { - background-color: rgba(255,255,255,0.13); -} - -.c21 .react-select__multi-value .react-select__multi-value__label { - color: #FFFFFF; - padding: 0 6px; -} - -.c21 .react-select__multi-value .react-select__multi-value__remove { - color: #FFFFFF; -} - -.c21 .react-select__multi-value .react-select__multi-value__remove:hover { - background-color: rgba(255,255,255,0.07); - color: #FF6257; -} - -.c21 .react-select__option:hover { - cursor: pointer; - background-color: rgba(255,255,255,0.07); -} - -.c21 .react-select__option--is-focused { - background-color: rgba(255,255,255,0.07); -} - -.c21 .react-select__option--is-focused:hover { - cursor: pointer; - background-color: rgba(255,255,255,0.07); -} - -.c21 .react-select__option--is-selected { - background-color: rgba(255,255,255,0.13); - color: inherit; - font-weight: 500; -} - -.c21 .react-select__option--is-selected:hover { - background-color: rgba(255,255,255,0.13); -} - -.c21 .react-select__clear-indicator { - color: rgba(255,255,255,0.72); -} - -.c21 .react-select__clear-indicator:hover, -.c21 .react-select__clear-indicator:focus { - background-color: rgba(255,255,255,0.07); -} - -.c21 .react-select__clear-indicator:hover svg, -.c21 .react-select__clear-indicator:focus svg { - color: #FF6257; -} - -.c21 .react-select__menu { - margin-top: 0px; - background-color: #4A5688; - box-shadow: 0px 5px 5px -3px rgba(0,0,0,0.2),0px 8px 10px 1px rgba(0,0,0,0.14),0px 3px 14px 2px rgba(0,0,0,0.12); -} - -.c21 .react-select__menu .react-select__menu-list::-webkit-scrollbar-thumb { - background: rgba(255,255,255,0.13); - border-radius: 4px; -} - -.c21 .react-select__indicator-separator { - display: none; -} - -.c21 .react-select__loading-indicator { - display: none; -} - -.c21 .react-select__control--is-disabled { - color: rgba(255,255,255,0.36); - border: 1px solid rgba(255,255,255,0.36); -} - -.c21 .react-select__control--is-disabled .react-select__single-value, -.c21 .react-select__control--is-disabled .react-select__placeholder { - color: rgba(255,255,255,0.36); -} - -.c21 .react-select__control--is-disabled .react-select__indicator { - color: rgba(255,255,255,0.36); -} - -.c21 .react-select__input { - color: #FFFFFF; -} - -.c12 { - background: rgba(255,255,255,0.07); -} - -
-