refactor(10.2-01): nest framework packages under modules

- Move remaining beach packages and embedded admin assets\n- Rewrite framework, example, build, and gate paths
This commit is contained in:
Jakub Zych
2026-09-28 02:21:02 +02:00
parent ac1f6d14f4
commit 5e50b166ef
277 changed files with 303 additions and 303 deletions

103
modules/bouncer/registry.go Normal file
View File

@@ -0,0 +1,103 @@
package bouncer
import (
"errors"
"fmt"
"net/http"
"reflect"
)
type namedGuard struct {
pluginID string
g any
}
// Registry stores named Guard / CredentialGuard implementations and derives
// auth middleware from them.
type Registry struct {
guards map[string]namedGuard
}
// NewRegistry returns an empty named-guard registry.
func NewRegistry() *Registry {
return &Registry{guards: make(map[string]namedGuard)}
}
// Register stores g under name. g must implement Guard or CredentialGuard.
// Empty name, nil g, a type implementing neither, or a duplicate name all
// fail with a "bouncer: ..." error naming pluginID and name.
func (reg *Registry) Register(pluginID, name string, g any) error {
if reg == nil {
return fmt.Errorf("bouncer: registry is nil")
}
if name == "" || g == nil {
return fmt.Errorf("bouncer: plugin %q registered empty guard %q", pluginID, name)
}
switch rv := reflect.ValueOf(g); rv.Kind() {
case reflect.Pointer, reflect.Map, reflect.Slice, reflect.Func, reflect.Chan, reflect.Interface:
if rv.IsNil() {
return fmt.Errorf("bouncer: plugin %q registered empty guard %q", pluginID, name)
}
}
_, isGuard := g.(Guard)
_, isCred := g.(CredentialGuard)
if !isGuard && !isCred {
return fmt.Errorf("bouncer: plugin %q registered guard %q that implements neither Guard nor CredentialGuard", pluginID, name)
}
if existing, ok := reg.guards[name]; ok {
return fmt.Errorf("bouncer: guard %q already registered by %s", name, existing.pluginID)
}
if reg.guards == nil {
reg.guards = make(map[string]namedGuard)
}
reg.guards[name] = namedGuard{pluginID: pluginID, g: g}
return nil
}
// Middleware derives an http middleware from a registered guard. Unknown
// names fail (fail boot, mirrors surf.RegisterMiddleware's contract).
// On Authenticate/AuthenticateCredential success: WithUser (+WithCredential
// if a credential was returned) then next.ServeHTTP.
// On failure: if the guard implements UnauthorizedWriter, it writes the
// response and the chain stops; otherwise next.ServeHTTP runs unauthenticated.
func (reg *Registry) Middleware(name string) (func(http.Handler) http.Handler, error) {
if reg == nil {
return nil, fmt.Errorf("bouncer: registry is nil")
}
ng, ok := reg.guards[name]
if !ok {
return nil, fmt.Errorf("bouncer: unknown guard %q", name)
}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
principal, cred, err := authenticate(ng.g, r)
if err != nil || principal == nil {
if wtr, ok := ng.g.(UnauthorizedWriter); ok {
if err == nil {
err = errors.New("unauthenticated")
}
wtr.WriteUnauthorized(w, err)
return
}
next.ServeHTTP(w, r)
return
}
ctx := WithUser(r.Context(), principal)
if cred != nil {
ctx = WithCredential(ctx, cred)
}
next.ServeHTTP(w, r.WithContext(ctx))
})
}, nil
}
func authenticate(g any, r *http.Request) (*Principal, any, error) {
if cg, ok := g.(CredentialGuard); ok {
return cg.AuthenticateCredential(r)
}
if gd, ok := g.(Guard); ok {
p, err := gd.Authenticate(r)
return p, nil, err
}
return nil, nil, fmt.Errorf("bouncer: guard implements neither Guard nor CredentialGuard")
}