Files
patrickandClaude Sonnet 5 8686423112
CI / Core-Modul (Build/Vet/Test) (push) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Canceled after 0s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Canceled after 0s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Canceled after 0s
CI / Web (dms-browser) (push) Canceled after 0s
CI / Web (pdf-viewer) (push) Canceled after 0s
CI / Web (shl) (push) Canceled after 0s
INT-16: tenant-kontext in modul-rueckkanaelen (modulecall, retentionclient, destroy-callback)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 00:20:27 +02:00

67 lines
1.4 KiB
Go

package modulecall
import (
"errors"
"net/http"
"strings"
)
const (
HeaderTenant = "X-Nexarch-Tenant"
HeaderUser = "X-Nexarch-User"
maxLen = 128
)
var (
ErrTenantRequired = errors.New("modulecall: tenant-kontext fehlt")
ErrTenantMismatch = errors.New("modulecall: tenant-kontext passt nicht zur instanz")
)
type Context struct {
Tenant string
User string
}
func valid(s string) bool {
if s == "" || len(s) > maxLen {
return false
}
for _, r := range s {
if r < 0x21 || r == 0x7f {
return false
}
}
return true
}
func Apply(req *http.Request, tc Context, instanceTenant string) error {
if !valid(instanceTenant) || !valid(tc.Tenant) {
return ErrTenantRequired
}
if tc.Tenant != instanceTenant {
return ErrTenantMismatch
}
if tc.User != "" && !valid(tc.User) {
return ErrTenantRequired
}
req.Header.Set(HeaderTenant, tc.Tenant)
if tc.User != "" {
req.Header.Set(HeaderUser, tc.User)
}
return nil
}
func FromRequest(r *http.Request, instanceTenant string) (Context, error) {
if !valid(instanceTenant) {
return Context{}, ErrTenantRequired
}
tenant := strings.TrimSpace(r.Header.Get(HeaderTenant))
if !valid(tenant) {
return Context{}, ErrTenantRequired
}
if tenant != instanceTenant {
return Context{Tenant: tenant}, ErrTenantMismatch
}
return Context{Tenant: tenant, User: strings.TrimSpace(r.Header.Get(HeaderUser))}, nil
}