Files
web-base/react/admin-panel/src/views/profile/mfa-box.js

98 lines
3.8 KiB
JavaScript

import React, {useCallback, useContext, useState} from "react";
import {LocaleContext} from "shared/locale";
import {CheckCircle, ErrorOutline, Fingerprint, Remove} from "@mui/icons-material";
import {Box, Button, CircularProgress, FormControl, FormLabel, styled, TextField} from "@mui/material";
import SpacedFormGroup from "../../elements/form-group";
import MfaTotp from "./mfa-totp";
import MfaFido from "./mfa-fido";
import CollapseBox from "./collapse-box";
const MfaStatusBox = styled(Box)((props) => ({
display: "grid",
gridTemplateColumns: "30px auto",
}));
const MFAOptions = styled(Box)((props) => ({
"& > div": {
borderColor: props.theme.palette.divider,
borderStyle: "solid",
borderWidth: 1,
borderRadius: 5,
maxWidth: 150,
cursor: "pointer",
textAlign: "center",
display: "inline-grid",
gridTemplateRows: "130px 50px",
alignItems: "center",
padding: props.theme.spacing(1),
marginRight: props.theme.spacing(1),
"&:hover": {
backgroundColor: "lightgray",
},
"& img": {
width: "100%",
},
}
}));
export default function MultiFactorBox(props) {
// meta
const {profile, setProfile, setDialogData, api, showDialog, ...other} = props;
const {translate: L} = useContext(LocaleContext);
// data
const [mfaPassword, set2FAPassword] = useState("");
// ui
const [is2FARemoving, set2FARemoving] = useState(false);
const onRemove2FA = useCallback(() => {
if (!is2FARemoving) {
set2FARemoving(true);
api.remove2FA(mfaPassword).then(data => {
set2FARemoving(false);
set2FAPassword("");
if (!data.success) {
showDialog(data.msg, L("account.remove_2fa_error"));
} else {
setProfile({...profile, twoFactorToken: null});
}
});
}
}, [api, showDialog, is2FARemoving, mfaPassword, profile]);
return <CollapseBox title={L("account.2fa_token")}
icon={<Fingerprint />} {...other}>
{profile.twoFactorToken && profile.twoFactorToken.confirmed ?
<Box>
<MfaStatusBox mb={2}>
<CheckCircle color="info" title={L("account.two_factor_confirmed")} />
<span>{L("account.2fa_type_" + profile.twoFactorToken.type)}</span>
</MfaStatusBox>
<SpacedFormGroup>
<FormLabel>{L("account.password")}</FormLabel>
<FormControl>
<TextField variant={"outlined"} size="small"
value={mfaPassword} type={"password"}
onChange={e => set2FAPassword(e.target.value)}
placeholder={L("account.password")}
/>
</FormControl>
</SpacedFormGroup>
<Button startIcon={is2FARemoving ? <CircularProgress size={12} /> : <Remove />}
color="error" onClick={onRemove2FA}
variant="outlined" size="small"
disabled={is2FARemoving || !api.hasPermission("tfa/remove")}>
{is2FARemoving ? L("general.removing") + "…" : L("general.remove")}
</Button>
</Box> :
<MFAOptions>
<MfaTotp api={api} showDialog={showDialog} setDialogData={setDialogData}
set2FA={token => setProfile({...profile, twoFactorToken: token })} />
<MfaFido api={api} showDialog={showDialog} setDialogData={setDialogData}
set2FA={token => setProfile({...profile, twoFactorToken: token })} />
</MFAOptions>
}
</CollapseBox>
}