import {RouteComponentProps} from 'react-router'; import styled from '@emotion/styled'; import {addErrorMessage} from 'sentry/actionCreators/indicator'; import {openEmailVerification} from 'sentry/actionCreators/modal'; import {Button} from 'sentry/components/button'; import CircleIndicator from 'sentry/components/circleIndicator'; import EmptyMessage from 'sentry/components/emptyMessage'; import FieldGroup from 'sentry/components/forms/fieldGroup'; import ListLink from 'sentry/components/links/listLink'; import NavTabs from 'sentry/components/navTabs'; import Panel from 'sentry/components/panels/panel'; import PanelBody from 'sentry/components/panels/panelBody'; import PanelHeader from 'sentry/components/panels/panelHeader'; import PanelItem from 'sentry/components/panels/panelItem'; import {Tooltip} from 'sentry/components/tooltip'; import {IconDelete} from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import {Authenticator, OrganizationSummary} from 'sentry/types'; import oxfordizeArray from 'sentry/utils/oxfordizeArray'; import recreateRoute from 'sentry/utils/recreateRoute'; import DeprecatedAsyncView from 'sentry/views/deprecatedAsyncView'; import RemoveConfirm from 'sentry/views/settings/account/accountSecurity/components/removeConfirm'; import TwoFactorRequired from 'sentry/views/settings/account/accountSecurity/components/twoFactorRequired'; import PasswordForm from 'sentry/views/settings/account/passwordForm'; import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader'; import TextBlock from 'sentry/views/settings/components/text/textBlock'; type Props = { authenticators: Authenticator[] | null; countEnrolled: number; deleteDisabled: boolean; handleRefresh: () => void; hasVerifiedEmail: boolean; onDisable: (auth: Authenticator) => void; orgsRequire2fa: OrganizationSummary[]; } & DeprecatedAsyncView['props'] & RouteComponentProps<{}, {}>; /** * Lists 2fa devices + password change form */ class AccountSecurity extends DeprecatedAsyncView { getTitle() { return t('Security'); } getEndpoints(): ReturnType { return []; } handleSessionClose = async () => { try { await this.api.requestPromise('/auth/', { method: 'DELETE', data: {all: true}, }); window.location.assign('/auth/login/'); } catch (err) { addErrorMessage(t('There was a problem closing all sessions')); throw err; } }; formatOrgSlugs = () => { const {orgsRequire2fa} = this.props; const slugs = orgsRequire2fa.map(({slug}) => slug); return oxfordizeArray(slugs); }; handleAdd2FAClicked = () => { const {handleRefresh} = this.props; openEmailVerification({ onClose: () => { handleRefresh(); }, actionMessage: 'enrolling a 2FA device', }); }; renderBody() { const {authenticators, countEnrolled, deleteDisabled, onDisable, hasVerifiedEmail} = this.props; const isEmpty = !authenticators?.length; return (
{t('Settings')} {t('Session History')} } /> {!isEmpty && countEnrolled === 0 && } {t('Sessions')} {t('Two-Factor Authentication')} {isEmpty && ( {t('No available authenticators to add')} )} {!isEmpty && authenticators?.map(auth => { const { id, authId, description, isBackupInterface, isEnrolled, disallowNewEnrollment, configureButton, name, } = auth; if (disallowNewEnrollment && !isEnrolled) { return null; } return ( {name} {!isBackupInterface && !isEnrolled && hasVerifiedEmail && ( )} {!isBackupInterface && !isEnrolled && !hasVerifiedEmail && ( )} {isEnrolled && authId && ( )} {!isBackupInterface && isEnrolled && ( onDisable(auth)} disabled={deleteDisabled} >
); } } const AuthenticatorName = styled('span')` font-size: 1.2em; `; const AuthenticatorPanelItem = styled(PanelItem)` flex-direction: column; `; const AuthenticatorHeader = styled('div')` display: flex; flex: 1; align-items: center; `; const AuthenticatorTitle = styled('div')` flex: 1; `; const Actions = styled('div')` display: grid; grid-auto-flow: column; gap: ${space(1)}; `; const AuthenticatorStatus = styled(CircleIndicator)` margin-right: ${space(1)}; `; const Description = styled(TextBlock)` margin-top: ${space(2)}; margin-bottom: 0; `; export default AccountSecurity;