mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-04 13:20:19 +08:00
feat: add TOTP multi-factor authentication (#2014)
* feat: add totp multi-factor authentication * feat: add license * feat:i18n and update yarn.lock * feat:i18n * fix: i18n
This commit is contained in:
@ -16,8 +16,8 @@ import React, {useState} from "react";
|
||||
import i18next from "i18next";
|
||||
import {Button, Input} from "antd";
|
||||
import * as AuthBackend from "./AuthBackend";
|
||||
import {EmailMfaType, SmsMfaType} from "./MfaSetupPage";
|
||||
import {MfaSmsVerifyForm, mfaAuth} from "./MfaVerifyForm";
|
||||
import {EmailMfaType, RecoveryMfaType, SmsMfaType} from "./MfaSetupPage";
|
||||
import {MfaSmsVerifyForm, MfaTotpVerifyForm, mfaAuth} from "./MfaVerifyForm";
|
||||
|
||||
export const NextMfa = "NextMfa";
|
||||
export const RequiredMfa = "RequiredMfa";
|
||||
@ -60,7 +60,7 @@ export function MfaAuthVerifyForm({formValues, oAuthParams, mfaProps, applicatio
|
||||
});
|
||||
};
|
||||
|
||||
if (mfaType === SmsMfaType || mfaType === EmailMfaType) {
|
||||
if (mfaType !== RecoveryMfaType) {
|
||||
return (
|
||||
<div style={{width: 300, height: 350}}>
|
||||
<div style={{marginBottom: 24, textAlign: "center", fontSize: "24px"}}>
|
||||
@ -69,12 +69,18 @@ export function MfaAuthVerifyForm({formValues, oAuthParams, mfaProps, applicatio
|
||||
<div style={{marginBottom: 24}}>
|
||||
{i18next.t("mfa:Multi-factor authentication description")}
|
||||
</div>
|
||||
<MfaSmsVerifyForm
|
||||
mfaProps={mfaProps}
|
||||
method={mfaAuth}
|
||||
onFinish={verify}
|
||||
application={application}
|
||||
/>
|
||||
{mfaType === SmsMfaType || mfaType === EmailMfaType ? (
|
||||
<MfaSmsVerifyForm
|
||||
mfaProps={mfaProps}
|
||||
method={mfaAuth}
|
||||
onFinish={verify}
|
||||
application={application}
|
||||
/>) : (
|
||||
<MfaTotpVerifyForm
|
||||
mfaProps={mfaProps}
|
||||
onFinish={verify}
|
||||
/>
|
||||
)}
|
||||
<span style={{float: "right"}}>
|
||||
{i18next.t("mfa:Have problems?")}
|
||||
<a onClick={() => {
|
||||
@ -85,7 +91,7 @@ export function MfaAuthVerifyForm({formValues, oAuthParams, mfaProps, applicatio
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
} else if (mfaType === "recovery") {
|
||||
} else {
|
||||
return (
|
||||
<div style={{width: 300, height: 350}}>
|
||||
<div style={{marginBottom: 24, textAlign: "center", fontSize: "24px"}}>
|
||||
|
@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import React, {useEffect, useState} from "react";
|
||||
import React, {useState} from "react";
|
||||
import {Button, Col, Form, Input, Result, Row, Steps} from "antd";
|
||||
import * as ApplicationBackend from "../backend/ApplicationBackend";
|
||||
import * as Setting from "../Setting";
|
||||
@ -26,6 +26,7 @@ import {MfaSmsVerifyForm, MfaTotpVerifyForm, mfaSetup} from "./MfaVerifyForm";
|
||||
export const EmailMfaType = "email";
|
||||
export const SmsMfaType = "sms";
|
||||
export const TotpMfaType = "app";
|
||||
export const RecoveryMfaType = "recovery";
|
||||
|
||||
function CheckPasswordForm({user, onSuccess, onFail}) {
|
||||
const [form] = Form.useForm();
|
||||
@ -76,29 +77,11 @@ function CheckPasswordForm({user, onSuccess, onFail}) {
|
||||
);
|
||||
}
|
||||
|
||||
export function MfaVerifyForm({mfaType, application, user, onSuccess, onFail}) {
|
||||
export function MfaVerifyForm({mfaProps, application, user, onSuccess, onFail}) {
|
||||
const [form] = Form.useForm();
|
||||
const [mfaProps, setMfaProps] = useState({mfaType: mfaType});
|
||||
|
||||
useEffect(() => {
|
||||
if (mfaType === SmsMfaType) {
|
||||
setMfaProps({
|
||||
mfaType: mfaType,
|
||||
secret: user.phone,
|
||||
countryCode: user.countryCode,
|
||||
});
|
||||
}
|
||||
|
||||
if (mfaType === EmailMfaType) {
|
||||
setMfaProps({
|
||||
mfaType: mfaType,
|
||||
secret: user.email,
|
||||
});
|
||||
}
|
||||
}, [mfaType]);
|
||||
|
||||
const onFinish = ({passcode}) => {
|
||||
const data = {passcode, mfaType: mfaType, ...user};
|
||||
const data = {passcode, mfaType: mfaProps.mfaType, ...user};
|
||||
MfaBackend.MfaSetupVerify(data)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
@ -115,14 +98,14 @@ export function MfaVerifyForm({mfaType, application, user, onSuccess, onFail}) {
|
||||
});
|
||||
};
|
||||
|
||||
if (mfaType === null || mfaType === undefined || mfaProps.secret === undefined) {
|
||||
if (mfaProps === undefined || mfaProps === null) {
|
||||
return <div></div>;
|
||||
}
|
||||
|
||||
if (mfaType === SmsMfaType || mfaType === EmailMfaType) {
|
||||
return <MfaSmsVerifyForm onFinish={onFinish} application={application} method={mfaSetup} mfaProps={mfaProps} />;
|
||||
} else if (mfaType === TotpMfaType) {
|
||||
return <MfaTotpVerifyForm onFinish={onFinish} />;
|
||||
if (mfaProps.mfaType === SmsMfaType || mfaProps.mfaType === EmailMfaType) {
|
||||
return <MfaSmsVerifyForm mfaProps={mfaProps} onFinish={onFinish} application={application} method={mfaSetup} user={user} />;
|
||||
} else if (mfaProps.mfaType === TotpMfaType) {
|
||||
return <MfaTotpVerifyForm mfaProps={mfaProps} onFinish={onFinish} />;
|
||||
} else {
|
||||
return <div></div>;
|
||||
}
|
||||
@ -183,7 +166,7 @@ class MfaSetupPage extends React.Component {
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (this.state.isAuthenticated === true && this.state.mfaProps === null) {
|
||||
if (this.state.isAuthenticated === true && (this.state.mfaProps === null || this.state.mfaType !== prevState.mfaType)) {
|
||||
MfaBackend.MfaSetupInitiate({
|
||||
mfaType: this.state.mfaType,
|
||||
...this.getUser(),
|
||||
@ -226,18 +209,20 @@ class MfaSetupPage extends React.Component {
|
||||
renderStep() {
|
||||
switch (this.state.current) {
|
||||
case 0:
|
||||
return <CheckPasswordForm
|
||||
user={this.getUser()}
|
||||
onSuccess={() => {
|
||||
this.setState({
|
||||
current: this.state.current + 1,
|
||||
isAuthenticated: true,
|
||||
});
|
||||
}}
|
||||
onFail={(res) => {
|
||||
Setting.showMessage("error", i18next.t("mfa:Failed to initiate MFA"));
|
||||
}}
|
||||
/>;
|
||||
return (
|
||||
<CheckPasswordForm
|
||||
user={this.getUser()}
|
||||
onSuccess={() => {
|
||||
this.setState({
|
||||
current: this.state.current + 1,
|
||||
isAuthenticated: true,
|
||||
});
|
||||
}}
|
||||
onFail={(res) => {
|
||||
Setting.showMessage("error", i18next.t("mfa:Failed to initiate MFA"));
|
||||
}}
|
||||
/>
|
||||
);
|
||||
case 1:
|
||||
if (!this.state.isAuthenticated) {
|
||||
return null;
|
||||
@ -246,7 +231,7 @@ class MfaSetupPage extends React.Component {
|
||||
return (
|
||||
<div>
|
||||
<MfaVerifyForm
|
||||
mfaType={this.state.mfaType}
|
||||
mfaProps={this.state.mfaProps}
|
||||
application={this.state.application}
|
||||
user={this.props.account}
|
||||
onSuccess={() => {
|
||||
@ -261,11 +246,6 @@ class MfaSetupPage extends React.Component {
|
||||
<Col span={24} style={{display: "flex", justifyContent: "left"}}>
|
||||
{(this.state.mfaType === EmailMfaType || this.props.account.mfaEmailEnabled) ? null :
|
||||
<Button type={"link"} onClick={() => {
|
||||
if (this.state.isPromptPage) {
|
||||
this.props.history.push(`/prompt/${this.state.application.name}?promptType=mfa&mfaType=${EmailMfaType}`);
|
||||
} else {
|
||||
this.props.history.push(`/mfa-authentication/setup?mfaType=${EmailMfaType}`);
|
||||
}
|
||||
this.setState({
|
||||
mfaType: EmailMfaType,
|
||||
});
|
||||
@ -275,17 +255,21 @@ class MfaSetupPage extends React.Component {
|
||||
{
|
||||
(this.state.mfaType === SmsMfaType || this.props.account.mfaPhoneEnabled) ? null :
|
||||
<Button type={"link"} onClick={() => {
|
||||
if (this.state.isPromptPage) {
|
||||
this.props.history.push(`/prompt/${this.state.application.name}?promptType=mfa&mfaType=${SmsMfaType}`);
|
||||
} else {
|
||||
this.props.history.push(`/mfa-authentication/setup?mfaType=${SmsMfaType}`);
|
||||
}
|
||||
this.setState({
|
||||
mfaType: SmsMfaType,
|
||||
});
|
||||
}
|
||||
}>{i18next.t("mfa:Use SMS")}</Button>
|
||||
}
|
||||
{
|
||||
(this.state.mfaType === TotpMfaType) ? null :
|
||||
<Button type={"link"} onClick={() => {
|
||||
this.setState({
|
||||
mfaType: TotpMfaType,
|
||||
});
|
||||
}
|
||||
}>{i18next.t("mfa:Use Authenticator App")}</Button>
|
||||
}
|
||||
</Col>
|
||||
</div>
|
||||
);
|
||||
@ -294,18 +278,20 @@ class MfaSetupPage extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <EnableMfaForm user={this.getUser()} mfaType={this.state.mfaType} recoveryCodes={this.state.mfaProps.recoveryCodes}
|
||||
onSuccess={() => {
|
||||
Setting.showMessage("success", i18next.t("general:Enabled successfully"));
|
||||
if (this.state.isPromptPage && this.state.redirectUri) {
|
||||
Setting.goToLink(this.state.redirectUri);
|
||||
} else {
|
||||
Setting.goToLink("/account");
|
||||
}
|
||||
}}
|
||||
onFail={(res) => {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to enable")}: ${res.msg}`);
|
||||
}} />;
|
||||
return (
|
||||
<EnableMfaForm user={this.getUser()} mfaType={this.state.mfaType} recoveryCodes={this.state.mfaProps.recoveryCodes}
|
||||
onSuccess={() => {
|
||||
Setting.showMessage("success", i18next.t("general:Enabled successfully"));
|
||||
if (this.state.isPromptPage && this.state.redirectUri) {
|
||||
Setting.goToLink(this.state.redirectUri);
|
||||
} else {
|
||||
Setting.goToLink("/account");
|
||||
}
|
||||
}}
|
||||
onFail={(res) => {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to enable")}: ${res.msg}`);
|
||||
}} />
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -328,24 +314,20 @@ class MfaSetupPage extends React.Component {
|
||||
<Col span={24} style={{justifyContent: "center"}}>
|
||||
<Row>
|
||||
<Col span={24}>
|
||||
<div style={{textAlign: "center", fontSize: "28px"}}>
|
||||
{i18next.t("mfa:Protect your account with Multi-factor authentication")}</div>
|
||||
<div style={{textAlign: "center", fontSize: "16px", marginTop: "10px"}}>{i18next.t("mfa:Each time you sign in to your Account, you'll need your password and a authentication code")}</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col span={24}>
|
||||
<Steps current={this.state.current}
|
||||
items={[
|
||||
{title: i18next.t("mfa:Verify Password"), icon: <UserOutlined />},
|
||||
{title: i18next.t("mfa:Verify Code"), icon: <KeyOutlined />},
|
||||
{title: i18next.t("general:Enable"), icon: <CheckOutlined />},
|
||||
]}
|
||||
style={{width: "90%", maxWidth: "500px", margin: "auto", marginTop: "80px",
|
||||
}} >
|
||||
</Steps>
|
||||
<p style={{textAlign: "center", fontSize: "28px"}}>
|
||||
{i18next.t("mfa:Protect your account with Multi-factor authentication")}</p>
|
||||
<p style={{textAlign: "center", fontSize: "16px", marginTop: "10px"}}>{i18next.t("mfa:Each time you sign in to your Account, you'll need your password and a authentication code")}</p>
|
||||
</Col>
|
||||
</Row>
|
||||
<Steps current={this.state.current}
|
||||
items={[
|
||||
{title: i18next.t("mfa:Verify Password"), icon: <UserOutlined />},
|
||||
{title: i18next.t("mfa:Verify Code"), icon: <KeyOutlined />},
|
||||
{title: i18next.t("general:Enable"), icon: <CheckOutlined />},
|
||||
]}
|
||||
style={{width: "90%", maxWidth: "500px", margin: "auto", marginTop: "50px",
|
||||
}} >
|
||||
</Steps>
|
||||
</Col>
|
||||
<Col span={24} style={{display: "flex", justifyContent: "center"}}>
|
||||
<div style={{marginTop: "10px", textAlign: "center"}}>
|
||||
|
@ -12,23 +12,33 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import {Button, Col, Form, Input, Row} from "antd";
|
||||
import {Button, Col, Form, Input, QRCode, Space} from "antd";
|
||||
import i18next from "i18next";
|
||||
import {CopyOutlined, UserOutlined} from "@ant-design/icons";
|
||||
import {SendCodeInput} from "../common/SendCodeInput";
|
||||
import * as Setting from "../Setting";
|
||||
import React from "react";
|
||||
import React, {useEffect} from "react";
|
||||
import copy from "copy-to-clipboard";
|
||||
import {CountryCodeSelect} from "../common/select/CountryCodeSelect";
|
||||
import {EmailMfaType} from "./MfaSetupPage";
|
||||
import {EmailMfaType, SmsMfaType} from "./MfaSetupPage";
|
||||
|
||||
export const mfaAuth = "mfaAuth";
|
||||
export const mfaSetup = "mfaSetup";
|
||||
|
||||
export const MfaSmsVerifyForm = ({mfaProps, application, onFinish, method}) => {
|
||||
export const MfaSmsVerifyForm = ({mfaProps, application, onFinish, method, user}) => {
|
||||
const [dest, setDest] = React.useState(mfaProps.secret ?? "");
|
||||
const [form] = Form.useForm();
|
||||
|
||||
useEffect(() => {
|
||||
if (mfaProps.mfaType === SmsMfaType) {
|
||||
setDest(user.phone);
|
||||
}
|
||||
|
||||
if (mfaProps.mfaType === EmailMfaType) {
|
||||
setDest(user.email);
|
||||
}
|
||||
}, [mfaProps.mfaType]);
|
||||
|
||||
const isEmail = () => {
|
||||
return mfaProps.mfaType === EmailMfaType;
|
||||
};
|
||||
@ -42,9 +52,9 @@ export const MfaSmsVerifyForm = ({mfaProps, application, onFinish, method}) => {
|
||||
countryCode: mfaProps.countryCode,
|
||||
}}
|
||||
>
|
||||
{mfaProps.secret !== "" ?
|
||||
{dest !== "" ?
|
||||
<div style={{marginBottom: 20, textAlign: "left", gap: 8}}>
|
||||
{isEmail() ? i18next.t("mfa:Your email is") : i18next.t("mfa:Your phone is")} {mfaProps.secret}
|
||||
{isEmail() ? i18next.t("mfa:Your email is") : i18next.t("mfa:Your phone is")} {dest}
|
||||
</div> :
|
||||
(<React.Fragment>
|
||||
<p>{isEmail() ? i18next.t("mfa:Please bind your email first, the system will automatically uses the mail for multi-factor authentication") :
|
||||
@ -114,44 +124,49 @@ export const MfaSmsVerifyForm = ({mfaProps, application, onFinish, method}) => {
|
||||
export const MfaTotpVerifyForm = ({mfaProps, onFinish}) => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const renderSecret = () => {
|
||||
if (!mfaProps.secret) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Col span={24} style={{display: "flex", justifyContent: "center"}}>
|
||||
<QRCode
|
||||
errorLevel="H"
|
||||
value={mfaProps.url}
|
||||
icon={"https://cdn.casdoor.com/static/favicon.png"}
|
||||
/>
|
||||
</Col>
|
||||
<p style={{textAlign: "center"}}>{i18next.t("mfa:Scan the QR code with your Authenticator App")}</p>
|
||||
<p style={{textAlign: "center"}}>{i18next.t("mfa:Or copy the secret to your Authenticator App")}</p>
|
||||
<Col span={24}>
|
||||
<Space>
|
||||
<Input value={mfaProps.secret} />
|
||||
<Button
|
||||
type="primary"
|
||||
shape="round"
|
||||
icon={<CopyOutlined />}
|
||||
onClick={() => {
|
||||
copy(`${mfaProps.secret}`);
|
||||
Setting.showMessage(
|
||||
"success",
|
||||
i18next.t("mfa:Multi-factor secret to clipboard successfully")
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
</Col>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<Form
|
||||
form={form}
|
||||
style={{width: "300px"}}
|
||||
onFinish={onFinish}
|
||||
>
|
||||
<Row type="flex" justify="center" align="middle">
|
||||
<Col>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row type="flex" justify="center" align="middle">
|
||||
<Col>
|
||||
{Setting.getLabel(
|
||||
i18next.t("mfa:Multi-factor secret"),
|
||||
i18next.t("mfa:Multi-factor secret - Tooltip")
|
||||
)}
|
||||
:
|
||||
</Col>
|
||||
<Col>
|
||||
<Input value={mfaProps.secret} />
|
||||
</Col>
|
||||
<Col>
|
||||
<Button
|
||||
type="primary"
|
||||
shape="round"
|
||||
icon={<CopyOutlined />}
|
||||
onClick={() => {
|
||||
copy(`${mfaProps.secret}`);
|
||||
Setting.showMessage(
|
||||
"success",
|
||||
i18next.t("mfa:Multi-factor secret to clipboard successfully")
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{renderSecret()}
|
||||
<Form.Item
|
||||
name="passcode"
|
||||
rules={[{required: true, message: "Please input your passcode"}]}
|
||||
@ -162,7 +177,6 @@ export const MfaTotpVerifyForm = ({mfaProps, onFinish}) => {
|
||||
placeholder={i18next.t("mfa:Passcode")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button
|
||||
style={{marginTop: 24}}
|
||||
|
@ -434,17 +434,18 @@
|
||||
"Multi-factor methods": "Multi-factor methods",
|
||||
"Multi-factor recover": "Multi-factor recover",
|
||||
"Multi-factor recover description": "Multi-factor recover description",
|
||||
"Multi-factor secret": "Multi-factor secret",
|
||||
"Multi-factor secret - Tooltip": "Multi-factor secret - Tooltip",
|
||||
"Multi-factor secret to clipboard successfully": "Multi-factor secret to clipboard successfully",
|
||||
"Or copy the secret to your Authenticator App": "Or copy the secret to your Authenticator App",
|
||||
"Passcode": "Passcode",
|
||||
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
|
||||
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
|
||||
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
|
||||
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
|
||||
"Recovery code": "Recovery code",
|
||||
"Scan the QR code with your Authenticator App": "Scan the QR code with your Authenticator App",
|
||||
"Set preferred": "Set preferred",
|
||||
"Setup": "Setup",
|
||||
"Use Authenticator App": "Use Authenticator App",
|
||||
"Use Email": "Use Email",
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
|
@ -434,17 +434,18 @@
|
||||
"Multi-factor methods": "Multi-factor methods",
|
||||
"Multi-factor recover": "Multi-factor recover",
|
||||
"Multi-factor recover description": "If you are unable to access your device, enter your recovery code to verify your identity",
|
||||
"Multi-factor secret": "Multi-factor secret",
|
||||
"Multi-factor secret - Tooltip": "Multi-factor secret - Tooltip",
|
||||
"Multi-factor secret to clipboard successfully": "Multi-factor secret to clipboard successfully",
|
||||
"Or copy the secret to your Authenticator App": "Or copy the secret to your Authenticator App",
|
||||
"Passcode": "Passcode",
|
||||
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
|
||||
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
|
||||
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
|
||||
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
|
||||
"Recovery code": "Recovery code",
|
||||
"Scan the QR code with your Authenticator App": "Scan the QR code with your Authenticator App",
|
||||
"Set preferred": "Set preferred",
|
||||
"Setup": "Setup",
|
||||
"Use Authenticator App": "Use Authenticator App",
|
||||
"Use Email": "Use Email",
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
|
@ -434,17 +434,18 @@
|
||||
"Multi-factor methods": "Multi-factor methods",
|
||||
"Multi-factor recover": "Multi-factor recover",
|
||||
"Multi-factor recover description": "Multi-factor recover description",
|
||||
"Multi-factor secret": "Multi-factor secret",
|
||||
"Multi-factor secret - Tooltip": "Multi-factor secret - Tooltip",
|
||||
"Multi-factor secret to clipboard successfully": "Multi-factor secret to clipboard successfully",
|
||||
"Or copy the secret to your Authenticator App": "Or copy the secret to your Authenticator App",
|
||||
"Passcode": "Passcode",
|
||||
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
|
||||
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
|
||||
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
|
||||
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
|
||||
"Recovery code": "Recovery code",
|
||||
"Scan the QR code with your Authenticator App": "Scan the QR code with your Authenticator App",
|
||||
"Set preferred": "Set preferred",
|
||||
"Setup": "Setup",
|
||||
"Use Authenticator App": "Use Authenticator App",
|
||||
"Use Email": "Use Email",
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
|
@ -434,17 +434,18 @@
|
||||
"Multi-factor methods": "Multi-factor methods",
|
||||
"Multi-factor recover": "Multi-factor recover",
|
||||
"Multi-factor recover description": "Multi-factor recover description",
|
||||
"Multi-factor secret": "Multi-factor secret",
|
||||
"Multi-factor secret - Tooltip": "Multi-factor secret - Tooltip",
|
||||
"Multi-factor secret to clipboard successfully": "Multi-factor secret to clipboard successfully",
|
||||
"Or copy the secret to your Authenticator App": "Or copy the secret to your Authenticator App",
|
||||
"Passcode": "Passcode",
|
||||
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
|
||||
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
|
||||
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
|
||||
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
|
||||
"Recovery code": "Recovery code",
|
||||
"Scan the QR code with your Authenticator App": "Scan the QR code with your Authenticator App",
|
||||
"Set preferred": "Set preferred",
|
||||
"Setup": "Setup",
|
||||
"Use Authenticator App": "Use Authenticator App",
|
||||
"Use Email": "Use Email",
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
|
@ -434,17 +434,18 @@
|
||||
"Multi-factor methods": "Multi-factor methods",
|
||||
"Multi-factor recover": "Multi-factor recover",
|
||||
"Multi-factor recover description": "Multi-factor recover description",
|
||||
"Multi-factor secret": "Multi-factor secret",
|
||||
"Multi-factor secret - Tooltip": "Multi-factor secret - Tooltip",
|
||||
"Multi-factor secret to clipboard successfully": "Multi-factor secret to clipboard successfully",
|
||||
"Or copy the secret to your Authenticator App": "Or copy the secret to your Authenticator App",
|
||||
"Passcode": "Passcode",
|
||||
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
|
||||
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
|
||||
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
|
||||
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
|
||||
"Recovery code": "Recovery code",
|
||||
"Scan the QR code with your Authenticator App": "Scan the QR code with your Authenticator App",
|
||||
"Set preferred": "Set preferred",
|
||||
"Setup": "Setup",
|
||||
"Use Authenticator App": "Use Authenticator App",
|
||||
"Use Email": "Use Email",
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
|
@ -434,17 +434,18 @@
|
||||
"Multi-factor methods": "Multi-factor methods",
|
||||
"Multi-factor recover": "Multi-factor recover",
|
||||
"Multi-factor recover description": "Multi-factor recover description",
|
||||
"Multi-factor secret": "Multi-factor secret",
|
||||
"Multi-factor secret - Tooltip": "Multi-factor secret - Tooltip",
|
||||
"Multi-factor secret to clipboard successfully": "Multi-factor secret to clipboard successfully",
|
||||
"Or copy the secret to your Authenticator App": "Or copy the secret to your Authenticator App",
|
||||
"Passcode": "Passcode",
|
||||
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
|
||||
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
|
||||
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
|
||||
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
|
||||
"Recovery code": "Recovery code",
|
||||
"Scan the QR code with your Authenticator App": "Scan the QR code with your Authenticator App",
|
||||
"Set preferred": "Set preferred",
|
||||
"Setup": "Setup",
|
||||
"Use Authenticator App": "Use Authenticator App",
|
||||
"Use Email": "Use Email",
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
|
@ -434,17 +434,18 @@
|
||||
"Multi-factor methods": "Multi-factor methods",
|
||||
"Multi-factor recover": "Multi-factor recover",
|
||||
"Multi-factor recover description": "Multi-factor recover description",
|
||||
"Multi-factor secret": "Multi-factor secret",
|
||||
"Multi-factor secret - Tooltip": "Multi-factor secret - Tooltip",
|
||||
"Multi-factor secret to clipboard successfully": "Multi-factor secret to clipboard successfully",
|
||||
"Or copy the secret to your Authenticator App": "Or copy the secret to your Authenticator App",
|
||||
"Passcode": "Passcode",
|
||||
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
|
||||
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
|
||||
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
|
||||
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
|
||||
"Recovery code": "Recovery code",
|
||||
"Scan the QR code with your Authenticator App": "Scan the QR code with your Authenticator App",
|
||||
"Set preferred": "Set preferred",
|
||||
"Setup": "Setup",
|
||||
"Use Authenticator App": "Use Authenticator App",
|
||||
"Use Email": "Use Email",
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
|
@ -434,17 +434,18 @@
|
||||
"Multi-factor methods": "Métodos de vários fatores",
|
||||
"Multi-factor recover": "Recuperação de vários fatores",
|
||||
"Multi-factor recover description": "Se você não conseguir acessar seu dispositivo, insira seu código de recuperação para verificar sua identidade",
|
||||
"Multi-factor secret": "Segredo de vários fatores",
|
||||
"Multi-factor secret - Tooltip": "Segredo de vários fatores - Dica de ferramenta",
|
||||
"Multi-factor secret to clipboard successfully": "Segredo de vários fatores copiado para a área de transferência com sucesso",
|
||||
"Or copy the secret to your Authenticator App": "Or copy the secret to your Authenticator App",
|
||||
"Passcode": "Código de acesso",
|
||||
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
|
||||
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
|
||||
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Guarde este código de recuperação. Quando o seu dispositivo não puder fornecer um código de autenticação, você poderá redefinir a autenticação mfa usando este código de recuperação",
|
||||
"Protect your account with Multi-factor authentication": "Proteja sua conta com autenticação de vários fatores",
|
||||
"Recovery code": "Código de recuperação",
|
||||
"Scan the QR code with your Authenticator App": "Scan the QR code with your Authenticator App",
|
||||
"Set preferred": "Definir preferido",
|
||||
"Setup": "Configuração",
|
||||
"Use Authenticator App": "Use Authenticator App",
|
||||
"Use Email": "Use Email",
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Usar código de verificação SMS",
|
||||
|
@ -434,17 +434,18 @@
|
||||
"Multi-factor methods": "Multi-factor methods",
|
||||
"Multi-factor recover": "Multi-factor recover",
|
||||
"Multi-factor recover description": "Multi-factor recover description",
|
||||
"Multi-factor secret": "Multi-factor secret",
|
||||
"Multi-factor secret - Tooltip": "Multi-factor secret - Tooltip",
|
||||
"Multi-factor secret to clipboard successfully": "Multi-factor secret to clipboard successfully",
|
||||
"Or copy the secret to your Authenticator App": "Or copy the secret to your Authenticator App",
|
||||
"Passcode": "Passcode",
|
||||
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
|
||||
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
|
||||
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
|
||||
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
|
||||
"Recovery code": "Recovery code",
|
||||
"Scan the QR code with your Authenticator App": "Scan the QR code with your Authenticator App",
|
||||
"Set preferred": "Set preferred",
|
||||
"Setup": "Setup",
|
||||
"Use Authenticator App": "Use Authenticator App",
|
||||
"Use Email": "Use Email",
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
|
@ -434,17 +434,18 @@
|
||||
"Multi-factor methods": "Multi-factor methods",
|
||||
"Multi-factor recover": "Multi-factor recover",
|
||||
"Multi-factor recover description": "Multi-factor recover description",
|
||||
"Multi-factor secret": "Multi-factor secret",
|
||||
"Multi-factor secret - Tooltip": "Multi-factor secret - Tooltip",
|
||||
"Multi-factor secret to clipboard successfully": "Multi-factor secret to clipboard successfully",
|
||||
"Or copy the secret to your Authenticator App": "Or copy the secret to your Authenticator App",
|
||||
"Passcode": "Passcode",
|
||||
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "Please bind your email first, the system will automatically uses the mail for multi-factor authentication",
|
||||
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "Please bind your phone first, the system automatically uses the phone for multi-factor authentication",
|
||||
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code",
|
||||
"Protect your account with Multi-factor authentication": "Protect your account with Multi-factor authentication",
|
||||
"Recovery code": "Recovery code",
|
||||
"Scan the QR code with your Authenticator App": "Scan the QR code with your Authenticator App",
|
||||
"Set preferred": "Set preferred",
|
||||
"Setup": "Setup",
|
||||
"Use Authenticator App": "Use Authenticator App",
|
||||
"Use Email": "Use Email",
|
||||
"Use SMS": "Use SMS",
|
||||
"Use SMS verification code": "Use SMS verification code",
|
||||
|
@ -434,17 +434,18 @@
|
||||
"Multi-factor methods": "多因素认证方式",
|
||||
"Multi-factor recover": "重置多因素认证",
|
||||
"Multi-factor recover description": "如果您无法访问您的设备,输入您的多因素认证恢复代码来确认您的身份",
|
||||
"Multi-factor secret": "多因素密钥",
|
||||
"Multi-factor secret - Tooltip": "多因素密钥 - Tooltip",
|
||||
"Multi-factor secret to clipboard successfully": "多因素密钥已复制到剪贴板",
|
||||
"Or copy the secret to your Authenticator App": "或者将这个密钥复制到你的身份验证应用中",
|
||||
"Passcode": "认证码",
|
||||
"Please bind your email first, the system will automatically uses the mail for multi-factor authentication": "请先绑定邮箱,之后会自动使用该邮箱作为多因素认证的方式",
|
||||
"Please bind your phone first, the system automatically uses the phone for multi-factor authentication": "请先绑定手机号,之后会自动使用该手机号作为多因素认证的方式",
|
||||
"Please save this recovery code. Once your device cannot provide an authentication code, you can reset mfa authentication by this recovery code": "请保存此恢复代码。一旦您的设备无法提供身份验证码,您可以通过此恢复码重置多因素认证",
|
||||
"Protect your account with Multi-factor authentication": "通过多因素认证保护您的帐户",
|
||||
"Recovery code": "恢复码",
|
||||
"Scan the QR code with your Authenticator App": "用你的身份验证应用扫描二维码",
|
||||
"Set preferred": "设为首选",
|
||||
"Setup": "设置",
|
||||
"Use Authenticator App": "使用身份验证应用",
|
||||
"Use Email": "使用电子邮件",
|
||||
"Use SMS": "使用短信",
|
||||
"Use SMS verification code": "使用手机或电子邮件发送验证码认证",
|
||||
|
Reference in New Issue
Block a user