mirror of
https://github.com/hanzoai/base.git
synced 2026-10-21 03:41:50 +00:00
What such a key may reach was a list of addresses kept in the rule that reads it. The list held Base's own routes and nothing else, so bootnode's twelve reads — which it registers precisely to be reachable that way, and guards with a read-only refusal beside each of its eleven writes — answered 403 wherever the plugin was on. A list of one package's addresses kept in another goes stale the moment that package mounts a route, and it goes stale silently. So the answer moves to the route: apis.Public declares one where it is registered, and the rule holds no addresses at all. Bootnode declares its twelve reads; Base declares its records, rest, files and health reads. The rule keeps one address of its own, the public submit path, because whether it is public is the collection's statement and not the route's. A route needs to know its whole address for that, so the mux records it as it mounts: Route.Pattern is the method, the group prefixes and the path, the same string a request reports having matched. Second layer, restored: bootnode read ReadOnly off the identity headers, which the org plugin writes identically for every key it resolves — so a publishable key arrived as a person and no read-only refusal could fire. The headers say who; the credential says what kind. Co-authored-by: Hanzo Dev <[email protected]>
60 lines
1.9 KiB
Go
60 lines
1.9 KiB
Go
package apis
|
|
|
|
import (
|
|
"net/http"
|
|
"sync"
|
|
|
|
"github.com/hanzoai/base/core"
|
|
"github.com/hanzoai/base/tools/router"
|
|
)
|
|
|
|
// declared are the routes a publishable credential may reach. It starts empty:
|
|
// an address nobody declared is an address such a credential is refused.
|
|
var declared struct {
|
|
sync.RWMutex
|
|
routes []*router.Route[*core.RequestEvent]
|
|
}
|
|
|
|
// Public declares that a publishable credential — a key printed in a web page —
|
|
// may reach these routes. It is stated where the route is registered:
|
|
//
|
|
// Public(g.GET("/chains", p.handleListChains))
|
|
//
|
|
// so that the product owning a route owns the answer about it, and the address
|
|
// is written once. The alternative was a list of another package's addresses
|
|
// kept in the rule: it went stale the moment a plugin mounted a route, which is
|
|
// how twelve reads meant to be reachable by such a key answered 403.
|
|
//
|
|
// The routes are read back by their mounted [router.Route.Pattern], which is
|
|
// assembled by the mux and is what a request reports having matched, so a
|
|
// pattern that merely ends the same way is a different route.
|
|
func Public(routes ...*router.Route[*core.RequestEvent]) {
|
|
declared.Lock()
|
|
declared.routes = append(declared.routes, routes...)
|
|
declared.Unlock()
|
|
}
|
|
|
|
// IsPublic reports whether the route a request matched was declared [Public].
|
|
//
|
|
// The declaration is held per process rather than per app, because the answer
|
|
// is read where neither the router that mounted the route nor the plugin that
|
|
// declared it is in scope. A server builds one router, so the two are the same
|
|
// set; a process that built two routers over the same addresses would read one
|
|
// answer for both.
|
|
func IsPublic(r *http.Request) bool {
|
|
if r.Pattern == "" {
|
|
return false
|
|
}
|
|
|
|
declared.RLock()
|
|
defer declared.RUnlock()
|
|
|
|
for _, route := range declared.routes {
|
|
if route.Pattern() == r.Pattern {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|