Files
felhom.eu/hub/internal/api/routes.go
T

85 lines
5.2 KiB
Go

package api
// The box-API route table (hub v0.152.0, R-952, `05` §17.6). EVERY case of ServeHTTP's route switch has one entry,
// in the same order and with the same match, naming WHO may call it. TestAPIRouteTable_MatchesSwitch reads the
// switch from handler.go's syntax tree and fails on a route added without an entry here; TestAPIRoutes_NoCredential
// sends every non-public route a request with no credential and requires a refusal. The table documents and pins;
// each handler still does its own check (the table is not consulted at run time).
//
// An operator access token (fhp_…) is refused on EVERY route here, before the switch (handler.go ServeHTTP).
type apiAuth string
const (
authPublic apiAuth = "public" // no credential by design — the reason is on the entry
authCustomer apiAuth = "customer" // the household's controller key (or the global key)
authHost apiAuth = "host" // the box's own host key, self-scoped (or the global key)
authGlobal apiAuth = "global" // the operator/global key only
authPassphrase apiAuth = "passphrase" // X-Retrieval-Password of that household
authAppliance apiAuth = "appliance" // the appliance's own bearer token
authRecovery apiAuth = "recovery" // only while the operator has armed recovery mode for the host
)
type apiRoute struct {
Method string
Exact, Prefix, Suffix, Contains string
Auth apiAuth
Why string // for authPublic
}
var apiRoutes = []apiRoute{
{Method: "POST", Exact: "/report", Auth: authCustomer},
{Method: "GET", Exact: "/wait", Auth: authCustomer},
{Method: "POST", Exact: "/appliance/register", Auth: authPublic, Why: "a secret-free ISO box registers itself; per-IP rate-limited, answers no enumeration"},
{Method: "GET", Exact: "/appliance/poll", Auth: authAppliance},
{Method: "POST", Exact: "/host-report", Auth: authHost},
{Method: "POST", Exact: "/host-enroll", Auth: authPassphrase},
{Method: "POST", Exact: "/admin/hosts", Auth: authGlobal},
{Method: "PUT", Prefix: "/hosts/", Suffix: "/escrow", Auth: authHost},
{Method: "GET", Prefix: "/hosts/", Suffix: "/escrow", Auth: authHost},
{Method: "GET", Prefix: "/hosts/", Suffix: "/escrow/retained", Auth: authHost},
{Method: "PUT", Prefix: "/hosts/", Suffix: "/recovery-credential", Auth: authHost},
{Method: "GET", Prefix: "/admin/hosts/", Suffix: "/recovery-credential", Auth: authGlobal},
{Method: "PUT", Prefix: "/admin/hosts/", Suffix: "/recovery-mode", Auth: authGlobal},
{Method: "DELETE", Prefix: "/admin/hosts/", Suffix: "/recovery-mode", Auth: authGlobal},
{Method: "POST", Prefix: "/hosts/", Suffix: "/re-enroll", Auth: authRecovery},
{Method: "GET", Prefix: "/hosts/", Suffix: "/restore-directive", Auth: authHost},
{Method: "POST", Prefix: "/hosts/", Suffix: "/wg", Auth: authHost},
{Method: "POST", Prefix: "/hosts/", Suffix: "/pbs/consume-token", Auth: authHost},
{Method: "POST", Prefix: "/hosts/", Suffix: "/os-report", Auth: authHost},
{Method: "GET", Prefix: "/hosts/", Suffix: "/desired-state", Auth: authHost},
{Method: "GET", Prefix: "/hosts/", Suffix: "/jobs", Auth: authHost},
{Method: "DELETE", Prefix: "/hosts/", Contains: "/jobs/", Auth: authHost},
{Method: "PUT", Prefix: "/admin/hosts/", Suffix: "/desired-state", Auth: authGlobal},
{Method: "POST", Prefix: "/admin/hosts/", Suffix: "/jobs", Auth: authGlobal},
{Method: "PUT", Exact: "/admin/wg/endpoint", Auth: authGlobal},
{Method: "GET", Exact: "/admin/wg/endpoint", Auth: authGlobal},
{Method: "POST", Exact: "/admin/wg/peers", Auth: authGlobal},
{Method: "DELETE", Exact: "/admin/wg/peers", Auth: authGlobal},
{Method: "GET", Exact: "/admin/wg/peers", Auth: authGlobal},
{Method: "PUT", Exact: "/admin/wg/operator-peer", Auth: authGlobal},
{Method: "GET", Exact: "/admin/wg/operator-peer", Auth: authGlobal},
{Method: "POST", Exact: "/claim/reset-request", Auth: authCustomer},
{Method: "POST", Exact: "/event", Auth: authCustomer},
{Method: "POST", Exact: "/mail", Auth: authCustomer},
{Method: "POST", Exact: "/notify", Auth: authCustomer},
{Method: "POST", Exact: "/preferences", Auth: authCustomer},
{Method: "GET", Exact: "/customers", Auth: authGlobal},
{Method: "GET", Prefix: "/customers/", Auth: authGlobal},
{Method: "GET", Prefix: "/recovery/", Auth: authPassphrase},
{Method: "GET", Prefix: "/config/", Auth: authPassphrase},
{Method: "GET", Prefix: "/box-config/", Auth: authCustomer},
{Method: "POST", Prefix: "/offsite/consume-password/", Auth: authCustomer},
{Method: "POST", Prefix: "/offsite/register-key/", Auth: authCustomer},
{Method: "POST", Prefix: "/offsite/confirm-key/", Auth: authCustomer},
{Method: "POST", Prefix: "/offsite/move-aside/", Auth: authCustomer},
{Method: "POST", Prefix: "/offsite/window-open/", Auth: authCustomer},
{Method: "POST", Prefix: "/offsite/window-close/", Auth: authCustomer},
{Method: "POST", Prefix: "/offsite/abandon-request/", Auth: authCustomer},
{Method: "POST", Prefix: "/offsite/abandon-cancel/", Auth: authCustomer},
{Method: "POST", Prefix: "/offsite/abandon-status/", Auth: authCustomer},
{Method: "GET", Prefix: "/artifacts/", Auth: authPassphrase},
{Method: "GET", Exact: "/assets/manifest", Auth: authCustomer},
{Method: "GET", Prefix: "/assets/file/", Auth: authCustomer},
}