mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:47: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:
@@ -96,6 +96,11 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
|
||||
RegisterFilterEventMapper(HumanPasswordlessTokenBeginLoginType, HumanPasswordlessBeginLoginEventMapper).
|
||||
RegisterFilterEventMapper(HumanPasswordlessTokenCheckSucceededType, HumanPasswordlessCheckSucceededEventMapper).
|
||||
RegisterFilterEventMapper(HumanPasswordlessTokenCheckFailedType, HumanPasswordlessCheckFailedEventMapper).
|
||||
RegisterFilterEventMapper(HumanPasswordlessInitCodeAddedType, HumanPasswordlessInitCodeAddedEventMapper).
|
||||
RegisterFilterEventMapper(HumanPasswordlessInitCodeRequestedType, HumanPasswordlessInitCodeRequestedEventMapper).
|
||||
RegisterFilterEventMapper(HumanPasswordlessInitCodeSentType, HumanPasswordlessInitCodeSentEventMapper).
|
||||
RegisterFilterEventMapper(HumanPasswordlessInitCodeCheckFailedType, HumanPasswordlessInitCodeCodeCheckFailedEventMapper).
|
||||
RegisterFilterEventMapper(HumanPasswordlessInitCodeCheckSucceededType, HumanPasswordlessInitCodeCodeCheckSucceededEventMapper).
|
||||
RegisterFilterEventMapper(HumanRefreshTokenAddedType, HumanRefreshTokenAddedEventMapper).
|
||||
RegisterFilterEventMapper(HumanRefreshTokenRenewedType, HumanRefreshTokenRenewedEventEventMapper).
|
||||
RegisterFilterEventMapper(HumanRefreshTokenRemovedType, HumanRefreshTokenRemovedEventEventMapper).
|
||||
|
@@ -2,21 +2,32 @@ package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/repository"
|
||||
)
|
||||
|
||||
const (
|
||||
passwordlessEventPrefix = humanEventPrefix + "passwordless.token."
|
||||
HumanPasswordlessTokenAddedType = passwordlessEventPrefix + "added"
|
||||
HumanPasswordlessTokenVerifiedType = passwordlessEventPrefix + "verified"
|
||||
HumanPasswordlessTokenSignCountChangedType = passwordlessEventPrefix + "signcount.changed"
|
||||
HumanPasswordlessTokenRemovedType = passwordlessEventPrefix + "removed"
|
||||
HumanPasswordlessTokenBeginLoginType = passwordlessEventPrefix + "begin.login"
|
||||
HumanPasswordlessTokenCheckSucceededType = passwordlessEventPrefix + "check.succeeded"
|
||||
HumanPasswordlessTokenCheckFailedType = passwordlessEventPrefix + "check.failed"
|
||||
passwordlessEventPrefix = humanEventPrefix + "passwordless."
|
||||
humanPasswordlessTokenEventPrefix = passwordlessEventPrefix + "token."
|
||||
HumanPasswordlessTokenAddedType = humanPasswordlessTokenEventPrefix + "added"
|
||||
HumanPasswordlessTokenVerifiedType = humanPasswordlessTokenEventPrefix + "verified"
|
||||
HumanPasswordlessTokenSignCountChangedType = humanPasswordlessTokenEventPrefix + "signcount.changed"
|
||||
HumanPasswordlessTokenRemovedType = humanPasswordlessTokenEventPrefix + "removed"
|
||||
HumanPasswordlessTokenBeginLoginType = humanPasswordlessTokenEventPrefix + "begin.login"
|
||||
HumanPasswordlessTokenCheckSucceededType = humanPasswordlessTokenEventPrefix + "check.succeeded"
|
||||
HumanPasswordlessTokenCheckFailedType = humanPasswordlessTokenEventPrefix + "check.failed"
|
||||
humanPasswordlessInitCodePrefix = passwordlessEventPrefix + "initialization.code."
|
||||
HumanPasswordlessInitCodeAddedType = humanPasswordlessInitCodePrefix + "added"
|
||||
HumanPasswordlessInitCodeRequestedType = humanPasswordlessInitCodePrefix + "requested"
|
||||
HumanPasswordlessInitCodeSentType = humanPasswordlessInitCodePrefix + "sent"
|
||||
HumanPasswordlessInitCodeCheckFailedType = humanPasswordlessInitCodePrefix + "check.failed"
|
||||
HumanPasswordlessInitCodeCheckSucceededType = humanPasswordlessInitCodePrefix + "check.succeeded"
|
||||
)
|
||||
|
||||
type HumanPasswordlessAddedEvent struct {
|
||||
@@ -254,3 +265,215 @@ func HumanPasswordlessCheckFailedEventMapper(event *repository.Event) (eventstor
|
||||
|
||||
return &HumanPasswordlessCheckFailedEvent{HumanWebAuthNCheckFailedEvent: *e.(*HumanWebAuthNCheckFailedEvent)}, nil
|
||||
}
|
||||
|
||||
type HumanPasswordlessInitCodeAddedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
ID string `json:"id"`
|
||||
Code *crypto.CryptoValue `json:"code"`
|
||||
Expiry time.Duration `json:"expiry"`
|
||||
}
|
||||
|
||||
func (e *HumanPasswordlessInitCodeAddedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *HumanPasswordlessInitCodeAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHumanPasswordlessInitCodeAddedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id string,
|
||||
code *crypto.CryptoValue,
|
||||
expiry time.Duration,
|
||||
) *HumanPasswordlessInitCodeAddedEvent {
|
||||
return &HumanPasswordlessInitCodeAddedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
HumanPasswordlessInitCodeAddedType,
|
||||
),
|
||||
ID: id,
|
||||
Code: code,
|
||||
Expiry: expiry,
|
||||
}
|
||||
}
|
||||
|
||||
func HumanPasswordlessInitCodeAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
webAuthNAdded := &HumanPasswordlessInitCodeAddedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
err := json.Unmarshal(event.Data, webAuthNAdded)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "USER-BDf32", "unable to unmarshal human passwordless code added")
|
||||
}
|
||||
return webAuthNAdded, nil
|
||||
}
|
||||
|
||||
type HumanPasswordlessInitCodeRequestedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
ID string `json:"id"`
|
||||
Code *crypto.CryptoValue `json:"code"`
|
||||
Expiry time.Duration `json:"expiry"`
|
||||
}
|
||||
|
||||
func (e *HumanPasswordlessInitCodeRequestedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *HumanPasswordlessInitCodeRequestedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHumanPasswordlessInitCodeRequestedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id string,
|
||||
code *crypto.CryptoValue,
|
||||
expiry time.Duration,
|
||||
) *HumanPasswordlessInitCodeRequestedEvent {
|
||||
return &HumanPasswordlessInitCodeRequestedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
HumanPasswordlessInitCodeRequestedType,
|
||||
),
|
||||
ID: id,
|
||||
Code: code,
|
||||
Expiry: expiry,
|
||||
}
|
||||
}
|
||||
|
||||
func HumanPasswordlessInitCodeRequestedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
webAuthNAdded := &HumanPasswordlessInitCodeRequestedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
err := json.Unmarshal(event.Data, webAuthNAdded)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "USER-VGfg3", "unable to unmarshal human passwordless code delivery added")
|
||||
}
|
||||
return webAuthNAdded, nil
|
||||
}
|
||||
|
||||
type HumanPasswordlessInitCodeSentEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
func (e *HumanPasswordlessInitCodeSentEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *HumanPasswordlessInitCodeSentEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHumanPasswordlessInitCodeSentEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id string,
|
||||
) *HumanPasswordlessInitCodeSentEvent {
|
||||
return &HumanPasswordlessInitCodeSentEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
HumanPasswordlessInitCodeSentType,
|
||||
),
|
||||
ID: id,
|
||||
}
|
||||
}
|
||||
|
||||
func HumanPasswordlessInitCodeSentEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
webAuthNAdded := &HumanPasswordlessInitCodeSentEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
err := json.Unmarshal(event.Data, webAuthNAdded)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "USER-Gtg4j", "unable to unmarshal human passwordless code sent")
|
||||
}
|
||||
return webAuthNAdded, nil
|
||||
}
|
||||
|
||||
type HumanPasswordlessInitCodeCheckFailedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
func (e *HumanPasswordlessInitCodeCheckFailedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *HumanPasswordlessInitCodeCheckFailedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHumanPasswordlessInitCodeCheckFailedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id string,
|
||||
) *HumanPasswordlessInitCodeCheckFailedEvent {
|
||||
return &HumanPasswordlessInitCodeCheckFailedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
HumanPasswordlessInitCodeCheckFailedType,
|
||||
),
|
||||
ID: id,
|
||||
}
|
||||
}
|
||||
|
||||
func HumanPasswordlessInitCodeCodeCheckFailedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
webAuthNAdded := &HumanPasswordlessInitCodeCheckFailedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
err := json.Unmarshal(event.Data, webAuthNAdded)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "USER-Gtg4j", "unable to unmarshal human passwordless code check failed")
|
||||
}
|
||||
return webAuthNAdded, nil
|
||||
}
|
||||
|
||||
type HumanPasswordlessInitCodeCheckSucceededEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
func (e *HumanPasswordlessInitCodeCheckSucceededEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *HumanPasswordlessInitCodeCheckSucceededEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewHumanPasswordlessInitCodeCheckSucceededEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id string,
|
||||
) *HumanPasswordlessInitCodeCheckSucceededEvent {
|
||||
return &HumanPasswordlessInitCodeCheckSucceededEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
aggregate,
|
||||
HumanPasswordlessInitCodeCheckSucceededType,
|
||||
),
|
||||
ID: id,
|
||||
}
|
||||
}
|
||||
|
||||
func HumanPasswordlessInitCodeCodeCheckSucceededEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
webAuthNAdded := &HumanPasswordlessInitCodeCheckSucceededEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
err := json.Unmarshal(event.Data, webAuthNAdded)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "USER-Gtg4j", "unable to unmarshal human passwordless code check succeeded")
|
||||
}
|
||||
return webAuthNAdded, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user