mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:37:32 +00:00
feat: passwordless registration (#2103)
* begin pw less registration * create pwless one time codes * send pwless link * separate send and add passwordless link * separate send and add passwordless link events * custom message text for passwordless registration * begin custom login texts for passwordless * i18n * i18n message * i18n message * custom message text * custom login text * org design and texts * create link in human import process * fix import human tests * begin passwordless init required step * passwordless init * passwordless init * do not return link in mgmt api * prompt * passwordless init only (no additional prompt) * cleanup * cleanup * add passwordless prompt to custom login text * increase init code complexity * fix grpc * cleanup * fix and add some cases for nextStep tests * fix tests * Update internal/notification/static/i18n/en.yaml * Update internal/notification/static/i18n/de.yaml * Update proto/zitadel/management.proto * Update internal/ui/login/static/i18n/de.yaml * Update internal/ui/login/static/i18n/de.yaml * Update internal/ui/login/static/i18n/de.yaml Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
@@ -23,6 +23,7 @@ import (
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/notification/types"
|
||||
user_repo "github.com/caos/zitadel/internal/repository/user"
|
||||
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
|
||||
"github.com/caos/zitadel/internal/user/repository/view"
|
||||
"github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
@@ -124,6 +125,8 @@ func (n *Notification) Reduce(event *models.Event) (err error) {
|
||||
err = n.handlePasswordCode(event)
|
||||
case es_model.DomainClaimed:
|
||||
err = n.handleDomainClaimed(event)
|
||||
case models.EventType(user_repo.HumanPasswordlessInitCodeRequestedType):
|
||||
err = n.handlePasswordlessRegistrationLink(event)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -312,6 +315,52 @@ func (n *Notification) handleDomainClaimed(event *models.Event) (err error) {
|
||||
return n.command.UserDomainClaimedSent(ctx, event.ResourceOwner, event.AggregateID)
|
||||
}
|
||||
|
||||
func (n *Notification) handlePasswordlessRegistrationLink(event *models.Event) (err error) {
|
||||
addedEvent := new(user_repo.HumanPasswordlessInitCodeRequestedEvent)
|
||||
if err := json.Unmarshal(event.Data, addedEvent); err != nil {
|
||||
return err
|
||||
}
|
||||
events, err := n.getUserEvents(event.AggregateID, event.Sequence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, e := range events {
|
||||
if e.Type == models.EventType(user_repo.HumanPasswordlessInitCodeSentType) {
|
||||
sentEvent := new(user_repo.HumanPasswordlessInitCodeSentEvent)
|
||||
if err := json.Unmarshal(e.Data, sentEvent); err != nil {
|
||||
return err
|
||||
}
|
||||
if sentEvent.ID == addedEvent.ID {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
user, err := n.getUserByID(event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx := getSetNotifyContextData(event.ResourceOwner)
|
||||
colors, err := n.getLabelPolicy(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
template, err := n.getMailTemplate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
translator, err := n.getTranslatorWithOrgTexts(user.ResourceOwner, domain.PasswordlessRegistrationMessageType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = types.SendPasswordlessRegistrationLink(string(template.Template), translator, user, addedEvent, n.systemDefaults, n.AesCrypto, colors, n.apiDomain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return n.command.HumanPasswordlessInitCodeSent(ctx, event.AggregateID, event.ResourceOwner, addedEvent.ID)
|
||||
}
|
||||
|
||||
func (n *Notification) checkIfCodeAlreadyHandledOrExpired(event *models.Event, expiry time.Duration, eventTypes ...models.EventType) (bool, error) {
|
||||
if event.CreationDate.Add(expiry).Before(time.Now().UTC()) {
|
||||
return true, nil
|
||||
|
@@ -1,35 +1,42 @@
|
||||
InitCode:
|
||||
Title: Zitadel - User initialisieren
|
||||
Title: ZITADEL - User initialisieren
|
||||
PreHeader: User initialisieren
|
||||
Subject: User initialisieren
|
||||
Greeting: Hallo {{.FirstName}} {{.LastName}},
|
||||
Text: Dieser Benutzer wurde soeben im Zitadel erstellt. Mit dem Benutzernamen <br><strong>{{.PreferredLoginName}}</strong><br> kannst du dich anmelden. Nutze den untenstehenden Button, um die Initialisierung abzuschliessen <br>(Code <strong>{{.Code}}</strong>).<br> Falls du dieses Mail nicht angefordert hast, kannst du es einfach ignorieren.
|
||||
Text: Dieser Benutzer wurde soeben in ZITADEL erstellt. Mit dem Benutzernamen <br><strong>{{.PreferredLoginName}}</strong><br> kannst du dich anmelden. Nutze den untenstehenden Button, um die Initialisierung abzuschliessen <br>(Code <strong>{{.Code}}</strong>).<br> Falls du dieses Mail nicht angefordert hast, kannst du es einfach ignorieren.
|
||||
ButtonText: Initialisierung abschliessen
|
||||
PasswordReset:
|
||||
Title: Zitadel - Passwort zurücksetzen
|
||||
Title: ZITADEL - Passwort zurücksetzen
|
||||
PreHeader: Passwort zurücksetzen
|
||||
Subject: Passwort zurücksetzen
|
||||
Greeting: Hallo {{.FirstName}} {{.LastName}},
|
||||
Text: Wir haben eine Anfrage für das Zurücksetzen deines Passwortes bekommen. Du kannst den untenstehenden Button verwenden, um dein Passwort zurückzusetzen <br>(Code <strong>{{.Code}}</strong>).<br> Falls du dieses Mail nicht angefordert hast, kannst du es ignorieren.
|
||||
ButtonText: Passwort zurücksetzen
|
||||
VerifyEmail:
|
||||
Title: Zitadel - Email verifizieren
|
||||
Title: ZITADEL - Email verifizieren
|
||||
PreHeader: Email verifizieren
|
||||
Subject: Email verifizieren
|
||||
Greeting: Hallo {{.FirstName}} {{.LastName}},
|
||||
Text: Eine neue E-Mail Adresse wurde hinzugefügt. Bitte verwende den untenstehenden Button um diese zu verifizieren <br>(Code <strong>{{.Code}}</strong>).<br> Falls du deine E-Mail Adresse nicht selber hinzugefügt hast, kannst du dieses E-Mail ignorieren.
|
||||
ButtonText: Email verifizieren
|
||||
VerifyPhone:
|
||||
Title: Zitadel - Telefonnummer verifizieren
|
||||
Title: ZITADEL - Telefonnummer verifizieren
|
||||
PreHeader: Telefonnummer verifizieren
|
||||
Subject: Telefonnummer verifizieren
|
||||
Greeting: Hallo {{.FirstName}} {{.LastName}},
|
||||
Text: Eine Telefonnummer wurde hinzugefügt. Bitte verifiziere diese in dem du folgenden Code eingibst<br>(Code <strong>{{.Code}}</strong>).<br>
|
||||
ButtonText: Telefon verifizieren
|
||||
DomainClaimed:
|
||||
Title: Zitadel - Domain wurde beansprucht
|
||||
Title: ZITADEL - Domain wurde beansprucht
|
||||
PreHeader: Email / Username ändern
|
||||
Subject: Domain wurde beansprucht
|
||||
Greeting: Hallo {{.FirstName}} {{.LastName}},
|
||||
Text: Die Domain {{.Domain}} wurde von einer Organisation beansprucht. Dein derzeitiger User {{.Username}} ist nicht Teil dieser Organisation. Daher musst du beim nächsten Login eine neue Email hinterlegen. Für diesen Login haben wir dir einen temporären Usernamen ({{.TempUsername}}) erstellt.
|
||||
ButtonText: Login
|
||||
PasswordlessRegistration:
|
||||
Title: ZITADEL - Passwortlosen Login hinzufügen
|
||||
PreHeader: Passwortlosen Login hinzufügen
|
||||
Subject: Passwortlosen Login hinzufügen
|
||||
Greeting: Hallo {{.FirstName}} {{.LastName}},
|
||||
Text: Wir haben eine Anfrage für das Hinzufügen eines Token für den passwortlosen Login erhalten. Du kannst den untenstehenden Button verwenden, um dein Token oder Gerät hinzuzufügen.
|
||||
ButtonText: Passwortlosen Login hinzufügen
|
||||
|
@@ -1,35 +1,42 @@
|
||||
InitCode:
|
||||
Title: Zitadel - Initialize User
|
||||
Title: ZITADEL - Initialize User
|
||||
PreHeader: Initialize User
|
||||
Subject: Initialize User
|
||||
Greeting: Hello {{.FirstName}} {{.LastName}},
|
||||
Text: This user was created in Zitadel. Use the username {{.PreferredLoginName}} to login. Please click the button below to finish the initialization process. (Code {{.Code}}) If you didn't ask for this mail, please ignore it.
|
||||
Text: This user was created in ZITADEL. Use the username {{.PreferredLoginName}} to login. Please click the button below to finish the initialization process. (Code {{.Code}}) If you didn't ask for this mail, please ignore it.
|
||||
ButtonText: Finish initialization
|
||||
PasswordReset:
|
||||
Title: Zitadel - Reset password
|
||||
Title: ZITADEL - Reset password
|
||||
PreHeader: Reset password
|
||||
Subject: Reset password
|
||||
Greeting: Hello {{.FirstName}} {{.LastName}},
|
||||
Text: We received a password reset request. Please use the button below to reset your password. (Code {{.Code}}) If you didn't ask for this mail, please ignore it.
|
||||
ButtonText: Reset password
|
||||
VerifyEmail:
|
||||
Title: Zitadel - Verify email
|
||||
Title: ZITADEL - Verify email
|
||||
PreHeader: Verify email
|
||||
Subject: Verify email
|
||||
Greeting: Hello {{.FirstName}} {{.LastName}},
|
||||
Text: A new email has been added. Please use the button below to verify your mail. (Code {{.Code}}) If you din't add a new email, please ignore this email.
|
||||
ButtonText: Verify email
|
||||
VerifyPhone:
|
||||
Title: Zitadel - Verify phone
|
||||
Title: ZITADEL - Verify phone
|
||||
PreHeader: Verify phone
|
||||
Subject: Verify phone
|
||||
Greeting: Hello {{.FirstName}} {{.LastName}},
|
||||
Text: A new phonenumber has been added. Please use the following code to verify it {{.Code}}
|
||||
ButtonText: Verify phone
|
||||
DomainClaimed:
|
||||
Title: Zitadel - Domain has been claimed
|
||||
Title: ZITADEL - Domain has been claimed
|
||||
PreHeader: Change email / username
|
||||
Subject: Domain has been claimed
|
||||
Greeting: Hello {{.FirstName}} {{.LastName}},
|
||||
Text: The domain {{.Domain}} has been claimed by an organisation. Your current user {{.Username}} is not part of this organisation. Therefore you'll have to change your email when you login. We have created a temporary username ({{.TempUsername}}) for this login.
|
||||
ButtonText: Login
|
||||
PasswordlessRegistration:
|
||||
Title: ZITADEL - Add Passwordless Login
|
||||
PreHeader: Add Passwordless Login
|
||||
Subject: Add Passwordless Login
|
||||
Greeting: Hello {{.FirstName}} {{.LastName}},
|
||||
Text: We received a request to add a token for passwordless login. Please use the button below to add your token or device for passwordless login.
|
||||
ButtonText: Add Passwordless Login
|
||||
|
@@ -0,0 +1,37 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/config/systemdefaults"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/i18n"
|
||||
iam_model "github.com/caos/zitadel/internal/iam/model"
|
||||
"github.com/caos/zitadel/internal/notification/templates"
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
view_model "github.com/caos/zitadel/internal/user/repository/view/model"
|
||||
)
|
||||
|
||||
type PasswordlessRegistrationLinkData struct {
|
||||
templates.TemplateData
|
||||
URL string
|
||||
}
|
||||
|
||||
func SendPasswordlessRegistrationLink(mailhtml string, translator *i18n.Translator, user *view_model.NotifyUser, code *user.HumanPasswordlessInitCodeRequestedEvent, systemDefaults systemdefaults.SystemDefaults, alg crypto.EncryptionAlgorithm, colors *iam_model.LabelPolicyView, apiDomain string) error {
|
||||
codeString, err := crypto.DecryptString(code.Code, alg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
url := domain.PasswordlessInitCodeLink(systemDefaults.Notifications.Endpoints.PasswordlessRegistration, user.ID, user.ResourceOwner, code.ID, codeString)
|
||||
var args = mapNotifyUserToArgs(user)
|
||||
|
||||
emailCodeData := &PasswordlessRegistrationLinkData{
|
||||
TemplateData: templates.GetTemplateData(translator, args, apiDomain, url, domain.PasswordlessRegistrationMessageType, user.PreferredLanguage, colors),
|
||||
URL: url,
|
||||
}
|
||||
|
||||
template, err := templates.GetParsedTemplate(mailhtml, emailCodeData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return generateEmail(user, emailCodeData.Subject, template, systemDefaults.Notifications, true)
|
||||
}
|
Reference in New Issue
Block a user