mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 20: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:
@@ -1,6 +1,9 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/domain"
|
||||
"github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/repository/user"
|
||||
@@ -430,3 +433,106 @@ func (rm *HumanPasswordlessLoginReadModel) Query() *eventstore.SearchQueryBuilde
|
||||
Builder()
|
||||
|
||||
}
|
||||
|
||||
type HumanPasswordlessInitCodeWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
CodeID string
|
||||
Attempts uint8
|
||||
CryptoCode *crypto.CryptoValue
|
||||
Expiration time.Duration
|
||||
State domain.PasswordlessInitCodeState
|
||||
}
|
||||
|
||||
func NewHumanPasswordlessInitCodeWriteModel(userID, codeID, resourceOwner string) *HumanPasswordlessInitCodeWriteModel {
|
||||
return &HumanPasswordlessInitCodeWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: userID,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
CodeID: codeID,
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *HumanPasswordlessInitCodeWriteModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *user.HumanPasswordlessInitCodeAddedEvent:
|
||||
if wm.CodeID == e.ID {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *user.HumanPasswordlessInitCodeRequestedEvent:
|
||||
if wm.CodeID == e.ID {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *user.HumanPasswordlessInitCodeSentEvent:
|
||||
if wm.CodeID == e.ID {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *user.HumanPasswordlessInitCodeCheckFailedEvent:
|
||||
if wm.CodeID == e.ID {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *user.HumanPasswordlessInitCodeCheckSucceededEvent:
|
||||
if wm.CodeID == e.ID {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *user.UserRemovedEvent:
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *HumanPasswordlessInitCodeWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *user.HumanPasswordlessInitCodeAddedEvent:
|
||||
wm.appendAddedEvent(e)
|
||||
case *user.HumanPasswordlessInitCodeRequestedEvent:
|
||||
wm.appendRequestedEvent(e)
|
||||
case *user.HumanPasswordlessInitCodeSentEvent:
|
||||
wm.State = domain.PasswordlessInitCodeStateActive
|
||||
case *user.HumanPasswordlessInitCodeCheckFailedEvent:
|
||||
wm.appendCheckFailedEvent(e)
|
||||
case *user.HumanPasswordlessInitCodeCheckSucceededEvent:
|
||||
wm.State = domain.PasswordlessInitCodeStateRemoved
|
||||
case *user.UserRemovedEvent:
|
||||
wm.State = domain.PasswordlessInitCodeStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *HumanPasswordlessInitCodeWriteModel) appendAddedEvent(e *user.HumanPasswordlessInitCodeAddedEvent) {
|
||||
wm.CryptoCode = e.Code
|
||||
wm.Expiration = e.Expiry
|
||||
wm.State = domain.PasswordlessInitCodeStateActive
|
||||
}
|
||||
|
||||
func (wm *HumanPasswordlessInitCodeWriteModel) appendRequestedEvent(e *user.HumanPasswordlessInitCodeRequestedEvent) {
|
||||
wm.CryptoCode = e.Code
|
||||
wm.Expiration = e.Expiry
|
||||
wm.State = domain.PasswordlessInitCodeStateRequested
|
||||
}
|
||||
|
||||
func (wm *HumanPasswordlessInitCodeWriteModel) appendCheckFailedEvent(e *user.HumanPasswordlessInitCodeCheckFailedEvent) {
|
||||
wm.Attempts++
|
||||
if wm.Attempts == 3 { //TODO: config?
|
||||
wm.State = domain.PasswordlessInitCodeStateRemoved
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *HumanPasswordlessInitCodeWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(user.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(user.HumanPasswordlessInitCodeAddedType,
|
||||
user.HumanPasswordlessInitCodeRequestedType,
|
||||
user.HumanPasswordlessInitCodeSentType,
|
||||
user.HumanPasswordlessInitCodeCheckFailedType,
|
||||
user.HumanPasswordlessInitCodeCheckSucceededType,
|
||||
user.UserRemovedType).
|
||||
Builder()
|
||||
}
|
||||
|
Reference in New Issue
Block a user