mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 03:57:32 +00:00
feat(login): add OTP (email and sms) (#6353)
* feat: login with otp * fix(i18n): japanese translation * add missing files * fix provider change * add event types translations to en * add tests * resourceOwner * remove unused handler * fix: secret generators and add comments * add setup step * rename * linting * fix setup * improve otp handling * fix autocomplete * translations for login and notifications * translations for event types * changes from review * check selected mfa type
This commit is contained in:
@@ -62,11 +62,7 @@ func (s *Server) VerifyMyPhone(ctx context.Context, req *auth_pb.VerifyMyPhoneRe
|
||||
|
||||
func (s *Server) ResendMyPhoneVerification(ctx context.Context, _ *auth_pb.ResendMyPhoneVerificationRequest) (*auth_pb.ResendMyPhoneVerificationResponse, error) {
|
||||
ctxData := authz.GetCtxData(ctx)
|
||||
phoneCodeGenerator, err := s.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyPhoneCode, s.userCodeAlg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
objectDetails, err := s.command.CreateHumanPhoneVerificationCode(ctx, ctxData.UserID, ctxData.ResourceOwner, phoneCodeGenerator)
|
||||
objectDetails, err := s.command.CreateHumanPhoneVerificationCode(ctx, ctxData.UserID, ctxData.ResourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -549,11 +549,7 @@ func (s *Server) RemoveHumanPhone(ctx context.Context, req *mgmt_pb.RemoveHumanP
|
||||
}
|
||||
|
||||
func (s *Server) ResendHumanPhoneVerification(ctx context.Context, req *mgmt_pb.ResendHumanPhoneVerificationRequest) (*mgmt_pb.ResendHumanPhoneVerificationResponse, error) {
|
||||
phoneCodeGenerator, err := s.query.InitEncryptionGenerator(ctx, domain.SecretGeneratorTypeVerifyPhoneCode, s.userCodeAlg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
objectDetails, err := s.command.CreateHumanPhoneVerificationCode(ctx, req.UserId, authz.GetCtxData(ctx).OrgID, phoneCodeGenerator)
|
||||
objectDetails, err := s.command.CreateHumanPhoneVerificationCode(ctx, req.UserId, authz.GetCtxData(ctx).OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -261,7 +261,9 @@ func CodeChallengeToOIDC(challenge *domain.OIDCCodeChallenge) *oidc.CodeChalleng
|
||||
|
||||
func AMRFromMFAType(mfaType domain.MFAType) string {
|
||||
switch mfaType {
|
||||
case domain.MFATypeTOTP:
|
||||
case domain.MFATypeTOTP,
|
||||
domain.MFATypeOTPSMS,
|
||||
domain.MFATypeOTPEmail:
|
||||
return OTP
|
||||
case domain.MFATypeU2F,
|
||||
domain.MFATypeU2FUserVerification:
|
||||
|
@@ -149,6 +149,8 @@ type authMethod string
|
||||
const (
|
||||
authMethodPassword authMethod = "password"
|
||||
authMethodOTP authMethod = "OTP"
|
||||
authMethodOTPSMS authMethod = "OTP SMS"
|
||||
authMethodOTPEmail authMethod = "OTP Email"
|
||||
authMethodU2F authMethod = "U2F"
|
||||
authMethodPasswordless authMethod = "passwordless"
|
||||
)
|
||||
|
@@ -171,6 +171,14 @@ func setContext(ctx context.Context, resourceOwner string) context.Context {
|
||||
return authz.SetCtxData(ctx, data)
|
||||
}
|
||||
|
||||
func setUserContext(ctx context.Context, userID, resourceOwner string) context.Context {
|
||||
data := authz.CtxData{
|
||||
UserID: userID,
|
||||
OrgID: resourceOwner,
|
||||
}
|
||||
return authz.SetCtxData(ctx, data)
|
||||
}
|
||||
|
||||
func (l *Login) baseURL(ctx context.Context) string {
|
||||
return http_utils.BuildOrigin(authz.GetInstance(ctx).RequestedHost(), l.externalSecure) + HandlerPrefix
|
||||
}
|
||||
|
125
internal/api/ui/login/mfa_init_sms.go
Normal file
125
internal/api/ui/login/mfa_init_sms.go
Normal file
@@ -0,0 +1,125 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
)
|
||||
|
||||
const (
|
||||
tmplMFASMSInit = "mfainitsms"
|
||||
)
|
||||
|
||||
type smsInitData struct {
|
||||
userData
|
||||
Edit bool
|
||||
MFAType domain.MFAType
|
||||
Phone string
|
||||
}
|
||||
|
||||
type smsInitFormData struct {
|
||||
Edit bool `schema:"edit"`
|
||||
Resend bool `schema:"resend"`
|
||||
Phone string `schema:"phone"`
|
||||
NewPhone string `schema:"newPhone"`
|
||||
Code string `schema:"code"`
|
||||
}
|
||||
|
||||
// handleRegisterOTPSMS checks if the user has a verified phone number and will directly add OTP SMS as 2FA.
|
||||
// It will also add a successful OTP SMS check to the auth request.
|
||||
// If there's no verified phone number, the potential last phone number will be used to render the registration page
|
||||
func (l *Login) handleRegisterOTPSMS(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) {
|
||||
user, err := l.query.GetNotifyUserByID(r.Context(), true, authReq.UserID, false)
|
||||
if err != nil {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
if user.VerifiedPhone == "" {
|
||||
data := new(smsInitData)
|
||||
data.Phone = user.LastPhone
|
||||
data.Edit = user.LastPhone == ""
|
||||
l.renderRegisterSMS(w, r, authReq, data, nil)
|
||||
return
|
||||
}
|
||||
_, err = l.command.AddHumanOTPSMSWithCheckSucceeded(setUserContext(r.Context(), authReq.UserID, authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq)
|
||||
if err != nil {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
done := &mfaDoneData{
|
||||
MFAType: domain.MFATypeOTPSMS,
|
||||
}
|
||||
l.renderMFAInitDone(w, r, authReq, done)
|
||||
}
|
||||
|
||||
func (l *Login) renderRegisterSMS(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *smsInitData, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
data.baseData = l.getBaseData(r, authReq, "InitMFAOTP.Title", "InitMFAOTP.Description", errID, errMessage)
|
||||
data.profileData = l.getProfileData(authReq)
|
||||
data.MFAType = domain.MFATypeOTPSMS
|
||||
l.renderer.RenderTemplate(w, r, l.getTranslator(r.Context(), authReq), l.renderer.Templates[tmplMFASMSInit], data, nil)
|
||||
}
|
||||
|
||||
// handleRegisterSMSCheck handles form submissions of the SMS registration.
|
||||
// The user can be either in edit mode, where a phone number can be entered / changed.
|
||||
// If a phone was set, the user can either switch to edit mode, have a resend of the code or verify the code by entering it.
|
||||
// On successful code verification, the phone will be added to the user as well as his MFA
|
||||
// and a successful OTP SMS check will be added to the auth request.
|
||||
func (l *Login) handleRegisterSMSCheck(w http.ResponseWriter, r *http.Request) {
|
||||
formData := new(smsInitFormData)
|
||||
authReq, err := l.getAuthRequestAndParseData(r, formData)
|
||||
if err != nil {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := setUserContext(r.Context(), authReq.UserID, authReq.UserOrgID)
|
||||
// save the current state
|
||||
data := &smsInitData{Phone: formData.Phone}
|
||||
|
||||
if formData.Edit {
|
||||
data.Edit = true
|
||||
l.renderRegisterSMS(w, r, authReq, data, err)
|
||||
return
|
||||
}
|
||||
|
||||
if formData.Resend {
|
||||
_, err = l.command.CreateHumanPhoneVerificationCode(ctx, authReq.UserID, authReq.UserOrgID)
|
||||
l.renderRegisterSMS(w, r, authReq, data, err)
|
||||
return
|
||||
}
|
||||
|
||||
// if the user is currently in edit mode,
|
||||
// he can either change the phone number
|
||||
// or just return to the code verification again
|
||||
if formData.Code == "" {
|
||||
data.Phone = formData.NewPhone
|
||||
if formData.NewPhone != formData.Phone {
|
||||
_, err = l.command.ChangeUserPhone(ctx, authReq.UserID, authReq.UserOrgID, formData.NewPhone, l.userCodeAlg)
|
||||
if err != nil {
|
||||
// stay in edit more
|
||||
data.Edit = true
|
||||
}
|
||||
}
|
||||
l.renderRegisterSMS(w, r, authReq, data, err)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = l.command.VerifyUserPhone(ctx, authReq.UserID, authReq.UserOrgID, formData.Code, l.userCodeAlg)
|
||||
if err != nil {
|
||||
l.renderRegisterSMS(w, r, authReq, data, err)
|
||||
return
|
||||
}
|
||||
_, err = l.command.AddHumanOTPSMSWithCheckSucceeded(ctx, authReq.UserID, authReq.UserOrgID, authReq)
|
||||
if err != nil {
|
||||
l.renderRegisterSMS(w, r, authReq, data, err)
|
||||
return
|
||||
}
|
||||
done := &mfaDoneData{
|
||||
MFAType: domain.MFATypeOTPSMS,
|
||||
}
|
||||
l.renderMFAInitDone(w, r, authReq, done)
|
||||
}
|
@@ -83,6 +83,12 @@ func (l *Login) handleMFACreation(w http.ResponseWriter, r *http.Request, authRe
|
||||
case domain.MFATypeTOTP:
|
||||
l.handleTOTPCreation(w, r, authReq, data)
|
||||
return
|
||||
case domain.MFATypeOTPSMS:
|
||||
l.handleRegisterOTPSMS(w, r, authReq)
|
||||
return
|
||||
case domain.MFATypeOTPEmail:
|
||||
l.handleRegisterOTPEmail(w, r, authReq)
|
||||
return
|
||||
case domain.MFATypeU2F:
|
||||
l.renderRegisterU2F(w, r, authReq, nil)
|
||||
return
|
||||
@@ -103,3 +109,17 @@ func (l *Login) handleTOTPCreation(w http.ResponseWriter, r *http.Request, authR
|
||||
}
|
||||
l.renderMFAInitVerify(w, r, authReq, data, nil)
|
||||
}
|
||||
|
||||
// handleRegisterOTPEmail will directly add OTP Email as 2FA.
|
||||
// It will also add a successful OTP Email check to the auth request.
|
||||
func (l *Login) handleRegisterOTPEmail(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest) {
|
||||
_, err := l.command.AddHumanOTPEmailWithCheckSucceeded(setUserContext(r.Context(), authReq.UserID, authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq)
|
||||
if err != nil {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
done := &mfaDoneData{
|
||||
MFAType: domain.MFATypeOTPEmail,
|
||||
}
|
||||
l.renderMFAInitDone(w, r, authReq, done)
|
||||
}
|
||||
|
@@ -84,6 +84,12 @@ func (l *Login) renderMFAVerifySelected(w http.ResponseWriter, r *http.Request,
|
||||
data.SelectedMFAProvider = domain.MFATypeTOTP
|
||||
data.Title = translator.LocalizeWithoutArgs("VerifyMFAOTP.Title")
|
||||
data.Description = translator.LocalizeWithoutArgs("VerifyMFAOTP.Description")
|
||||
case domain.MFATypeOTPSMS:
|
||||
l.handleOTPVerification(w, r, authReq, verificationStep.MFAProviders, domain.MFATypeOTPSMS, nil)
|
||||
return
|
||||
case domain.MFATypeOTPEmail:
|
||||
l.handleOTPVerification(w, r, authReq, verificationStep.MFAProviders, domain.MFATypeOTPEmail, nil)
|
||||
return
|
||||
default:
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
|
126
internal/api/ui/login/mfa_verify_otp_handler.go
Normal file
126
internal/api/ui/login/mfa_verify_otp_handler.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
)
|
||||
|
||||
const (
|
||||
tmplOTPVerification = "otpverification"
|
||||
querySelectedProvider = "selectedProvider"
|
||||
)
|
||||
|
||||
type mfaOTPData struct {
|
||||
userData
|
||||
MFAProviders []domain.MFAType
|
||||
SelectedProvider domain.MFAType
|
||||
}
|
||||
|
||||
type mfaOTPFormData struct {
|
||||
Resend bool `schema:"resend"`
|
||||
Code string `schema:"code"`
|
||||
SelectedProvider domain.MFAType `schema:"selectedProvider"`
|
||||
Provider domain.MFAType `schema:"provider"`
|
||||
}
|
||||
|
||||
func OTPLink(origin, authRequestID, code string, provider domain.MFAType) string {
|
||||
return fmt.Sprintf("%s%s?%s=%s&%s=%s&%s=%d", externalLink(origin), EndpointMFAOTPVerify, QueryAuthRequestID, authRequestID, queryCode, code, querySelectedProvider, provider)
|
||||
}
|
||||
|
||||
// renderOTPVerification renders the OTP verification for SMS and Email based on the passed MFAType.
|
||||
// It will send a new code to either phone or email first.
|
||||
func (l *Login) handleOTPVerification(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, providers []domain.MFAType, selectedProvider domain.MFAType, err error) {
|
||||
if err != nil {
|
||||
l.renderOTPVerification(w, r, authReq, providers, selectedProvider, err)
|
||||
return
|
||||
}
|
||||
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
|
||||
var sendCode func(ctx context.Context, userID, resourceOwner, authRequestID, userAgentID string) error
|
||||
switch selectedProvider {
|
||||
case domain.MFATypeOTPSMS:
|
||||
sendCode = l.authRepo.SendMFAOTPSMS
|
||||
case domain.MFATypeOTPEmail:
|
||||
sendCode = l.authRepo.SendMFAOTPEmail
|
||||
// another type should never be passed, but just making sure
|
||||
case domain.MFATypeU2F,
|
||||
domain.MFATypeTOTP,
|
||||
domain.MFATypeU2FUserVerification:
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
err = sendCode(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, authReq.ID, userAgentID)
|
||||
l.renderOTPVerification(w, r, authReq, providers, selectedProvider, err)
|
||||
}
|
||||
|
||||
func (l *Login) renderOTPVerification(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, providers []domain.MFAType, selectedProvider domain.MFAType, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
data := &mfaOTPData{
|
||||
userData: l.getUserData(r, authReq, "VerifyMFAU2F.Title", "VerifyMFAU2F.Description", errID, errMessage),
|
||||
MFAProviders: removeSelectedProviderFromList(providers, selectedProvider),
|
||||
SelectedProvider: selectedProvider,
|
||||
}
|
||||
l.renderer.RenderTemplate(w, r, l.getTranslator(r.Context(), authReq), l.renderer.Templates[tmplOTPVerification], data, nil)
|
||||
}
|
||||
|
||||
// handleOTPVerificationCheck handles form submissions of the OTP verification.
|
||||
// On successful code verification, the check will be added to the auth request.
|
||||
// A user is also able to request a code resend or choose another provider.
|
||||
func (l *Login) handleOTPVerificationCheck(w http.ResponseWriter, r *http.Request) {
|
||||
formData := new(mfaOTPFormData)
|
||||
authReq, err := l.getAuthRequestAndParseData(r, formData)
|
||||
if err != nil {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
step, ok := authReq.PossibleSteps[0].(*domain.MFAVerificationStep)
|
||||
if !ok {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
if formData.Resend {
|
||||
l.handleOTPVerification(w, r, authReq, step.MFAProviders, formData.SelectedProvider, nil)
|
||||
return
|
||||
}
|
||||
if formData.Code == "" {
|
||||
l.renderMFAVerifySelected(w, r, authReq, step, formData.Provider, nil)
|
||||
return
|
||||
}
|
||||
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
|
||||
var actionType authMethod
|
||||
var verifyCode func(ctx context.Context, userID, resourceOwner, code, authRequestID, userAgentID string, info *domain.BrowserInfo) error
|
||||
switch formData.SelectedProvider {
|
||||
case domain.MFATypeOTPSMS:
|
||||
actionType = authMethodOTPSMS
|
||||
verifyCode = l.authRepo.VerifyMFAOTPSMS
|
||||
case domain.MFATypeOTPEmail:
|
||||
actionType = authMethodOTPEmail
|
||||
verifyCode = l.authRepo.VerifyMFAOTPEmail
|
||||
// another type should never be passed, but just making sure
|
||||
case domain.MFATypeU2F,
|
||||
domain.MFATypeTOTP,
|
||||
domain.MFATypeU2FUserVerification:
|
||||
l.renderOTPVerification(w, r, authReq, step.MFAProviders, formData.SelectedProvider, err)
|
||||
return
|
||||
}
|
||||
err = verifyCode(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.UserOrgID, formData.Code, authReq.ID, userAgentID, domain.BrowserInfoFromRequest(r))
|
||||
|
||||
metadata, actionErr := l.runPostInternalAuthenticationActions(authReq, r, actionType, err)
|
||||
if err == nil && actionErr == nil && len(metadata) > 0 {
|
||||
_, err = l.command.BulkSetUserMetadata(r.Context(), authReq.UserID, authReq.UserOrgID, metadata...)
|
||||
} else if actionErr != nil && err == nil {
|
||||
err = actionErr
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
l.renderOTPVerification(w, r, authReq, step.MFAProviders, formData.SelectedProvider, err)
|
||||
return
|
||||
}
|
||||
l.renderNextStep(w, r, authReq)
|
||||
}
|
@@ -54,9 +54,11 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage
|
||||
tmplPasswordlessRegistration: "passwordless_registration.html",
|
||||
tmplPasswordlessRegistrationDone: "passwordless_registration_done.html",
|
||||
tmplPasswordlessPrompt: "passwordless_prompt.html",
|
||||
tmplMFAVerify: "mfa_verify_otp.html",
|
||||
tmplMFAVerify: "mfa_verify_totp.html",
|
||||
tmplMFAPrompt: "mfa_prompt.html",
|
||||
tmplMFAInitVerify: "mfa_init_otp.html",
|
||||
tmplMFASMSInit: "mfa_init_otp_sms.html",
|
||||
tmplOTPVerification: "mfa_verify_otp.html",
|
||||
tmplMFAU2FInit: "mfa_init_u2f.html",
|
||||
tmplU2FVerification: "mfa_verification_u2f.html",
|
||||
tmplMFAInitDone: "mfa_init_done.html",
|
||||
@@ -170,6 +172,12 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage
|
||||
"mfaInitVerifyUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointMFAInitVerify)
|
||||
},
|
||||
"mfaInitSMSVerifyUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointMFASMSInitVerify)
|
||||
},
|
||||
"mfaOTPVerifyUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointMFAOTPVerify)
|
||||
},
|
||||
"mfaInitU2FVerifyUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointMFAInitU2FVerify)
|
||||
},
|
||||
|
@@ -31,6 +31,8 @@ const (
|
||||
EndpointMFAVerify = "/mfa/verify"
|
||||
EndpointMFAPrompt = "/mfa/prompt"
|
||||
EndpointMFAInitVerify = "/mfa/init/verify"
|
||||
EndpointMFASMSInitVerify = "/mfa/init/sms/verify"
|
||||
EndpointMFAOTPVerify = "/mfa/otp/verify"
|
||||
EndpointMFAInitU2FVerify = "/mfa/init/u2f/verify"
|
||||
EndpointU2FVerification = "/mfa/u2f/verify"
|
||||
EndpointMailVerification = "/mail/verification"
|
||||
@@ -89,6 +91,9 @@ func CreateRouter(login *Login, staticDir http.FileSystem, interceptors ...mux.M
|
||||
router.HandleFunc(EndpointMFAPrompt, login.handleMFAPromptSelection).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointMFAPrompt, login.handleMFAPrompt).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointMFAInitVerify, login.handleMFAInitVerify).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointMFASMSInitVerify, login.handleRegisterSMSCheck).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointMFAOTPVerify, login.handleOTPVerificationCheck).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointMFAOTPVerify, login.handleOTPVerificationCheck).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointMFAInitU2FVerify, login.handleRegisterU2F).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointU2FVerification, login.handleU2FVerification).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointMailVerification, login.handleMailVerification).Methods(http.MethodGet)
|
||||
|
@@ -85,6 +85,8 @@ InitMFAPrompt:
|
||||
потребителски акаунт.
|
||||
Provider0: 'Приложение за удостоверяване (напр. Google/Microsoft Authenticator, Authy)'
|
||||
Provider1: 'Зависи от устройството (напр. FaceID, Windows Hello, пръстов отпечатък)'
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP имейл
|
||||
NextButtonText: следващия
|
||||
SkipButtonText: пропуснете
|
||||
InitMFAOTP:
|
||||
@@ -98,6 +100,15 @@ InitMFAOTP:
|
||||
CodeLabel: Код
|
||||
NextButtonText: следващия
|
||||
CancelButtonText: анулиране
|
||||
InitMFAOTPSMS:
|
||||
Title: 2-факторна проверка
|
||||
DescriptionPhone: Създайте своя 2-фактор. Въведете телефонния си номер, за да го потвърдите.
|
||||
DescriptionCode: Създайте своя 2-фактор. Въведете получения код, за да потвърдите своя телефонен номер.
|
||||
PhoneLabel: Тайна
|
||||
CodeLabel: Код
|
||||
EditButtonText: редактиране
|
||||
ResendButtonText: код за препращане
|
||||
NextButtonText: следващия
|
||||
InitMFAU2F:
|
||||
Title: Добавете ключ за сигурност
|
||||
Description: >-
|
||||
@@ -118,6 +129,8 @@ InitMFADone:
|
||||
MFAProvider:
|
||||
Provider0: 'Приложение за удостоверяване (напр. Google/Microsoft Authenticator, Authy)'
|
||||
Provider1: 'Зависи от устройството (напр. FaceID, Windows Hello, пръстов отпечатък)'
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP имейл
|
||||
ChooseOther: или изберете друга опция
|
||||
VerifyMFAOTP:
|
||||
Title: Проверете 2-фактора
|
||||
|
@@ -89,6 +89,8 @@ InitMFAPrompt:
|
||||
Description: 2-Faktor-Authentifizierung gibt dir eine zusätzliche Sicherheit für dein Benutzerkonto. Damit stellst du sicher, dass nur du Zugriff auf deinen Account hast.
|
||||
Provider0: Authenticator App (e.g Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Geräte abhängig (e.g FaceID, Windows Hello, Fingerprint)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP Email
|
||||
NextButtonText: weiter
|
||||
SkipButtonText: überspringen
|
||||
|
||||
@@ -101,6 +103,16 @@ InitMFAOTP:
|
||||
NextButtonText: weiter
|
||||
CancelButtonText: abbrechen
|
||||
|
||||
InitMFAOTPSMS:
|
||||
Title: 2-Faktor hinzufügen
|
||||
DescriptionPhone: Erstelle deinen 2-Faktor. Gib deine Telefonnummer ein, um sie zu verifizieren.
|
||||
DescriptionCode: Erstelle deinen 2-Faktor. Gib den erhaltenen Code ein um deinen Telefonnummer zu verifizieren.
|
||||
PhoneLabel: Telefonnummer
|
||||
CodeLabel: Code
|
||||
EditButtonText: bearbeiten
|
||||
ResendButtonText: Code erneut senden
|
||||
NextButtonText: weiter
|
||||
|
||||
InitMFAU2F:
|
||||
Title: Sicherheitsschlüssel hinzufügen
|
||||
Description: Ein Sicherheitsschlüssel ist eine Verifizierungsmethode, die in Ihrem Telefon integriert sein kann, Bluetooth verwenden oder direkt an den USB-Anschluss Ihres Computers angeschlossen werden.
|
||||
@@ -118,9 +130,18 @@ InitMFADone:
|
||||
MFAProvider:
|
||||
Provider0: Authenticator App (e.g Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Geräte abhängig (e.g FaceID, Windows Hello, Fingerprint)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP Email
|
||||
ChooseOther: oder wähle eine andere Option aus
|
||||
|
||||
VerifyMFAOTP:
|
||||
Title: 2-Faktor verifizieren
|
||||
Description: Verifiziere deinen Zweitfaktor
|
||||
CodeLabel: Code
|
||||
ResendButtonText: Code erneut senden
|
||||
NextButtonText: next
|
||||
|
||||
VerifyOTP:
|
||||
Title: 2-Faktor verifizieren
|
||||
Description: Verifiziere deinen Zweitfaktor
|
||||
CodeLabel: Code
|
||||
|
@@ -89,6 +89,8 @@ InitMFAPrompt:
|
||||
Description: 2-factor authentication gives you an additional security for your user account. This ensures that only you have access to your account.
|
||||
Provider0: Authenticator App (e.g Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Device dependent (e.g FaceID, Windows Hello, Fingerprint)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP Email
|
||||
NextButtonText: next
|
||||
SkipButtonText: skip
|
||||
|
||||
@@ -101,6 +103,16 @@ InitMFAOTP:
|
||||
NextButtonText: next
|
||||
CancelButtonText: cancel
|
||||
|
||||
InitMFAOTPSMS:
|
||||
Title: 2-Factor Verification
|
||||
DescriptionPhone: Create your 2-factor. Enter your phone number to verify it.
|
||||
DescriptionCode: Create your 2-factor. Enter the received code to verify your phone number.
|
||||
PhoneLabel: Phone
|
||||
CodeLabel: Code
|
||||
EditButtonText: edit
|
||||
ResendButtonText: resend code
|
||||
NextButtonText: next
|
||||
|
||||
InitMFAU2F:
|
||||
Title: Add security key
|
||||
Description: A security key is a verification method that can be built into your phone, use Bluetooth, or plug directly into your computer's USB port.
|
||||
@@ -110,7 +122,7 @@ InitMFAU2F:
|
||||
ErrorRetry: Retry, create a new challenge or choose a different method.
|
||||
|
||||
InitMFADone:
|
||||
Title: Security key verified
|
||||
Title: 2-factor verified
|
||||
Description: Awesome! You just successfully set up your 2-factor and made your account way more secure. The Factor has to be entered on each login.
|
||||
NextButtonText: next
|
||||
CancelButtonText: cancel
|
||||
@@ -118,6 +130,8 @@ InitMFADone:
|
||||
MFAProvider:
|
||||
Provider0: Authenticator App (e.g Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Device dependent (e.g FaceID, Windows Hello, Fingerprint)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP Email
|
||||
ChooseOther: or choose another option
|
||||
|
||||
VerifyMFAOTP:
|
||||
@@ -126,6 +140,13 @@ VerifyMFAOTP:
|
||||
CodeLabel: Code
|
||||
NextButtonText: next
|
||||
|
||||
VerifyOTP:
|
||||
Title: Verify 2-Factor
|
||||
Description: Verify your second factor
|
||||
CodeLabel: Code
|
||||
ResendButtonText: resend code
|
||||
NextButtonText: next
|
||||
|
||||
VerifyMFAU2F:
|
||||
Title: 2-Factor Verification
|
||||
Description: Verify your 2-Factor with the registered device (e.g FaceID, Windows Hello, Fingerprint)
|
||||
|
@@ -89,6 +89,8 @@ InitMFAPrompt:
|
||||
Description: La autenticación de doble factor te proporciona seguridad adicional para tu cuenta de usuario. Ésta asegura que solo tú tienes acceso a tu cuenta.
|
||||
Provider0: App autenticadora (p.e Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Dependiente de un dispositivo (p.e FaceID, Windows Hello, Huella dactilar)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP email
|
||||
NextButtonText: siguiente
|
||||
SkipButtonText: saltar
|
||||
|
||||
@@ -101,6 +103,16 @@ InitMFAOTP:
|
||||
NextButtonText: siguiente
|
||||
CancelButtonText: cancelar
|
||||
|
||||
InitMFASMS:
|
||||
Title: Verificación de doble factor
|
||||
DescriptionPhone: Crea tu doble factor de autenticación. Introduce tu número de teléfono para verificarlo.
|
||||
DescriptionCode: Crea tu doble factor de autenticación. Ingrese el código recibido para verificar su número de teléfono.
|
||||
PhoneLabel: Número de teléfono
|
||||
CodeLabel: Código
|
||||
EditButtonText: editar
|
||||
ResendButtonText: reenviar código
|
||||
NextButtonText: siguiente
|
||||
|
||||
InitMFAU2F:
|
||||
Title: Añadir clave de seguridad
|
||||
Description: Una clave de seguridad es un método de verificación que puede integrarse en tu teléfono móvil, con Bluetooth, o conectándolo directamente en el puerto USB de tu ordenador.
|
||||
@@ -118,6 +130,8 @@ InitMFADone:
|
||||
MFAProvider:
|
||||
Provider0: App autenticadora (p.e Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Dependiente de un dispositivo (p.e FaceID, Windows Hello, Huella dactilar)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP email
|
||||
ChooseOther: o elige otra opción
|
||||
|
||||
VerifyMFAOTP:
|
||||
|
@@ -89,6 +89,8 @@ InitMFAPrompt:
|
||||
Description: L'authentification à deux facteurs vous offre une sécurité supplémentaire pour votre compte d'utilisateur. Vous êtes ainsi assuré d'être le seul à avoir accès à votre compte.
|
||||
Provider0: Application d'authentification (par exemple, Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Dépend de l'appareil (par ex. FaceID, Windows Hello, empreinte digitale)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP e-mail
|
||||
NextButtonText: Suivant
|
||||
SkipButtonText: Passer
|
||||
|
||||
@@ -101,6 +103,16 @@ InitMFAOTP:
|
||||
NextButtonText: Suivant
|
||||
CancelButtonText: Annuler
|
||||
|
||||
InitMFASMS:
|
||||
Title: Vérification à deux facteurs
|
||||
DescriptionPhone: Créez votre 2-facteurs. Entrez votre numéro de téléphone pour le vérifier.
|
||||
DescriptionCode: Créez votre 2-facteurs. Entrez le code reçu pour vérifier votre numéro de téléphone.
|
||||
PhoneLabel: Numéro de téléphone
|
||||
CodeLabel: Code
|
||||
EditButtonText: Modifier
|
||||
ResendButtonText: Renvoyer le code
|
||||
NextButtonText: Suivant
|
||||
|
||||
InitMFAU2F:
|
||||
Title: Ajouter une clé de sécurité
|
||||
Description: Une clé de sécurité est une méthode de vérification qui peut être intégrée à votre téléphone, utiliser Bluetooth ou se brancher directement sur le port USB de votre ordinateur.
|
||||
@@ -118,6 +130,8 @@ InitMFADone:
|
||||
MFAProvider:
|
||||
Provider0: Application d'authentification (par exemple, Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Dépend de l'appareil (par ex. FaceID, Windows Hello, empreinte digitale)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP e-mail
|
||||
ChooseOther: ou choisissez une autre option
|
||||
|
||||
VerifyMFAOTP:
|
||||
|
@@ -89,6 +89,8 @@ InitMFAPrompt:
|
||||
Description: L'autenticazione a due fattori offre un'ulteriore sicurezza al vostro account utente. Questo garantisce che solo voi possiate accedere al vostro account.
|
||||
Provider0: App Autenticatore (ad esempio Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Dipende dal dispositivo (ad es. FaceID, Windows Hello, impronta digitale)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP e-mail
|
||||
NextButtonText: Avanti
|
||||
SkipButtonText: salta
|
||||
|
||||
@@ -101,6 +103,16 @@ InitMFAOTP:
|
||||
NextButtonText: Avanti
|
||||
CancelButtonText: annulla
|
||||
|
||||
InitMFASMS:
|
||||
Title: Verificazione a 2 fattori
|
||||
DescriptionPhone: Crea il tuo 2 fattori. Inserisci il tuo numero di telefono per verificarlo.
|
||||
DescriptionCode: Crea il tuo 2 fattori. Inserisci il codice ricevuto per verificare il tuo numero di telefono.
|
||||
PhoneLabel: Numero di telefono
|
||||
CodeLabel: Codice
|
||||
EditButtonText: Modifica
|
||||
ResendButtonText: Reinvia codice
|
||||
NextButtonText: Avanti
|
||||
|
||||
InitMFAU2F:
|
||||
Title: Aggiungi chiave di sicurezza
|
||||
Description: Una chiave di sicurezza è un metodo di verifica che può essere integrato nel telefono, utilizzare il Bluetooth o collegarlo direttamente alla porta USB del computer.
|
||||
@@ -118,6 +130,8 @@ InitMFADone:
|
||||
MFAProvider:
|
||||
Provider0: App Autenticatore (ad esempio Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Dipende dal dispositivo (ad es. FaceID, Windows Hello, impronta digitale)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP e-mail
|
||||
ChooseOther: o scegli un'altra opzione
|
||||
|
||||
VerifyMFAOTP:
|
||||
|
@@ -82,6 +82,8 @@ InitMFAPrompt:
|
||||
Description: 二要素認証でアカウントのセキュリティを強化します。
|
||||
Provider0: 認証アプリ(Google/Microsoft Authenticator、Authyなど)
|
||||
Provider1: デバイス依存(例:FaceID、Windows Hello、指紋など)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTPメール
|
||||
NextButtonText: 次へ
|
||||
SkipButtonText: スキップ
|
||||
|
||||
@@ -94,6 +96,16 @@ InitMFAOTP:
|
||||
NextButtonText: 次へ
|
||||
CancelButtonText: キャンセル
|
||||
|
||||
InitMFASMS:
|
||||
Title: 二要素認証
|
||||
DescriptionPhone: 二要素認証を作成します。確認するには電話番号を入力してください。
|
||||
DescriptionCode: 二要素認証を作成します。受信したコードを入力して電話番号を確認します。
|
||||
PhoneLabel: 電話番号
|
||||
CodeLabel: コード
|
||||
EditButtonText: 編集
|
||||
ResendButtonText: コードを再送信
|
||||
NextButtonText: 次へ
|
||||
|
||||
InitMFAU2F:
|
||||
Title: セキュリティキーの追加
|
||||
Description: セキュリティキーは、携帯電話への組み込みや、Bluetoothの使用、パソコンのUSBポートに直接差し込むことなどで認証する方法です。
|
||||
@@ -111,6 +123,8 @@ InitMFADone:
|
||||
MFAProvider:
|
||||
Provider0: Authenticatorアプリ(Google/Microsoft Authenticator、Authyなど)
|
||||
Provider1: デバイス依存(FaceID、Windows Hello、指紋など)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTPメール
|
||||
ChooseOther: または、他のオプションを選択
|
||||
|
||||
VerifyMFAOTP:
|
||||
|
@@ -89,6 +89,8 @@ InitMFAPrompt:
|
||||
Description: 2-факторската автентикација ви дава дополнителна безбедност за вашата корисничка сметка. Ова обезбедува само вие да имате пристап до вашата сметка.
|
||||
Provider0: Апликација за автентикација (на пример Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Во зависност од вашиот уред (на пример FaceID, Windows Hello, отпечаток од прст)
|
||||
Provider3: ОТП СМС
|
||||
Provider4: ОТП е-пошта
|
||||
NextButtonText: следно
|
||||
SkipButtonText: прескокни
|
||||
|
||||
@@ -101,6 +103,16 @@ InitMFAOTP:
|
||||
NextButtonText: следно
|
||||
CancelButtonText: откажи
|
||||
|
||||
InitMFASMS:
|
||||
Title: Потврда на 2-факторска автентикација
|
||||
DescriptionPhone: Направете двофакторна автентикација. Внесете го вашиот телефонски број за да го потврдите.
|
||||
DescriptionCode: Направете двофакторна автентикација. Внесете го примениот код за да го потврдите вашиот телефонски број.
|
||||
PhoneLabel: Телефонски број
|
||||
CodeLabel: Код
|
||||
EditButtonText: Уредување
|
||||
ResendButtonText: повторно испрати код
|
||||
NextButtonText: следно
|
||||
|
||||
InitMFAU2F:
|
||||
Title: Додајте безбедносен клуч
|
||||
Description: Безбедносниот клуч е метод на верификација кој може да се интегрира во вашиот телефон, да користи Bluetooth или директно да се поврзе во USB приклучокот на вашиот компјутер.
|
||||
@@ -118,6 +130,8 @@ InitMFADone:
|
||||
MFAProvider:
|
||||
Provider0: Апликација за автентикација (на пример Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Во зависност од вашиот уред (на пример FaceID, Windows Hello, отпечаток од прст)
|
||||
Provider3: ОТП СМС
|
||||
Provider4: ОТП е-пошта
|
||||
ChooseOther: или изберете друга опција
|
||||
|
||||
VerifyMFAOTP:
|
||||
|
@@ -89,6 +89,8 @@ InitMFAPrompt:
|
||||
Description: 2-etapowe uwierzytelnianie daje Ci dodatkową ochronę dla Twojego konta użytkownika. Dzięki temu masz pewność, że tylko Ty masz dostęp do swojego konta.
|
||||
Provider0: Aplikacja uwierzytelniająca (np. Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Zależny od urządzenia (np. FaceID, Windows Hello, Odcisk palca)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP e-mail
|
||||
NextButtonText: dalej
|
||||
SkipButtonText: pomiń
|
||||
|
||||
@@ -101,6 +103,16 @@ InitMFAOTP:
|
||||
NextButtonText: dalej
|
||||
CancelButtonText: anuluj
|
||||
|
||||
InitMFASMS:
|
||||
Title: Weryfikacja 2-etapowa
|
||||
DescriptionPhone: Utwórz uwierzytelnianie dwuskładnikowe. Wprowadź swój numer telefonu, aby go zweryfikować.
|
||||
DescriptionCode: Utwórz uwierzytelnianie dwuskładnikowe. Wprowadź otrzymany kod, aby zweryfikować swój numer telefonu.
|
||||
PhoneLabel: Numer telefonu
|
||||
CodeLabel: Kod
|
||||
EditButtonText: edytować
|
||||
ResendButtonText: wyślij kod ponownie
|
||||
NextButtonText: dalej
|
||||
|
||||
InitMFAU2F:
|
||||
Title: Dodaj klucz zabezpieczeń
|
||||
Description: Klucz zabezpieczeń to metoda weryfikacji, która może być zintegrowana z twoim telefonem, używająca Bluetooth lub podłączana bezpośrednio do portu USB komputera.
|
||||
@@ -118,6 +130,8 @@ InitMFADone:
|
||||
MFAProvider:
|
||||
Provider0: Aplikacja uwierzytelniająca (np. Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Zależny od urządzenia (np. FaceID, Windows Hello, Odcisk palca)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP e-mail
|
||||
ChooseOther: lub wybierz inną opcję
|
||||
|
||||
VerifyMFAOTP:
|
||||
|
@@ -89,6 +89,8 @@ InitMFAPrompt:
|
||||
Description: A autenticação de 2 fatores fornece uma segurança adicional para sua conta de usuário. Isso garante que apenas você tenha acesso à sua conta.
|
||||
Provider0: Aplicativo de autenticação (por exemplo, Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Dependente do dispositivo (por exemplo, FaceID, Windows Hello, Impressão digital)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP e-mail
|
||||
NextButtonText: próximo
|
||||
SkipButtonText: pular
|
||||
|
||||
@@ -101,6 +103,16 @@ InitMFAOTP:
|
||||
NextButtonText: próximo
|
||||
CancelButtonText: cancelar
|
||||
|
||||
InitMFASMS:
|
||||
Title: Verificação de 2 fatores
|
||||
DescriptionPhone: Crie sua verificação de 2 fatores. Digite seu número de telefone para verificá-lo.
|
||||
DescriptionCode: Crie sua verificação de 2 fatores. Digite o código recebido para verificar seu número de telefone.
|
||||
PhoneLabel: Número de telefone
|
||||
CodeLabel: Código
|
||||
EditButtonText: editar
|
||||
ResendButtonText: reenviar código
|
||||
NextButtonText: próximo
|
||||
|
||||
InitMFAU2F:
|
||||
Title: Adicionar chave de segurança
|
||||
Description: Uma chave de segurança é um método de verificação que pode ser incorporado ao seu telefone, usar Bluetooth ou conectar diretamente à porta USB do seu computador.
|
||||
@@ -118,6 +130,8 @@ InitMFADone:
|
||||
MFAProvider:
|
||||
Provider0: Aplicativo de autenticação (por exemplo, Google/Microsoft Authenticator, Authy)
|
||||
Provider1: Dependente do dispositivo (por exemplo, FaceID, Windows Hello, Impressão digital)
|
||||
Provider3: OTP SMS
|
||||
Provider4: OTP e-mail
|
||||
ChooseOther: ou escolha outra opção
|
||||
|
||||
VerifyMFAOTP:
|
||||
|
@@ -89,6 +89,8 @@ InitMFAPrompt:
|
||||
Description: 两步验证为您的账户提供了额外的安全保障。这确保只有你能访问你的账户。
|
||||
Provider0: 软件应用(如 Google/Migrosoft Authenticator、Authy)
|
||||
Provider1: 硬件设备(如 Face ID、Windows Hello、指纹)
|
||||
Provider3: 一次性密码短信
|
||||
Provider4: 一次性密码电子邮件
|
||||
NextButtonText: 继续
|
||||
SkipButtonText: 跳过
|
||||
|
||||
@@ -96,6 +98,16 @@ InitMFAOTP:
|
||||
Title: 双因素验证
|
||||
Description: 创建你的双因素。如果你还没有,请下载一个认证器应用程序。
|
||||
OTPDescription: 使用您的身份验证器应用程序(例如 Google Authenticator)扫描代码或复制密码并在下方插入生成的代码。
|
||||
PhoneLabel: 电话号码
|
||||
CodeLabel: 验证码
|
||||
EditButtonText: 编辑
|
||||
ResendButtonText: 重发代码
|
||||
NextButtonText: 继续
|
||||
|
||||
InitMFASMS:
|
||||
Title: 双因素验证
|
||||
DescriptionPhone: 创建双因素身份验证。输入您的电话号码进行验证。
|
||||
DescriptionCode: 创建双因素身份验证。输入收到的代码以验证您的电话号码。
|
||||
SecretLabel: 秘钥
|
||||
CodeLabel: 验证码
|
||||
NextButtonText: 继续
|
||||
@@ -118,6 +130,8 @@ InitMFADone:
|
||||
MFAProvider:
|
||||
Provider0: 软件应用(如 Google/Migrosoft Authenticator、Authy)
|
||||
Provider1: 硬件设备(如 Face ID、Windows Hello、指纹)
|
||||
Provider3: 一次性密码短信
|
||||
Provider4: 一次性密码电子邮件
|
||||
ChooseOther: 或选择其他选项
|
||||
|
||||
VerifyMFAOTP:
|
||||
|
6
internal/api/ui/login/static/resources/scripts/edit.js
Normal file
6
internal/api/ui/login/static/resources/scripts/edit.js
Normal file
@@ -0,0 +1,6 @@
|
||||
let form = document.getElementsByTagName('form')[0];
|
||||
let editButton = document.getElementById('edit');
|
||||
editButton.addEventListener('click', function () {
|
||||
form.submit();
|
||||
});
|
||||
|
@@ -1,15 +1,16 @@
|
||||
@mixin lgn-mfa-base {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
margin: 2rem 0;
|
||||
margin: 1rem 0;
|
||||
|
||||
.mfa {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
padding: 0 0.5rem;
|
||||
padding: 1rem 0.5rem;
|
||||
|
||||
label {
|
||||
display: flex;
|
||||
|
63
internal/api/ui/login/static/templates/mfa_init_otp_sms.html
Normal file
63
internal/api/ui/login/static/templates/mfa_init_otp_sms.html
Normal file
@@ -0,0 +1,63 @@
|
||||
{{template "main-top" .}}
|
||||
|
||||
<div class="lgn-head">
|
||||
<h1>{{t "InitMFAOTPSMS.Title"}}</h1>
|
||||
|
||||
{{ template "user-profile" . }}
|
||||
|
||||
{{if .Edit}}
|
||||
<p>{{t "InitMFAOTPSMS.DescriptionPhone"}}</p>
|
||||
{{else}}
|
||||
<p>{{t "InitMFAOTPSMS.DescriptionCode"}}</p>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<form action="{{ mfaInitSMSVerifyUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
<input type="hidden" name="mfaType" value="{{ .MFAType }}" />
|
||||
<input type="hidden" name="phone" value="{{ .Phone }}" />
|
||||
|
||||
<div class="fields">
|
||||
{{if .Edit}}
|
||||
<div class="field">
|
||||
<label class="lgn-label" for="newPhone">{{t "InitMFAOTPSMS.PhoneLabel"}}</label>
|
||||
<input class="lgn-input" type="tel" id="newPhone" name="newPhone" autocomplete="off" value="{{.Phone}}" autofocus required>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="field lgn-actions">
|
||||
<p>{{.Phone}}</p>
|
||||
<span class="fill-space"></span>
|
||||
<button type="button" id="edit" name="edit" value="true" class="lgn-stroked-button" formnovalidate>{{t "InitMFAOTPSMS.EditButtonText"}}</button>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if and .Phone (not .Edit) }}
|
||||
<div class="field">
|
||||
<label class="lgn-label" for="code">{{t "InitMFAOTPSMS.CodeLabel"}}</label>
|
||||
<input class="lgn-input" type="text" id="code" name="code" autocomplete="one-time-code" autofocus required>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{ template "error-message" .}}
|
||||
|
||||
<div class="lgn-actions lgn-reverse-order">
|
||||
<!-- position element in header -->
|
||||
<a class="lgn-icon-button lgn-left-action" href="{{ mfaPromptChangeUrl .AuthReqID .MFAType }}">
|
||||
<i class="lgn-icon-arrow-left-solid"></i>
|
||||
</a>
|
||||
<button class="lgn-raised-button lgn-primary" id="submit-button" type="submit">{{t "InitMFAOTPSMS.NextButtonText"}}</button>
|
||||
{{if and .Phone (not .Edit) }}
|
||||
<span class="fill-space"></span>
|
||||
<button type="submit" name="resend" value="true" class="lgn-stroked-button" formnovalidate>{{t "InitMFAOTPSMS.ResendButtonText"}}</button>
|
||||
{{end}}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script src="{{ resourceUrl "scripts/edit.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script>
|
||||
|
||||
{{template "main-bottom" .}}
|
@@ -34,6 +34,16 @@
|
||||
<img width="100px" height="100px" alt="OTP" src="{{ resourceUrl
|
||||
"images/mfa/mfa-u2f.svg" }}" />
|
||||
</div>
|
||||
{{ end }} {{ if eq $provider 3 }}
|
||||
<div class="mfa-img">
|
||||
<img width="100px" height="100px" alt="OTP SMS" src="{{ resourceUrl
|
||||
"images/mfa/mfa-u2f.svg" }}" /> // TODO: image
|
||||
</div>
|
||||
{{ end }}{{ if eq $provider 4 }}
|
||||
<div class="mfa-img">
|
||||
<img width="100px" height="100px" alt="OTP Email" src="{{ resourceUrl
|
||||
"images/mfa/mfa-u2f.svg" }}" /> // TODO: image
|
||||
</div>
|
||||
{{ end }}
|
||||
<span>{{ $providerName }} </span>
|
||||
</label>
|
||||
|
@@ -1,34 +1,37 @@
|
||||
{{template "main-top" .}}
|
||||
|
||||
<div class="lgn-head">
|
||||
<h1>{{t "VerifyMFAOTP.Title"}}</h1>
|
||||
<h1>{{t "VerifyOTP.Title"}}</h1>
|
||||
|
||||
{{ template "user-profile" . }}
|
||||
|
||||
<p>{{t "VerifyMFAOTP.Description"}}</p>
|
||||
<p>{{t "VerifyOTP.Description"}}</p>
|
||||
</div>
|
||||
|
||||
<form action="{{ mfaVerifyUrl }}" method="POST">
|
||||
<form action="{{ mfaOTPVerifyUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
<input type="hidden" name="mfaType" value="{{ .SelectedMFAProvider }}" />
|
||||
<input type="hidden" name="selectedProvider" value="{{ .SelectedProvider }}" />
|
||||
|
||||
<div class="fields">
|
||||
<label class="lgn-label" for="code">{{t "VerifyMFAOTP.CodeLabel"}}</label>
|
||||
<input class="lgn-input" type="text" id="code" name="code" autocomplete="off" autofocus required>
|
||||
<label class="lgn-label" for="code">{{t "VerifyOTP.CodeLabel"}}</label>
|
||||
<input class="lgn-input" type="text" id="code" name="code" autocomplete="one-time-code" autofocus required>
|
||||
</div>
|
||||
|
||||
{{ template "error-message" .}}
|
||||
|
||||
<div class="lgn-actions">
|
||||
<div class="lgn-actions lgn-reverse-order">
|
||||
<!-- position element in header -->
|
||||
<a class="lgn-icon-button lgn-left-action" href="{{ loginUrl }}">
|
||||
<i class="lgn-icon-arrow-left-solid"></i>
|
||||
</a>
|
||||
<button class="lgn-raised-button lgn-primary" id="submit-button" type="submit">{{t "VerifyOTP.NextButtonText"}}</button>
|
||||
|
||||
<span class="fill-space"></span>
|
||||
<button class="lgn-raised-button lgn-primary" id="submit-button" type="submit">{{t "VerifyMFAOTP.NextButtonText"}}</button>
|
||||
|
||||
<button type="submit" name="resend" value="true" class="lgn-stroked-button" formnovalidate>{{t "VerifyOTP.ResendButtonText"}}</button>
|
||||
</div>
|
||||
|
||||
{{ if .MFAProviders }}
|
||||
@@ -45,4 +48,4 @@
|
||||
|
||||
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script>
|
||||
{{template "main-bottom" .}}
|
||||
{{template "main-bottom" .}}
|
||||
|
48
internal/api/ui/login/static/templates/mfa_verify_totp.html
Normal file
48
internal/api/ui/login/static/templates/mfa_verify_totp.html
Normal file
@@ -0,0 +1,48 @@
|
||||
{{template "main-top" .}}
|
||||
|
||||
<div class="lgn-head">
|
||||
<h1>{{t "VerifyMFAOTP.Title"}}</h1>
|
||||
|
||||
{{ template "user-profile" . }}
|
||||
|
||||
<p>{{t "VerifyMFAOTP.Description"}}</p>
|
||||
</div>
|
||||
|
||||
<form action="{{ mfaVerifyUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
<input type="hidden" name="mfaType" value="{{ .SelectedMFAProvider }}" />
|
||||
|
||||
<div class="fields">
|
||||
<label class="lgn-label" for="code">{{t "VerifyMFAOTP.CodeLabel"}}</label>
|
||||
<input class="lgn-input" type="text" id="code" name="code" autocomplete="off" autofocus required>
|
||||
</div>
|
||||
|
||||
{{ template "error-message" .}}
|
||||
|
||||
<div class="lgn-actions">
|
||||
<!-- position element in header -->
|
||||
<a class="lgn-icon-button lgn-left-action" href="{{ loginUrl }}">
|
||||
<i class="lgn-icon-arrow-left-solid"></i>
|
||||
</a>
|
||||
<span class="fill-space"></span>
|
||||
<button class="lgn-raised-button lgn-primary" id="submit-button" type="submit">{{t "VerifyMFAOTP.NextButtonText"}}</button>
|
||||
</div>
|
||||
|
||||
{{ if .MFAProviders }}
|
||||
<div class="lgn-mfa-other">
|
||||
<p>{{t "MFAProvider.ChooseOther"}}</p>
|
||||
{{ range $provider := .MFAProviders}}
|
||||
{{ $providerName := (t (printf "MFAProvider.Provider%v" $provider)) }}
|
||||
<button class="lgn-stroked-button" type="submit" name="provider" value="{{$provider}}"
|
||||
formnovalidate>{{$providerName}}</button>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</form>
|
||||
|
||||
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/default_form_validation.js" }}"></script>
|
||||
{{template "main-bottom" .}}
|
Reference in New Issue
Block a user