package bouncer import ( "context" "time" ) type userKey struct{} // Principal is the authenticated identity stored on the request context. // PreferredLocale empty means no override. TokensValidAfter zero means no cutoff. // IsSuperuser and PermissionGrants are set only for backend-admin principals. // A grant ending in ".*" matches permission codes by prefix. type Principal struct { ID uint MustChangePassword bool PreferredLocale string TokensValidAfter time.Time IsSuperuser bool `json:"-"` PermissionGrants map[string]bool `json:"-"` } // WithUser stores the verified principal on ctx. func WithUser(ctx context.Context, user *Principal) context.Context { if ctx == nil { ctx = context.Background() } return context.WithValue(ctx, userKey{}, user) } // User returns the verified principal from ctx. func User(ctx context.Context) (*Principal, bool) { if ctx == nil { return nil, false } u, ok := ctx.Value(userKey{}).(*Principal) return u, ok && u != nil } type credentialKey struct{} // WithCredential stores the resolved credential (e.g. *ApiToken) on ctx. func WithCredential(ctx context.Context, cred any) context.Context { if ctx == nil { ctx = context.Background() } return context.WithValue(ctx, credentialKey{}, cred) } // Credential returns the resolved credential from ctx. func Credential(ctx context.Context) (any, bool) { if ctx == nil { return nil, false } c := ctx.Value(credentialKey{}) if c == nil { return nil, false } return c, true }