2023-01-16 11:30:03 +00:00
|
|
|
package query
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
|
2023-10-25 11:42:00 +00:00
|
|
|
"github.com/zitadel/zitadel/internal/api/authz"
|
2023-03-17 09:14:06 +00:00
|
|
|
"github.com/zitadel/zitadel/internal/api/call"
|
2023-10-25 11:42:00 +00:00
|
|
|
"github.com/zitadel/zitadel/internal/errors"
|
2023-01-16 11:30:03 +00:00
|
|
|
"github.com/zitadel/zitadel/internal/eventstore"
|
2023-01-19 15:50:05 +00:00
|
|
|
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
2023-01-16 11:30:03 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Event struct {
|
|
|
|
Editor *EventEditor
|
2023-10-19 10:19:10 +00:00
|
|
|
Aggregate *eventstore.Aggregate
|
2023-01-16 11:30:03 +00:00
|
|
|
Sequence uint64
|
|
|
|
CreationDate time.Time
|
|
|
|
Type string
|
|
|
|
Payload []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
type EventEditor struct {
|
2023-03-17 09:14:06 +00:00
|
|
|
ID string
|
|
|
|
DisplayName string
|
|
|
|
Service string
|
|
|
|
PreferedLoginName string
|
|
|
|
AvatarKey string
|
2023-01-16 11:30:03 +00:00
|
|
|
}
|
|
|
|
|
2023-10-25 11:42:00 +00:00
|
|
|
type eventsReducer struct {
|
|
|
|
ctx context.Context
|
|
|
|
q *Queries
|
|
|
|
events []*Event
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *eventsReducer) AppendEvents(events ...eventstore.Event) {
|
|
|
|
r.events = append(r.events, r.q.convertEvents(r.ctx, events)...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *eventsReducer) Reduce() error { return nil }
|
|
|
|
|
|
|
|
func (q *Queries) SearchEvents(ctx context.Context, query *eventstore.SearchQueryBuilder) (_ []*Event, err error) {
|
2023-01-19 15:50:05 +00:00
|
|
|
ctx, span := tracing.NewSpan(ctx)
|
|
|
|
defer func() { span.EndWithError(err) }()
|
2023-10-25 11:42:00 +00:00
|
|
|
auditLogRetention := q.defaultAuditLogRetention
|
|
|
|
instanceLimits, err := q.Limits(ctx, authz.GetInstance(ctx).InstanceID())
|
|
|
|
if err != nil && !errors.IsNotFound(err) {
|
2023-01-16 11:30:03 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2023-10-25 11:42:00 +00:00
|
|
|
if instanceLimits != nil && instanceLimits.AuditLogRetention != nil {
|
|
|
|
auditLogRetention = *instanceLimits.AuditLogRetention
|
|
|
|
}
|
2023-04-05 17:56:11 +00:00
|
|
|
if auditLogRetention != 0 {
|
2023-10-25 11:42:00 +00:00
|
|
|
query = filterAuditLogRetention(ctx, auditLogRetention, query)
|
2023-04-05 17:56:11 +00:00
|
|
|
}
|
2023-10-25 11:42:00 +00:00
|
|
|
reducer := &eventsReducer{ctx: ctx, q: q}
|
|
|
|
if err = q.eventstore.FilterToReducer(ctx, query, reducer); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return reducer.events, nil
|
2023-04-05 17:56:11 +00:00
|
|
|
}
|
|
|
|
|
2023-10-25 11:42:00 +00:00
|
|
|
func filterAuditLogRetention(ctx context.Context, auditLogRetention time.Duration, builder *eventstore.SearchQueryBuilder) *eventstore.SearchQueryBuilder {
|
2023-03-17 09:14:06 +00:00
|
|
|
callTime := call.FromContext(ctx)
|
|
|
|
if callTime.IsZero() {
|
|
|
|
callTime = time.Now()
|
|
|
|
}
|
2023-11-03 14:52:48 +00:00
|
|
|
oldestAllowed := callTime.Add(-auditLogRetention)
|
|
|
|
// The audit log retention time should overwrite the creation date after query only if it is older
|
|
|
|
// For example API calls should still be able to restrict the creation date after to a more recent date
|
|
|
|
if builder.GetCreationDateAfter().Before(oldestAllowed) {
|
|
|
|
return builder.CreationDateAfter(oldestAllowed)
|
|
|
|
}
|
|
|
|
return builder
|
2023-01-16 11:30:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (q *Queries) SearchEventTypes(ctx context.Context) []string {
|
|
|
|
return q.eventstore.EventTypes()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (q *Queries) SearchAggregateTypes(ctx context.Context) []string {
|
|
|
|
return q.eventstore.AggregateTypes()
|
|
|
|
}
|
|
|
|
|
2023-04-05 17:56:11 +00:00
|
|
|
func (q *Queries) convertEvents(ctx context.Context, events []eventstore.Event) []*Event {
|
2023-01-16 11:30:03 +00:00
|
|
|
result := make([]*Event, len(events))
|
2023-03-17 09:14:06 +00:00
|
|
|
users := make(map[string]*EventEditor)
|
2023-01-16 11:30:03 +00:00
|
|
|
for i, event := range events {
|
2023-01-19 15:50:05 +00:00
|
|
|
result[i] = q.convertEvent(ctx, event, users)
|
2023-01-16 11:30:03 +00:00
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2023-03-17 09:14:06 +00:00
|
|
|
func (q *Queries) convertEvent(ctx context.Context, event eventstore.Event, users map[string]*EventEditor) *Event {
|
2023-01-19 15:50:05 +00:00
|
|
|
ctx, span := tracing.NewSpan(ctx)
|
|
|
|
var err error
|
|
|
|
defer func() { span.EndWithError(err) }()
|
|
|
|
|
2023-10-19 10:19:10 +00:00
|
|
|
editor, ok := users[event.Creator()]
|
2023-01-19 15:50:05 +00:00
|
|
|
if !ok {
|
2023-10-19 10:19:10 +00:00
|
|
|
editor = q.editorUserByID(ctx, event.Creator())
|
|
|
|
users[event.Creator()] = editor
|
2023-01-16 11:30:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return &Event{
|
|
|
|
Editor: &EventEditor{
|
2023-10-19 10:19:10 +00:00
|
|
|
ID: event.Creator(),
|
|
|
|
Service: "zitadel",
|
2023-03-17 09:14:06 +00:00
|
|
|
DisplayName: editor.DisplayName,
|
|
|
|
PreferedLoginName: editor.PreferedLoginName,
|
|
|
|
AvatarKey: editor.AvatarKey,
|
2023-01-16 11:30:03 +00:00
|
|
|
},
|
|
|
|
Aggregate: event.Aggregate(),
|
|
|
|
Sequence: event.Sequence(),
|
2023-10-19 10:19:10 +00:00
|
|
|
CreationDate: event.CreatedAt(),
|
2023-01-16 11:30:03 +00:00
|
|
|
Type: string(event.Type()),
|
|
|
|
Payload: event.DataAsBytes(),
|
|
|
|
}
|
|
|
|
}
|
2023-01-19 15:50:05 +00:00
|
|
|
|
2023-03-17 09:14:06 +00:00
|
|
|
func (q *Queries) editorUserByID(ctx context.Context, userID string) *EventEditor {
|
2023-01-19 15:50:05 +00:00
|
|
|
user, err := q.GetUserByID(ctx, false, userID, false)
|
|
|
|
if err != nil {
|
2023-03-17 09:14:06 +00:00
|
|
|
return &EventEditor{ID: userID}
|
2023-01-19 15:50:05 +00:00
|
|
|
}
|
2023-03-17 09:14:06 +00:00
|
|
|
|
2023-01-19 15:50:05 +00:00
|
|
|
if user.Human != nil {
|
2023-03-17 09:14:06 +00:00
|
|
|
return &EventEditor{
|
|
|
|
ID: user.ID,
|
|
|
|
DisplayName: user.Human.DisplayName,
|
|
|
|
PreferedLoginName: user.PreferredLoginName,
|
|
|
|
AvatarKey: user.Human.AvatarKey,
|
|
|
|
}
|
2023-01-19 15:50:05 +00:00
|
|
|
} else if user.Machine != nil {
|
2023-03-17 09:14:06 +00:00
|
|
|
return &EventEditor{
|
|
|
|
ID: user.ID,
|
|
|
|
DisplayName: user.Machine.Name,
|
|
|
|
PreferedLoginName: user.PreferredLoginName,
|
|
|
|
}
|
2023-01-19 15:50:05 +00:00
|
|
|
}
|
2023-03-17 09:14:06 +00:00
|
|
|
return &EventEditor{ID: userID}
|
2023-01-19 15:50:05 +00:00
|
|
|
}
|