mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:27:42 +00:00
feat: invite user link (#8578)
# Which Problems Are Solved As an administrator I want to be able to invite users to my application with the API V2, some user data I will already prefil, the user should add the authentication method themself (password, passkey, sso). # How the Problems Are Solved - A user can now be created with a email explicitly set to false. - If a user has no verified email and no authentication method, an `InviteCode` can be created through the User V2 API. - the code can be returned or sent through email - additionally `URLTemplate` and an `ApplicatioName` can provided for the email - The code can be resent and verified through the User V2 API - The V1 login allows users to verify and resend the code and set a password (analog user initialization) - The message text for the user invitation can be customized # Additional Changes - `verifyUserPasskeyCode` directly uses `crypto.VerifyCode` (instead of `verifyEncryptedCode`) - `verifyEncryptedCode` is removed (unnecessarily queried for the code generator) # Additional Context - closes #8310 - TODO: login V2 will have to implement invite flow: https://github.com/zitadel/typescript/issues/166
This commit is contained in:
154
internal/api/ui/login/invite_user_handler.go
Normal file
154
internal/api/ui/login/invite_user_handler.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
queryInviteUserCode = "code"
|
||||
queryInviteUserUserID = "userID"
|
||||
queryInviteUserLoginName = "loginname"
|
||||
|
||||
tmplInviteUser = "inviteuser"
|
||||
)
|
||||
|
||||
type inviteUserFormData struct {
|
||||
Code string `schema:"code"`
|
||||
LoginName string `schema:"loginname"`
|
||||
Password string `schema:"password"`
|
||||
PasswordConfirm string `schema:"passwordconfirm"`
|
||||
UserID string `schema:"userID"`
|
||||
OrgID string `schema:"orgID"`
|
||||
Resend bool `schema:"resend"`
|
||||
}
|
||||
|
||||
type inviteUserData struct {
|
||||
baseData
|
||||
profileData
|
||||
Code string
|
||||
LoginName string
|
||||
UserID string
|
||||
MinLength uint64
|
||||
HasUppercase string
|
||||
HasLowercase string
|
||||
HasNumber string
|
||||
HasSymbol string
|
||||
}
|
||||
|
||||
func InviteUserLink(origin, userID, loginName, code, orgID string, authRequestID string) string {
|
||||
v := url.Values{}
|
||||
v.Set(queryInviteUserUserID, userID)
|
||||
v.Set(queryInviteUserLoginName, loginName)
|
||||
v.Set(queryInviteUserCode, code)
|
||||
v.Set(queryOrgID, orgID)
|
||||
v.Set(QueryAuthRequestID, authRequestID)
|
||||
return externalLink(origin) + EndpointInviteUser + "?" + v.Encode()
|
||||
}
|
||||
|
||||
func (l *Login) handleInviteUser(w http.ResponseWriter, r *http.Request) {
|
||||
authReq := l.checkOptionalAuthRequestOfEmailLinks(r)
|
||||
userID := r.FormValue(queryInviteUserUserID)
|
||||
orgID := r.FormValue(queryOrgID)
|
||||
code := r.FormValue(queryInviteUserCode)
|
||||
loginName := r.FormValue(queryInviteUserLoginName)
|
||||
l.renderInviteUser(w, r, authReq, userID, orgID, loginName, code, nil)
|
||||
}
|
||||
|
||||
func (l *Login) handleInviteUserCheck(w http.ResponseWriter, r *http.Request) {
|
||||
data := new(inviteUserFormData)
|
||||
authReq, err := l.getAuthRequestAndParseData(r, data)
|
||||
if err != nil {
|
||||
l.renderError(w, r, nil, err)
|
||||
return
|
||||
}
|
||||
|
||||
if data.Resend {
|
||||
l.resendUserInvite(w, r, authReq, data.UserID, data.OrgID, data.LoginName)
|
||||
return
|
||||
}
|
||||
l.checkUserInviteCode(w, r, authReq, data)
|
||||
}
|
||||
|
||||
func (l *Login) checkUserInviteCode(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, data *inviteUserFormData) {
|
||||
if data.Password != data.PasswordConfirm {
|
||||
err := zerrors.ThrowInvalidArgument(nil, "VIEW-KJS3h", "Errors.User.Password.ConfirmationWrong")
|
||||
l.renderInviteUser(w, r, authReq, data.UserID, data.OrgID, data.LoginName, data.Code, err)
|
||||
return
|
||||
}
|
||||
userOrgID := ""
|
||||
if authReq != nil {
|
||||
userOrgID = authReq.UserOrgID
|
||||
}
|
||||
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
|
||||
_, err := l.command.VerifyInviteCodeSetPassword(setUserContext(r.Context(), data.UserID, userOrgID), data.UserID, data.Code, data.Password, userAgentID)
|
||||
if err != nil {
|
||||
l.renderInviteUser(w, r, authReq, data.UserID, data.OrgID, data.LoginName, "", err)
|
||||
return
|
||||
}
|
||||
if authReq == nil {
|
||||
l.defaultRedirect(w, r)
|
||||
return
|
||||
}
|
||||
l.renderNextStep(w, r, authReq)
|
||||
}
|
||||
|
||||
func (l *Login) resendUserInvite(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID, orgID, loginName string) {
|
||||
var userOrgID, authRequestID string
|
||||
if authReq != nil {
|
||||
userOrgID = authReq.UserOrgID
|
||||
authRequestID = authReq.ID
|
||||
}
|
||||
_, err := l.command.ResendInviteCode(setUserContext(r.Context(), userID, userOrgID), userID, userOrgID, authRequestID)
|
||||
l.renderInviteUser(w, r, authReq, userID, orgID, loginName, "", err)
|
||||
}
|
||||
|
||||
func (l *Login) renderInviteUser(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, userID, orgID, loginName string, code string, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
if authReq != nil {
|
||||
userID = authReq.UserID
|
||||
orgID = authReq.UserOrgID
|
||||
}
|
||||
|
||||
translator := l.getTranslator(r.Context(), authReq)
|
||||
data := inviteUserData{
|
||||
baseData: l.getBaseData(r, authReq, translator, "InviteUser.Title", "InviteUser.Description", errID, errMessage),
|
||||
profileData: l.getProfileData(authReq),
|
||||
UserID: userID,
|
||||
Code: code,
|
||||
}
|
||||
// if the user clicked on the link in the mail, we need to make sure the loginName is rendered
|
||||
if authReq == nil {
|
||||
data.LoginName = loginName
|
||||
data.UserName = loginName
|
||||
}
|
||||
policy := l.getPasswordComplexityPolicyByUserID(r, userID)
|
||||
if policy != nil {
|
||||
data.MinLength = policy.MinLength
|
||||
if policy.HasUppercase {
|
||||
data.HasUppercase = UpperCaseRegex
|
||||
}
|
||||
if policy.HasLowercase {
|
||||
data.HasLowercase = LowerCaseRegex
|
||||
}
|
||||
if policy.HasSymbol {
|
||||
data.HasSymbol = SymbolRegex
|
||||
}
|
||||
if policy.HasNumber {
|
||||
data.HasNumber = NumberRegex
|
||||
}
|
||||
}
|
||||
if authReq == nil {
|
||||
if err == nil {
|
||||
l.customTexts(r.Context(), translator, orgID)
|
||||
}
|
||||
}
|
||||
l.renderer.RenderTemplate(w, r, translator, l.renderer.Templates[tmplInviteUser], data, nil)
|
||||
}
|
@@ -68,6 +68,7 @@ func CreateRenderer(pathPrefix string, staticStorage static.Storage, cookieName
|
||||
tmplInitPasswordDone: "init_password_done.html",
|
||||
tmplInitUser: "init_user.html",
|
||||
tmplInitUserDone: "init_user_done.html",
|
||||
tmplInviteUser: "invite_user.html",
|
||||
tmplPasswordResetDone: "password_reset_done.html",
|
||||
tmplChangePassword: "change_password.html",
|
||||
tmplChangePasswordDone: "change_password_done.html",
|
||||
@@ -193,6 +194,9 @@ func CreateRenderer(pathPrefix string, staticStorage static.Storage, cookieName
|
||||
"initUserUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointInitUser)
|
||||
},
|
||||
"inviteUserUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointInviteUser)
|
||||
},
|
||||
"changePasswordUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointChangePassword)
|
||||
},
|
||||
@@ -329,6 +333,8 @@ func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *
|
||||
l.renderInternalError(w, r, authReq, zerrors.ThrowPreconditionFailed(nil, "APP-asb43", "Errors.User.GrantRequired"))
|
||||
case *domain.ProjectRequiredStep:
|
||||
l.renderInternalError(w, r, authReq, zerrors.ThrowPreconditionFailed(nil, "APP-m92d", "Errors.User.ProjectRequired"))
|
||||
case *domain.VerifyInviteStep:
|
||||
l.renderInviteUser(w, r, authReq, "", "", "", "", nil)
|
||||
default:
|
||||
l.renderInternalError(w, r, authReq, zerrors.ThrowInternal(nil, "APP-ds3QF", "step no possible"))
|
||||
}
|
||||
|
@@ -30,6 +30,7 @@ const (
|
||||
EndpointChangePassword = "/password/change"
|
||||
EndpointPasswordReset = "/password/reset"
|
||||
EndpointInitUser = "/user/init"
|
||||
EndpointInviteUser = "/user/invite"
|
||||
EndpointMFAVerify = "/mfa/verify"
|
||||
EndpointMFAPrompt = "/mfa/prompt"
|
||||
EndpointMFAInitVerify = "/mfa/init/verify"
|
||||
@@ -94,6 +95,8 @@ func CreateRouter(login *Login, interceptors ...mux.MiddlewareFunc) *mux.Router
|
||||
router.HandleFunc(EndpointPasswordReset, login.handlePasswordReset).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointInitUser, login.handleInitUser).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointInitUser, login.handleInitUserCheck).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointInviteUser, login.handleInviteUser).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointInviteUser, login.handleInviteUserCheck).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointMFAVerify, login.handleMFAVerify).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointMFAPrompt, login.handleMFAPromptSelection).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointMFAPrompt, login.handleMFAPrompt).Methods(http.MethodPost)
|
||||
|
@@ -81,6 +81,14 @@ InitUserDone:
|
||||
Description: Имейлът е потвърден и паролата е успешно зададена
|
||||
NextButtonText: следващия
|
||||
CancelButtonText: анулиране
|
||||
InviteUser:
|
||||
Title: Активиране на потребителя
|
||||
Description: Проверете своя имейл с кода по-долу и задайте паролата си.
|
||||
CodeLabel: Код
|
||||
NewPasswordLabel: Нова парола
|
||||
NewPasswordConfirm: Потвърди парола
|
||||
NextButtonText: Напред
|
||||
ResendButtonText: Изпрати отново код
|
||||
InitMFAPrompt:
|
||||
Title: 2-факторна настройка
|
||||
Description: >-
|
||||
|
@@ -86,6 +86,15 @@ InitUserDone:
|
||||
NextButtonText: Další
|
||||
CancelButtonText: Zrušit
|
||||
|
||||
InviteUser:
|
||||
Title: Aktivace uživatele
|
||||
Description: Ověřte svůj e-mail pomocí níže uvedeného kódu a nastavte si heslo.
|
||||
CodeLabel: Kód
|
||||
NewPasswordLabel: Nové heslo
|
||||
NewPasswordConfirm: Potvrďte heslo
|
||||
NextButtonText: Další
|
||||
ResendButtonText: Odeslat kód znovu
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: Nastavení 2-faktorové autentizace
|
||||
Description: 2-faktorová autentizace vám poskytuje další zabezpečení pro váš uživatelský účet. Tím je zajištěno, že k vašemu účtu máte přístup pouze vy.
|
||||
|
@@ -86,6 +86,15 @@ InitUserDone:
|
||||
NextButtonText: Weiter
|
||||
CancelButtonText: Abbrechen
|
||||
|
||||
InviteUser:
|
||||
Title: Benutzer aktivieren
|
||||
Description: Bestätige deine E-Mail-Adresse mit dem unten stehenden Code und lege dein Passwort fest.
|
||||
CodeLabel: Code
|
||||
NewPasswordLabel: Neues Passwort
|
||||
NewPasswordConfirm: Passwort bestätigen
|
||||
NextButtonText: Weiter
|
||||
ResendButtonText: Code erneut senden
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: Zweitfaktor hinzufügen
|
||||
Description: Die Zwei-Faktor-Authentifizierung gibt dir eine zusätzliche Sicherheit für dein Benutzerkonto. Damit stellst du sicher, dass nur du Zugriff auf dein Konto hast.
|
||||
|
@@ -86,6 +86,15 @@ InitUserDone:
|
||||
NextButtonText: Next
|
||||
CancelButtonText: Cancel
|
||||
|
||||
InviteUser:
|
||||
Title: Activate User
|
||||
Description: Verify your e-mail with the code below and set your password.
|
||||
CodeLabel: Code
|
||||
NewPasswordLabel: New Password
|
||||
NewPasswordConfirm: Confirm Password
|
||||
NextButtonText: Next
|
||||
ResendButtonText: Resend Code
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: 2-Factor Setup
|
||||
Description: 2-factor authentication gives you an additional security for your user account. This ensures that only you have access to your account.
|
||||
|
@@ -86,6 +86,15 @@ InitUserDone:
|
||||
NextButtonText: siguiente
|
||||
CancelButtonText: cancelar
|
||||
|
||||
InviteUser:
|
||||
Title: Activar usuario
|
||||
Description: Verifica tu email con el siguiente código y establece tu contraseña.
|
||||
CodeLabel: Código
|
||||
NewPasswordLabel: Nueva contraseña
|
||||
NewPasswordConfirm: Confirmar contraseña
|
||||
NextButtonText: siguiente
|
||||
ResendButtonText: reenviar código
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: Configuración de doble factor
|
||||
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.
|
||||
|
@@ -86,6 +86,15 @@ InitUserDone:
|
||||
NextButtonText: Suivant
|
||||
CancelButtonText: Annuler
|
||||
|
||||
InviteUser:
|
||||
Title: Activer l'utilisateur
|
||||
Description: Vérifiez votre e-mail avec le code ci-dessous et définissez votre mot de passe.
|
||||
CodeLabel: Code
|
||||
NewPasswordLabel: Nouveau mot de passe
|
||||
NewPasswordConfirm: Confirmer le mot de passe
|
||||
NextButtonText: Suivant
|
||||
ResendButtonText: Renvoyer le code
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: Configuration authentification à 2 facteurs
|
||||
Description: L'authentification authentification à 2 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.
|
||||
|
@@ -76,6 +76,14 @@ InitUserDone:
|
||||
Description: Email terverifikasi dan Kata Sandi berhasil ditetapkan
|
||||
NextButtonText: Berikutnya
|
||||
CancelButtonText: Membatalkan
|
||||
InviteUser:
|
||||
Title: Aktifkan Pengguna
|
||||
Description: Verifikasi email Anda dengan kode di bawah ini dan atur kata sandi Anda.
|
||||
CodeLabel: Kode
|
||||
NewPasswordLabel: Kata Sandi Baru
|
||||
NewPasswordConfirm: Konfirmasi Kata Sandi
|
||||
NextButtonText: Selanjutnya
|
||||
ResendButtonText: Kirim Ulang Kode
|
||||
InitMFAPrompt:
|
||||
Title: Pengaturan 2 Faktor
|
||||
Description: Otentikasi 2 faktor memberi Anda keamanan tambahan untuk akun pengguna Anda.
|
||||
|
@@ -86,6 +86,15 @@ InitUserDone:
|
||||
NextButtonText: Avanti
|
||||
CancelButtonText: annulla
|
||||
|
||||
InviteUser:
|
||||
Title: Attiva utente
|
||||
Description: Verifica la tua email con il codice seguente e imposta la tua password.
|
||||
CodeLabel: Codice
|
||||
NewPasswordLabel: Nuova password
|
||||
NewPasswordConfirm: Conferma password
|
||||
NextButtonText: Avanti
|
||||
ResendButtonText: Reinvia codice
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: Impostazione a 2 fattori
|
||||
Description: L'autenticazione a due fattori offre un'ulteriore sicurezza al vostro account utente. Questo garantisce che solo voi possiate accedere al vostro account.
|
||||
|
@@ -79,6 +79,15 @@ InitUserDone:
|
||||
NextButtonText: 次へ
|
||||
CancelButtonText: キャンセル
|
||||
|
||||
InviteUser:
|
||||
Title: ユーザーの有効化
|
||||
Description: 下のコードでメールアドレスを確認し、パスワードを設定してください。
|
||||
CodeLabel: コード
|
||||
NewPasswordLabel: 新しいパスワード
|
||||
NewPasswordConfirm: パスワードの確認
|
||||
NextButtonText: 次へ
|
||||
ResendButtonText: コードを再送信
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: 二要素認証のセットアップ
|
||||
Description: 二要素認証でアカウントのセキュリティを強化します。
|
||||
|
@@ -86,6 +86,15 @@ InitUserDone:
|
||||
NextButtonText: следно
|
||||
CancelButtonText: откажи
|
||||
|
||||
InviteUser:
|
||||
Title: Активирање на корисникот
|
||||
Description: Проверете го вашиот имејл со кодот подолу и поставете ја вашата лозинка.
|
||||
CodeLabel: Код
|
||||
NewPasswordLabel: Нова лозинка
|
||||
NewPasswordConfirm: Потврди лозинка
|
||||
NextButtonText: Следно
|
||||
ResendButtonText: Повторно испрати код
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: Подесување на 2-факторска автентикација
|
||||
Description: 2-факторската автентикација ви дава дополнителна безбедност за вашата корисничка сметка. Ова обезбедува само вие да имате пристап до вашата сметка.
|
||||
|
@@ -86,6 +86,15 @@ InitUserDone:
|
||||
NextButtonText: Volgende
|
||||
CancelButtonText: Annuleren
|
||||
|
||||
InviteUser:
|
||||
Title: Gebruiker activeren
|
||||
Description: Verifieer uw e-mail met de onderstaande code en stel uw wachtwoord in.
|
||||
CodeLabel: Code
|
||||
NewPasswordLabel: Nieuw wachtwoord
|
||||
NewPasswordConfirm: Wachtwoord bevestigen
|
||||
NextButtonText: Volgende
|
||||
ResendButtonText: Code opnieuw verzenden
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: 2-Factor Setup
|
||||
Description: 2-factor authenticatie geeft u extra beveiliging voor uw gebruikersaccount. Hierdoor bent u de enige die toegang heeft tot uw account.
|
||||
|
@@ -86,6 +86,15 @@ InitUserDone:
|
||||
NextButtonText: dalej
|
||||
CancelButtonText: anuluj
|
||||
|
||||
InviteUser:
|
||||
Title: Aktywuj użytkownika
|
||||
Description: Zweryfikuj swój adres e-mail za pomocą poniższego kodu i ustaw swoje hasło.
|
||||
CodeLabel: Kod
|
||||
NewPasswordLabel: Nowe hasło
|
||||
NewPasswordConfirm: Potwierdź hasło
|
||||
NextButtonText: Dalej
|
||||
ResendButtonText: Wyślij ponownie kod
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: Konfiguracja 2-etapowego uwierzytelniania
|
||||
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.
|
||||
|
@@ -86,6 +86,15 @@ InitUserDone:
|
||||
NextButtonText: próximo
|
||||
CancelButtonText: cancelar
|
||||
|
||||
InviteUser:
|
||||
Title: Ativar usuário
|
||||
Description: Verifique seu e-mail com o código abaixo e defina sua senha.
|
||||
CodeLabel: Código
|
||||
NewPasswordLabel: Nova senha
|
||||
NewPasswordConfirm: Confirmar senha
|
||||
NextButtonText: Próximo
|
||||
ResendButtonText: Reenviar código
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: Configuração de 2 fatores
|
||||
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.
|
||||
|
@@ -85,6 +85,15 @@ InitUserDone:
|
||||
NextButtonText: далее
|
||||
CancelButtonText: отмена
|
||||
|
||||
InviteUser:
|
||||
Title: Активировать пользователя
|
||||
Description: Проверьте свой адрес электронной почты с помощью кода ниже и установите свой пароль.
|
||||
CodeLabel: Код
|
||||
NewPasswordLabel: Новый пароль
|
||||
NewPasswordConfirm: Подтвердить пароль
|
||||
NextButtonText: Далее
|
||||
ResendButtonText: Отправить код повторно
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: Установка двухфакторной аутентификации
|
||||
Description: Двухфакторная аутентификация обеспечивает дополнительную защиту вашей учётной записи.
|
||||
|
@@ -86,6 +86,15 @@ InitUserDone:
|
||||
NextButtonText: Fortsätt
|
||||
CancelButtonText: Avbryt
|
||||
|
||||
InviteUser:
|
||||
Title: Aktivera användare
|
||||
Description: Verifiera din e-post med koden nedan och sätt ditt lösenord.
|
||||
CodeLabel: Kod
|
||||
NewPasswordLabel: Nytt lösenord
|
||||
NewPasswordConfirm: Bekräfta lösenord
|
||||
NextButtonText: Nästa
|
||||
ResendButtonText: Skicka koden igen
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: tvåfaktorinställningar
|
||||
Description: 2-factor-identifiering ökar säkerheten för ditt konto. Enbart du som har tillgång till enheten kan logga in.
|
||||
|
@@ -86,6 +86,15 @@ InitUserDone:
|
||||
NextButtonText: 继续
|
||||
CancelButtonText: 取消
|
||||
|
||||
InviteUser:
|
||||
Title: 激活用户
|
||||
Description: 使用以下代码验证您的电子邮件并设置您的密码。
|
||||
CodeLabel: 代码
|
||||
NewPasswordLabel: 新密码
|
||||
NewPasswordConfirm: 确认密码
|
||||
NextButtonText: 下一步
|
||||
ResendButtonText: 重新发送代码
|
||||
|
||||
InitMFAPrompt:
|
||||
Title: 两步验证设置
|
||||
Description: 两步验证为您的账户提供了额外的安全保障。这确保只有你能访问你的账户。
|
||||
|
63
internal/api/ui/login/static/templates/invite_user.html
Normal file
63
internal/api/ui/login/static/templates/invite_user.html
Normal file
@@ -0,0 +1,63 @@
|
||||
{{template "main-top" .}}
|
||||
|
||||
<div class="lgn-head">
|
||||
<h1>{{t "InviteUser.Title"}}</h1>
|
||||
|
||||
{{ template "user-profile" . }}
|
||||
|
||||
<p>{{t "InviteUser.Description"}}</p>
|
||||
</div>
|
||||
|
||||
<form action="{{ inviteUserUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
<input type="hidden" name="userID" value="{{ .UserID }}" />
|
||||
<input type="hidden" name="orgID" value="{{ .OrgID }}" />
|
||||
<input type="text" name="loginName" value="{{if .DisplayLoginNameSuffix}}{{.LoginName}}{{else}}{{.UserName}}{{end}}" autocomplete="username" class="hidden" />
|
||||
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<label class="lgn-label" for="code">{{t "InviteUser.CodeLabel"}}</label>
|
||||
<input class="lgn-input" {{if .ErrMessage}}shake {{end}} type="text" id="code" name="code" value="{{.Code}}" autocomplete="one-time-code" autofocus
|
||||
required>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="lgn-label" for="password">{{t "InviteUser.NewPasswordLabel"}}</label>
|
||||
<input data-minlength="{{ .MinLength }}" data-has-uppercase="{{ .HasUppercase }}"
|
||||
data-has-lowercase="{{ .HasLowercase }}" data-has-number="{{ .HasNumber }}"
|
||||
data-has-symbol="{{ .HasSymbol }}" class="lgn-input" type="password" id="password" name="password"
|
||||
autocomplete="new-password" autofocus required>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label class="lgn-label" for="passwordconfirm">{{t "InviteUser.NewPasswordConfirm"}}</label>
|
||||
<input class="lgn-input" type="password" id="passwordconfirm" name="passwordconfirm"
|
||||
autocomplete="new-password" autofocus required>
|
||||
{{ template "password-complexity-policy-description" . }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ template "error-message" .}}
|
||||
|
||||
<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 type="submit" id="init-button" name="resend" value="false"
|
||||
class="lgn-primary lgn-raised-button">{{t "InviteUser.NextButtonText"}}</button>
|
||||
|
||||
<span class="fill-space"></span>
|
||||
|
||||
<button type="submit" name="resend" value="true" class="lgn-stroked-button" formnovalidate>{{t "InviteUser.ResendButtonText"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script src="{{ resourceUrl "scripts/form_submit.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/password_policy_check.js" }}"></script>
|
||||
<script src="{{ resourceUrl "scripts/init_password_check.js" }}"></script>
|
||||
|
||||
{{template "main-bottom" .}}
|
Reference in New Issue
Block a user