mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-14 08:07:32 +00:00
chore: move the go code into a subfolder
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/auth/repository/eventsourcing/view"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||
handler2 "github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
query2 "github.com/zitadel/zitadel/internal/query"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Client *database.DB
|
||||
Eventstore *eventstore.Eventstore
|
||||
|
||||
BulkLimit uint64
|
||||
FailureCountUntilSkip uint64
|
||||
TransactionDuration time.Duration
|
||||
Handlers map[string]*ConfigOverwrites
|
||||
|
||||
ActiveInstancer interface {
|
||||
ActiveInstances() []string
|
||||
}
|
||||
}
|
||||
|
||||
type ConfigOverwrites struct {
|
||||
MinimumCycleDuration time.Duration
|
||||
}
|
||||
|
||||
var projections []*handler.Handler
|
||||
|
||||
func Register(ctx context.Context, configs Config, view *view.View, queries *query2.Queries) {
|
||||
// make sure the slice does not contain old values
|
||||
projections = nil
|
||||
|
||||
projections = append(projections, newUser(ctx,
|
||||
configs.overwrite("User"),
|
||||
view,
|
||||
queries,
|
||||
))
|
||||
|
||||
projections = append(projections, newUserSession(ctx,
|
||||
configs.overwrite("UserSession"),
|
||||
view,
|
||||
queries,
|
||||
id.SonyFlakeGenerator(),
|
||||
))
|
||||
|
||||
projections = append(projections, newToken(ctx,
|
||||
configs.overwrite("Token"),
|
||||
view,
|
||||
))
|
||||
|
||||
projections = append(projections, newRefreshToken(ctx,
|
||||
configs.overwrite("RefreshToken"),
|
||||
view,
|
||||
))
|
||||
}
|
||||
|
||||
func Start(ctx context.Context) {
|
||||
for _, projection := range projections {
|
||||
projection.Start(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func Projections() []*handler2.Handler {
|
||||
return projections
|
||||
}
|
||||
|
||||
func ProjectInstance(ctx context.Context) error {
|
||||
for i, projection := range projections {
|
||||
logging.WithFields("name", projection.ProjectionName(), "instance", authz.GetInstance(ctx).InstanceID(), "index", fmt.Sprintf("%d/%d", i, len(projections))).Info("starting auth projection")
|
||||
for {
|
||||
_, err := projection.Trigger(ctx)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
var pgErr *pgconn.PgError
|
||||
errors.As(err, &pgErr)
|
||||
if pgErr.Code != database.PgUniqueConstraintErrorCode {
|
||||
return err
|
||||
}
|
||||
logging.WithFields("name", projection.ProjectionName(), "instance", authz.GetInstance(ctx).InstanceID()).WithError(err).Debug("auth projection failed because of unique constraint, retrying")
|
||||
}
|
||||
logging.WithFields("name", projection.ProjectionName(), "instance", authz.GetInstance(ctx).InstanceID(), "index", fmt.Sprintf("%d/%d", i, len(projections))).Info("auth projection done")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (config Config) overwrite(viewModel string) handler2.Config {
|
||||
c := handler2.Config{
|
||||
Client: config.Client,
|
||||
Eventstore: config.Eventstore,
|
||||
BulkLimit: uint16(config.BulkLimit),
|
||||
RequeueEvery: 3 * time.Minute,
|
||||
MaxFailureCount: uint8(config.FailureCountUntilSkip),
|
||||
TransactionDuration: config.TransactionDuration,
|
||||
ActiveInstancer: config.ActiveInstancer,
|
||||
}
|
||||
overwrite, ok := config.Handlers[viewModel]
|
||||
if !ok {
|
||||
return c
|
||||
}
|
||||
if overwrite.MinimumCycleDuration > 0 {
|
||||
c.RequeueEvery = overwrite.MinimumCycleDuration
|
||||
}
|
||||
return c
|
||||
}
|
@@ -0,0 +1,179 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
auth_view "github.com/zitadel/zitadel/internal/auth/repository/eventsourcing/view"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
"github.com/zitadel/zitadel/internal/repository/user"
|
||||
view_model "github.com/zitadel/zitadel/internal/user/repository/view/model"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
refreshTokenTable = "auth.refresh_tokens"
|
||||
)
|
||||
|
||||
var _ handler.Projection = (*RefreshToken)(nil)
|
||||
|
||||
type RefreshToken struct {
|
||||
view *auth_view.View
|
||||
}
|
||||
|
||||
func newRefreshToken(
|
||||
ctx context.Context,
|
||||
config handler.Config,
|
||||
view *auth_view.View,
|
||||
) *handler.Handler {
|
||||
return handler.NewHandler(
|
||||
ctx,
|
||||
&config,
|
||||
&RefreshToken{
|
||||
view: view,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Name implements [handler.Projection]
|
||||
func (*RefreshToken) Name() string {
|
||||
return refreshTokenTable
|
||||
}
|
||||
|
||||
// Reducers implements [handler.Projection]
|
||||
func (t *RefreshToken) Reducers() []handler.AggregateReducer {
|
||||
return []handler.AggregateReducer{
|
||||
{
|
||||
Aggregate: user.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: user.HumanRefreshTokenAddedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanRefreshTokenRenewedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanRefreshTokenRemovedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserLockedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserDeactivatedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserRemovedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Aggregate: instance.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: instance.InstanceRemovedEventType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Aggregate: org.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: org.OrgRemovedEventType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *RefreshToken) Reduce(event eventstore.Event) (_ *handler.Statement, err error) {
|
||||
// in case anything needs to be change here check if appendEvent function needs the change as well
|
||||
switch event.Type() {
|
||||
case user.HumanRefreshTokenAddedType:
|
||||
e, ok := event.(*user.HumanRefreshTokenAddedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-IoF6j", "reduce.wrong.event.type %s", user.HumanRefreshTokenAddedType)
|
||||
}
|
||||
columns := []handler.Column{
|
||||
handler.NewCol(view_model.RefreshTokenKeyClientID, e.ClientID),
|
||||
handler.NewCol(view_model.RefreshTokenKeyUserAgentID, e.UserAgentID),
|
||||
handler.NewCol(view_model.RefreshTokenKeyUserID, e.Aggregate().ID),
|
||||
handler.NewCol(view_model.RefreshTokenKeyInstanceID, e.Aggregate().InstanceID),
|
||||
handler.NewCol(view_model.RefreshTokenKeyTokenID, e.TokenID),
|
||||
handler.NewCol(view_model.RefreshTokenKeyResourceOwner, e.Aggregate().ResourceOwner),
|
||||
handler.NewCol(view_model.RefreshTokenKeyCreationDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.RefreshTokenKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.RefreshTokenKeySequence, event.Sequence()),
|
||||
handler.NewCol(view_model.RefreshTokenKeyAMR, e.AuthMethodsReferences),
|
||||
handler.NewCol(view_model.RefreshTokenKeyAuthTime, e.AuthTime),
|
||||
handler.NewCol(view_model.RefreshTokenKeyAudience, e.Audience),
|
||||
handler.NewCol(view_model.RefreshTokenKeyExpiration, event.CreatedAt().Add(e.Expiration)),
|
||||
handler.NewCol(view_model.RefreshTokenKeyIdleExpiration, event.CreatedAt().Add(e.IdleExpiration)),
|
||||
handler.NewCol(view_model.RefreshTokenKeyScopes, e.Scopes),
|
||||
handler.NewCol(view_model.RefreshTokenKeyToken, e.TokenID),
|
||||
handler.NewCol(view_model.RefreshTokenKeyActor, view_model.TokenActor{TokenActor: e.Actor}),
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.HumanRefreshTokenRenewedType:
|
||||
e, ok := event.(*user.HumanRefreshTokenRenewedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-AG43hq", "reduce.wrong.event.type %s", user.HumanRefreshTokenRenewedType)
|
||||
}
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.RefreshTokenKeyIdleExpiration, event.CreatedAt().Add(e.IdleExpiration)),
|
||||
handler.NewCol(view_model.RefreshTokenKeyToken, e.RefreshToken),
|
||||
handler.NewCol(view_model.RefreshTokenKeyChangeDate, e.CreatedAt()),
|
||||
handler.NewCol(view_model.RefreshTokenKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.RefreshTokenKeyTokenID, e.TokenID),
|
||||
handler.NewCond(view_model.RefreshTokenKeyInstanceID, e.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
case user.HumanRefreshTokenRemovedType:
|
||||
e, ok := event.(*user.HumanRefreshTokenRemovedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-SFF3t", "reduce.wrong.event.type %s", user.HumanRefreshTokenRemovedType)
|
||||
}
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.RefreshTokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.RefreshTokenKeyTokenID, e.TokenID),
|
||||
},
|
||||
), nil
|
||||
case user.UserLockedType,
|
||||
user.UserDeactivatedType,
|
||||
user.UserRemovedType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.RefreshTokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.RefreshTokenKeyUserID, event.Aggregate().ID),
|
||||
},
|
||||
), nil
|
||||
case instance.InstanceRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.RefreshTokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
case org.OrgRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.RefreshTokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.RefreshTokenKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
},
|
||||
), nil
|
||||
default:
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
}
|
361
apps/api/internal/auth/repository/eventsourcing/handler/token.go
Normal file
361
apps/api/internal/auth/repository/eventsourcing/handler/token.go
Normal file
@@ -0,0 +1,361 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
auth_view "github.com/zitadel/zitadel/internal/auth/repository/eventsourcing/view"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||
es_models "github.com/zitadel/zitadel/internal/eventstore/v1/models"
|
||||
proj_model "github.com/zitadel/zitadel/internal/project/model"
|
||||
project_es_model "github.com/zitadel/zitadel/internal/project/repository/eventsourcing/model"
|
||||
proj_view "github.com/zitadel/zitadel/internal/project/repository/view"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
"github.com/zitadel/zitadel/internal/repository/user"
|
||||
view_model "github.com/zitadel/zitadel/internal/user/repository/view/model"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
tokenTable = "auth.tokens"
|
||||
)
|
||||
|
||||
var _ handler.Projection = (*Token)(nil)
|
||||
|
||||
type Token struct {
|
||||
view *auth_view.View
|
||||
es handler.EventStore
|
||||
}
|
||||
|
||||
func newToken(
|
||||
ctx context.Context,
|
||||
config handler.Config,
|
||||
view *auth_view.View,
|
||||
) *handler.Handler {
|
||||
return handler.NewHandler(
|
||||
ctx,
|
||||
&config,
|
||||
&Token{
|
||||
view: view,
|
||||
es: config.Eventstore,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Name implements [handler.Projection]
|
||||
func (*Token) Name() string {
|
||||
return tokenTable
|
||||
}
|
||||
|
||||
// Reducers implements [handler.Projection]
|
||||
func (t *Token) Reducers() []handler.AggregateReducer {
|
||||
return []handler.AggregateReducer{
|
||||
{
|
||||
Aggregate: user.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: user.PersonalAccessTokenAddedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserTokenAddedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserV1ProfileChangedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanProfileChangedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserV1SignedOutType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanSignedOutType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserLockedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserDeactivatedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserRemovedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserTokenRemovedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.PersonalAccessTokenRemovedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanRefreshTokenRemovedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Aggregate: project.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: project.ApplicationDeactivatedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: project.ApplicationRemovedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: project.ProjectDeactivatedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
{
|
||||
Event: project.ProjectRemovedType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Aggregate: org.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: org.OrgRemovedEventType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Aggregate: instance.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: instance.InstanceRemovedEventType,
|
||||
Reduce: t.Reduce,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Token) Reduce(event eventstore.Event) (_ *handler.Statement, err error) { //nolint:gocognit
|
||||
// in case anything needs to be change here check if appendEvent function needs the change as well
|
||||
switch event.Type() {
|
||||
case user.UserTokenAddedType:
|
||||
e, ok := event.(*user.UserTokenAddedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-W4tnq", "reduce.wrong.event.type %s", user.UserTokenAddedType)
|
||||
}
|
||||
return handler.NewCreateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCol(view_model.TokenKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCol(view_model.TokenKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
handler.NewCol(view_model.TokenKeyID, e.TokenID),
|
||||
handler.NewCol(view_model.TokenKeyCreationDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.TokenKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.TokenKeySequence, event.Sequence()),
|
||||
handler.NewCol(view_model.TokenKeyApplicationID, e.ApplicationID),
|
||||
handler.NewCol(view_model.TokenKeyUserAgentID, e.UserAgentID),
|
||||
handler.NewCol(view_model.TokenKeyAudience, e.Audience),
|
||||
handler.NewCol(view_model.TokenKeyScopes, e.Scopes),
|
||||
handler.NewCol(view_model.TokenKeyExpiration, e.Expiration),
|
||||
handler.NewCol(view_model.TokenKeyPreferredLanguage, e.PreferredLanguage),
|
||||
handler.NewCol(view_model.TokenKeyRefreshTokenID, e.RefreshTokenID),
|
||||
handler.NewCol(view_model.TokenKeyActor, view_model.TokenActor{TokenActor: e.Actor}),
|
||||
handler.NewCol(view_model.TokenKeyIsPat, false),
|
||||
},
|
||||
), nil
|
||||
case user.PersonalAccessTokenAddedType:
|
||||
e, ok := event.(*user.PersonalAccessTokenAddedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-zF3rb", "reduce.wrong.event.type %s", user.PersonalAccessTokenAddedType)
|
||||
}
|
||||
return handler.NewCreateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCol(view_model.TokenKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCol(view_model.TokenKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
handler.NewCol(view_model.TokenKeyID, e.TokenID),
|
||||
handler.NewCol(view_model.TokenKeyCreationDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.TokenKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.TokenKeySequence, event.Sequence()),
|
||||
handler.NewCol(view_model.TokenKeyScopes, e.Scopes),
|
||||
handler.NewCol(view_model.TokenKeyExpiration, e.Expiration),
|
||||
handler.NewCol(view_model.TokenKeyIsPat, true),
|
||||
},
|
||||
), nil
|
||||
case user.UserV1ProfileChangedType,
|
||||
user.HumanProfileChangedType:
|
||||
e, ok := event.(*user.HumanProfileChangedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-ASF2t", "reduce.wrong.event.type %s", user.HumanProfileChangedType)
|
||||
}
|
||||
if e.PreferredLanguage == nil {
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.TokenKeyPreferredLanguage, gu.Value(e.PreferredLanguage).String()),
|
||||
handler.NewCol(view_model.TokenKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.TokenKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, e.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyUserID, e.Aggregate().ID),
|
||||
},
|
||||
), nil
|
||||
case user.UserV1SignedOutType,
|
||||
user.HumanSignedOutType:
|
||||
e, ok := event.(*user.HumanSignedOutEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-Wtn2q", "reduce.wrong.event.type %s", user.HumanSignedOutType)
|
||||
}
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCond(view_model.TokenKeyUserAgentID, e.UserAgentID),
|
||||
},
|
||||
), nil
|
||||
case user.UserLockedType,
|
||||
user.UserDeactivatedType,
|
||||
user.UserRemovedType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyUserID, event.Aggregate().ID),
|
||||
},
|
||||
), nil
|
||||
case user.UserTokenRemovedType,
|
||||
user.PersonalAccessTokenRemovedType:
|
||||
var tokenID string
|
||||
switch e := event.(type) {
|
||||
case *user.UserTokenRemovedEvent:
|
||||
tokenID = e.TokenID
|
||||
case *user.PersonalAccessTokenRemovedEvent:
|
||||
tokenID = e.TokenID
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-SF3ga", "reduce.wrong.event.type %s", user.UserTokenRemovedType)
|
||||
}
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyID, tokenID),
|
||||
},
|
||||
), nil
|
||||
case user.HumanRefreshTokenRemovedType:
|
||||
e, ok := event.(*user.HumanRefreshTokenRemovedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-Sfe11", "reduce.wrong.event.type %s", user.HumanRefreshTokenRemovedType)
|
||||
}
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyRefreshTokenID, e.TokenID),
|
||||
},
|
||||
), nil
|
||||
case project.ApplicationDeactivatedType,
|
||||
project.ApplicationRemovedType:
|
||||
var applicationID string
|
||||
switch e := event.(type) {
|
||||
case *project.ApplicationDeactivatedEvent:
|
||||
applicationID = e.AppID
|
||||
case *project.ApplicationRemovedEvent:
|
||||
applicationID = e.AppID
|
||||
default:
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-SF3fq", "reduce.wrong.event.type %v", []eventstore.EventType{project.ApplicationDeactivatedType, project.ApplicationRemovedType})
|
||||
}
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyApplicationID, applicationID),
|
||||
},
|
||||
), nil
|
||||
case project.ProjectDeactivatedType,
|
||||
project.ProjectRemovedType:
|
||||
project, err := t.getProjectByID(context.Background(), event.Aggregate().ID, event.Aggregate().InstanceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
applicationIDs := make([]string, 0, len(project.Applications))
|
||||
for _, app := range project.Applications {
|
||||
if app.OIDCConfig != nil && app.OIDCConfig.ClientID != "" {
|
||||
applicationIDs = append(applicationIDs, app.OIDCConfig.ClientID)
|
||||
}
|
||||
}
|
||||
if len(applicationIDs) == 0 {
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewOneOfTextCond(view_model.TokenKeyApplicationID, applicationIDs),
|
||||
},
|
||||
), nil
|
||||
case instance.InstanceRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
case org.OrgRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.TokenKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.TokenKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
},
|
||||
), nil
|
||||
default:
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
}
|
||||
|
||||
type userAgentIDPayload struct {
|
||||
ID string `json:"userAgentID"`
|
||||
}
|
||||
|
||||
func agentIDFromSession(event eventstore.Event) (string, error) {
|
||||
payload := new(userAgentIDPayload)
|
||||
if err := event.Unmarshal(payload); err != nil {
|
||||
logging.WithError(err).Error("could not unmarshal event data")
|
||||
return "", zerrors.ThrowInternal(nil, "MODEL-sd325", "could not unmarshal data")
|
||||
}
|
||||
return payload.ID, nil
|
||||
}
|
||||
|
||||
func (t *Token) getProjectByID(ctx context.Context, projID, instanceID string) (*proj_model.Project, error) {
|
||||
query, err := proj_view.ProjectByIDQuery(projID, instanceID, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
esProject := &project_es_model.Project{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: projID,
|
||||
},
|
||||
}
|
||||
events, err := t.es.Filter(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = esProject.AppendEvents(events...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if esProject.Sequence == 0 {
|
||||
return nil, zerrors.ThrowNotFound(nil, "EVENT-Dsdw2", "Errors.Project.NotFound")
|
||||
}
|
||||
return project_es_model.ProjectToModel(esProject), nil
|
||||
}
|
306
apps/api/internal/auth/repository/eventsourcing/handler/user.go
Normal file
306
apps/api/internal/auth/repository/eventsourcing/handler/user.go
Normal file
@@ -0,0 +1,306 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
auth_view "github.com/zitadel/zitadel/internal/auth/repository/eventsourcing/view"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||
query2 "github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
user_repo "github.com/zitadel/zitadel/internal/repository/user"
|
||||
view_model "github.com/zitadel/zitadel/internal/user/repository/view/model"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
userTable = "auth.users3"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
view *auth_view.View
|
||||
queries *query2.Queries
|
||||
es handler.EventStore
|
||||
}
|
||||
|
||||
var _ handler.Projection = (*User)(nil)
|
||||
|
||||
func newUser(
|
||||
ctx context.Context,
|
||||
config handler.Config,
|
||||
view *auth_view.View,
|
||||
queries *query2.Queries,
|
||||
) *handler.Handler {
|
||||
return handler.NewHandler(
|
||||
ctx,
|
||||
&config,
|
||||
&User{
|
||||
view: view,
|
||||
queries: queries,
|
||||
es: config.Eventstore,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (*User) Name() string {
|
||||
return userTable
|
||||
}
|
||||
func (u *User) Reducers() []handler.AggregateReducer {
|
||||
return []handler.AggregateReducer{
|
||||
{
|
||||
Aggregate: user_repo.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: user_repo.HumanOTPSMSRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanOTPEmailRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanAddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1AddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1RegisteredType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanRegisteredType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1PhoneRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1MFAOTPVerifiedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1MFAInitSkippedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1PasswordChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanPhoneRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanMFAOTPVerifiedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanU2FTokenVerifiedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanMFAInitSkippedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanPasswordChangedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanInitialCodeAddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1InitialCodeAddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserV1InitializedCheckSucceededType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanInitializedCheckSucceededType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanPasswordlessInitCodeAddedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.HumanPasswordlessInitCodeRequestedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
{
|
||||
Event: user_repo.UserRemovedType,
|
||||
Reduce: u.ProcessUser,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Aggregate: org.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: org.OrgRemovedEventType,
|
||||
Reduce: u.ProcessOrg,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Aggregate: instance.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: instance.InstanceRemovedEventType,
|
||||
Reduce: u.ProcessInstance,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gocognit
|
||||
func (u *User) ProcessUser(event eventstore.Event) (_ *handler.Statement, err error) {
|
||||
// in case anything needs to be change here check if appendEvent function needs the change as well
|
||||
switch event.Type() {
|
||||
case user_repo.UserV1AddedType,
|
||||
user_repo.HumanAddedType:
|
||||
e, ok := event.(*user_repo.HumanAddedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-SDAGF", "reduce.wrong.event.type %s", user_repo.HumanAddedType)
|
||||
}
|
||||
return u.setPasswordData(event, e.Secret, e.EncodedHash), nil
|
||||
case user_repo.UserV1RegisteredType,
|
||||
user_repo.HumanRegisteredType:
|
||||
e, ok := event.(*user_repo.HumanRegisteredEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-AS1hz", "reduce.wrong.event.type %s", user_repo.HumanRegisteredType)
|
||||
}
|
||||
return u.setPasswordData(event, e.Secret, e.EncodedHash), nil
|
||||
case user_repo.UserV1PasswordChangedType,
|
||||
user_repo.HumanPasswordChangedType:
|
||||
e, ok := event.(*user_repo.HumanPasswordChangedEvent)
|
||||
if !ok {
|
||||
return nil, zerrors.ThrowInvalidArgumentf(nil, "MODEL-Gd31w", "reduce.wrong.event.type %s", user_repo.HumanPasswordChangedType)
|
||||
}
|
||||
return u.setPasswordData(event, e.Secret, e.EncodedHash), nil
|
||||
case user_repo.UserV1PhoneRemovedType,
|
||||
user_repo.HumanPhoneRemovedType,
|
||||
user_repo.UserV1MFAOTPVerifiedType,
|
||||
user_repo.HumanMFAOTPVerifiedType,
|
||||
user_repo.HumanOTPSMSRemovedType,
|
||||
user_repo.HumanOTPEmailRemovedType,
|
||||
user_repo.HumanU2FTokenVerifiedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserKeyMFAInitSkipped, time.Time{}),
|
||||
handler.NewCol(view_model.UserKeyChangeDate, event.CreatedAt()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
}), nil
|
||||
case user_repo.UserV1MFAInitSkippedType,
|
||||
user_repo.HumanMFAInitSkippedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserKeyMFAInitSkipped, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserKeyChangeDate, event.CreatedAt()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
}), nil
|
||||
case user_repo.UserV1InitialCodeAddedType,
|
||||
user_repo.HumanInitialCodeAddedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserKeyInitRequired, true),
|
||||
handler.NewCol(view_model.UserKeyChangeDate, event.CreatedAt()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
}), nil
|
||||
case user_repo.UserV1InitializedCheckSucceededType,
|
||||
user_repo.HumanInitializedCheckSucceededType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserKeyInitRequired, false),
|
||||
handler.NewCol(view_model.UserKeyChangeDate, event.CreatedAt()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
}), nil
|
||||
case user_repo.HumanPasswordlessInitCodeAddedType,
|
||||
user_repo.HumanPasswordlessInitCodeRequestedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserKeyPasswordlessInitRequired, true),
|
||||
handler.NewCol(view_model.UserKeyPasswordInitRequired, false),
|
||||
handler.NewCol(view_model.UserKeyChangeDate, event.CreatedAt()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCond(view_model.UserKeyPasswordSet, false),
|
||||
}), nil
|
||||
case user_repo.UserRemovedType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
}), nil
|
||||
default:
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) setPasswordData(event eventstore.Event, secret *crypto.CryptoValue, hash string) *handler.Statement {
|
||||
set := secret != nil || hash != ""
|
||||
columns := []handler.Column{
|
||||
handler.NewCol(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCol(view_model.UserKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCol(view_model.UserKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
handler.NewCol(view_model.UserKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserKeyPasswordSet, set),
|
||||
handler.NewCol(view_model.UserKeyPasswordInitRequired, !set),
|
||||
handler.NewCol(view_model.UserKeyPasswordChange, event.CreatedAt()),
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:2], columns)
|
||||
}
|
||||
|
||||
func (u *User) ProcessOrg(event eventstore.Event) (_ *handler.Statement, err error) {
|
||||
// in case anything needs to be change here check if appendEvent function needs the change as well
|
||||
switch event.Type() {
|
||||
case org.OrgRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserKeyResourceOwner, event.Aggregate().ID),
|
||||
},
|
||||
), nil
|
||||
default:
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) ProcessInstance(event eventstore.Event) (_ *handler.Statement, err error) {
|
||||
// in case anything needs to be change here check if appendEvent function needs the change as well
|
||||
switch event.Type() {
|
||||
case instance.InstanceRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserKeyInstanceID, event.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
default:
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
}
|
@@ -0,0 +1,477 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
auth_view "github.com/zitadel/zitadel/internal/auth/repository/eventsourcing/view"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
query2 "github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
"github.com/zitadel/zitadel/internal/repository/user"
|
||||
es_model "github.com/zitadel/zitadel/internal/user/repository/eventsourcing/model"
|
||||
view_model "github.com/zitadel/zitadel/internal/user/repository/view/model"
|
||||
)
|
||||
|
||||
const (
|
||||
userSessionTable = "auth.user_sessions"
|
||||
|
||||
IDPrefixV1 = "V1_"
|
||||
)
|
||||
|
||||
type UserSession struct {
|
||||
queries *query2.Queries
|
||||
view *auth_view.View
|
||||
es handler.EventStore
|
||||
idGenerator id.Generator
|
||||
}
|
||||
|
||||
var _ handler.Projection = (*UserSession)(nil)
|
||||
|
||||
func newUserSession(
|
||||
ctx context.Context,
|
||||
config handler.Config,
|
||||
view *auth_view.View,
|
||||
queries *query2.Queries,
|
||||
idGenerator id.Generator,
|
||||
) *handler.Handler {
|
||||
return handler.NewHandler(
|
||||
ctx,
|
||||
&config,
|
||||
&UserSession{
|
||||
queries: queries,
|
||||
view: view,
|
||||
es: config.Eventstore,
|
||||
idGenerator: idGenerator,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// Name implements [handler.Projection]
|
||||
func (*UserSession) Name() string {
|
||||
return userSessionTable
|
||||
}
|
||||
|
||||
// Reducers implements [handler.Projection]
|
||||
func (s *UserSession) Reducers() []handler.AggregateReducer {
|
||||
return []handler.AggregateReducer{
|
||||
{
|
||||
Aggregate: user.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: user.UserV1PasswordCheckSucceededType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserV1PasswordCheckFailedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserV1MFAOTPCheckSucceededType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserV1MFAOTPCheckFailedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserV1SignedOutType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanPasswordCheckSucceededType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanPasswordCheckFailedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserIDPLoginCheckSucceededType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanMFAOTPCheckSucceededType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanMFAOTPCheckFailedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanU2FTokenCheckSucceededType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanU2FTokenCheckFailedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanPasswordlessTokenCheckSucceededType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanPasswordlessTokenCheckFailedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanSignedOutType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserV1PasswordChangedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserV1MFAOTPRemovedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserLockedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserDeactivatedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanPasswordChangedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanMFAOTPRemovedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserIDPLinkRemovedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserIDPLinkCascadeRemovedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanPasswordlessTokenRemovedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanU2FTokenRemovedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.UserRemovedType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
{
|
||||
Event: user.HumanRegisteredType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Aggregate: org.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: org.OrgRemovedEventType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Aggregate: instance.AggregateType,
|
||||
EventReducers: []handler.EventReducer{
|
||||
{
|
||||
Event: instance.InstanceRemovedEventType,
|
||||
Reduce: s.Reduce,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UserSession) sessionColumns(event eventstore.Event, columns ...handler.Column) ([]handler.Column, error) {
|
||||
userAgent, err := agentIDFromSession(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append([]handler.Column{
|
||||
handler.NewCol(view_model.UserSessionKeyUserAgentID, userAgent),
|
||||
handler.NewCol(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCol(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCol(view_model.UserSessionKeyCreationDate, handler.OnlySetValueOnInsert(userSessionTable, event.CreatedAt())),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
}, columns...), nil
|
||||
}
|
||||
|
||||
func (u *UserSession) sessionColumnsActivate(event eventstore.Event, columns ...handler.Column) ([]handler.Column, error) {
|
||||
sessionID, err := u.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sessionID = IDPrefixV1 + sessionID
|
||||
columns = slices.Grow(columns, 2)
|
||||
columns = append(columns,
|
||||
handler.NewCol(view_model.UserSessionKeyState, domain.UserSessionStateActive),
|
||||
handler.NewCol(view_model.UserSessionKeyID,
|
||||
handler.OnlySetValueInCase(userSessionTable, sessionID,
|
||||
handler.ConditionOr(
|
||||
handler.ColumnChangedCondition(userSessionTable, view_model.UserSessionKeyState, domain.UserSessionStateTerminated, domain.UserSessionStateActive),
|
||||
handler.ColumnIsNullCondition(userSessionTable, view_model.UserSessionKeyID),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
return u.sessionColumns(event, columns...)
|
||||
}
|
||||
|
||||
func (u *UserSession) Reduce(event eventstore.Event) (_ *handler.Statement, err error) {
|
||||
// in case anything needs to be change here check if appendEvent function needs the change as well
|
||||
switch event.Type() {
|
||||
case user.UserV1PasswordCheckSucceededType,
|
||||
user.HumanPasswordCheckSucceededType:
|
||||
columns, err := u.sessionColumnsActivate(event,
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, event.CreatedAt()),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.UserV1PasswordCheckFailedType,
|
||||
user.HumanPasswordCheckFailedType:
|
||||
columns, err := u.sessionColumnsActivate(event,
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, time.Time{}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.UserV1MFAOTPCheckSucceededType,
|
||||
user.HumanMFAOTPCheckSucceededType:
|
||||
columns, err := u.sessionColumnsActivate(event,
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerificationType, domain.MFATypeTOTP),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.UserV1MFAOTPCheckFailedType,
|
||||
user.HumanMFAOTPCheckFailedType,
|
||||
user.HumanU2FTokenCheckFailedType:
|
||||
columns, err := u.sessionColumnsActivate(event,
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerification, time.Time{}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.UserV1SignedOutType,
|
||||
user.HumanSignedOutType:
|
||||
columns, err := u.sessionColumns(event,
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordlessVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerificationType, domain.MFALevelNotSetUp),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerificationType, domain.MFALevelNotSetUp),
|
||||
handler.NewCol(view_model.UserSessionKeyExternalLoginVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyState, domain.UserSessionStateTerminated),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.UserIDPLoginCheckSucceededType:
|
||||
data := new(es_model.AuthRequest)
|
||||
err := data.SetData(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columns, err := u.sessionColumnsActivate(event,
|
||||
handler.NewCol(view_model.UserSessionKeyExternalLoginVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySelectedIDPConfigID, data.SelectedIDPConfigID),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.HumanU2FTokenCheckSucceededType:
|
||||
data := new(es_model.AuthRequest)
|
||||
err := data.SetData(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columns, err := u.sessionColumnsActivate(event,
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerificationType, domain.MFATypeU2F),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.HumanPasswordlessTokenCheckSucceededType:
|
||||
data := new(es_model.AuthRequest)
|
||||
err := data.SetData(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columns, err := u.sessionColumnsActivate(event,
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordlessVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerificationType, domain.MFATypeU2FUserVerification),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.HumanPasswordlessTokenCheckFailedType:
|
||||
data := new(es_model.AuthRequest)
|
||||
err := data.SetData(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
columns, err := u.sessionColumnsActivate(event,
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordlessVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerification, time.Time{}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewUpsertStatement(event, columns[0:3], columns), nil
|
||||
case user.UserLockedType,
|
||||
user.UserDeactivatedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordlessVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerificationType, domain.MFALevelNotSetUp),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerificationType, domain.MFALevelNotSetUp),
|
||||
handler.NewCol(view_model.UserSessionKeyExternalLoginVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyState, domain.UserSessionStateTerminated),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond(view_model.UserSessionKeyState, domain.UserSessionStateTerminated)),
|
||||
},
|
||||
), nil
|
||||
case user.UserV1PasswordChangedType,
|
||||
user.HumanPasswordChangedType:
|
||||
userAgent, err := agentIDFromSession(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewMultiStatement(event,
|
||||
handler.AddUpdateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserAgentID, userAgent),
|
||||
}),
|
||||
handler.AddUpdateStatement(
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond(view_model.UserSessionKeyUserAgentID, userAgent)),
|
||||
handler.Not(handler.NewCond(view_model.UserSessionKeyState, domain.UserSessionStateTerminated)),
|
||||
}),
|
||||
), nil
|
||||
case user.UserV1MFAOTPRemovedType,
|
||||
user.HumanMFAOTPRemovedType,
|
||||
user.HumanU2FTokenRemovedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserSessionKeySecondFactorVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond(view_model.UserSessionKeyState, domain.UserSessionStateTerminated)),
|
||||
},
|
||||
), nil
|
||||
case user.UserIDPLinkRemovedType,
|
||||
user.UserIDPLinkCascadeRemovedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserSessionKeyExternalLoginVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeySelectedIDPConfigID, ""),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond(view_model.UserSessionKeySelectedIDPConfigID, "")),
|
||||
},
|
||||
), nil
|
||||
case user.HumanPasswordlessTokenRemovedType:
|
||||
return handler.NewUpdateStatement(event,
|
||||
[]handler.Column{
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordlessVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyMultiFactorVerification, time.Time{}),
|
||||
handler.NewCol(view_model.UserSessionKeyChangeDate, event.CreatedAt()),
|
||||
handler.NewCol(view_model.UserSessionKeySequence, event.Sequence()),
|
||||
},
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
handler.Not(handler.NewCond(view_model.UserSessionKeyState, domain.UserSessionStateTerminated)),
|
||||
},
|
||||
), nil
|
||||
case user.UserRemovedType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyUserID, event.Aggregate().ID),
|
||||
},
|
||||
), nil
|
||||
case user.HumanRegisteredType:
|
||||
columns, err := u.sessionColumnsActivate(event,
|
||||
handler.NewCol(view_model.UserSessionKeyPasswordVerification, event.CreatedAt()),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return handler.NewCreateStatement(event,
|
||||
columns,
|
||||
), nil
|
||||
case instance.InstanceRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
},
|
||||
), nil
|
||||
case org.OrgRemovedEventType:
|
||||
return handler.NewDeleteStatement(event,
|
||||
[]handler.Condition{
|
||||
handler.NewCond(view_model.UserSessionKeyInstanceID, event.Aggregate().InstanceID),
|
||||
handler.NewCond(view_model.UserSessionKeyResourceOwner, event.Aggregate().ResourceOwner),
|
||||
},
|
||||
), nil
|
||||
default:
|
||||
return handler.NewNoOpStatement(event), nil
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user