Documentation
¶
Overview ¶
Package adminpath holds the rules for the per-install admin address: its format, how strong it is, the list of addresses scanners try, and (in generate.go) the random generator. It is a leaf package: pure functions plus the Site interface the server fills in. It imports no database, server or admin code.
Index ¶
- Variables
- func Generate() (string, error)
- func Normalize(s string) (string, error)
- type DB
- type Level
- type Reason
- type Result
- type Site
- type Store
- func (s *Store) Ack(ctx context.Context, path, by string) error
- func (s *Store) Get(ctx context.Context) (Stored, error)
- func (s *Store) Set(ctx context.Context, path, by string) error
- func (s *Store) SetAck(ctx context.Context, path, by string) error
- func (s *Store) SetIfPending(ctx context.Context, path string) (bool, error)
- type Stored
Constants ¶
This section is empty.
Variables ¶
var ErrFormat = errors.New("not a valid admin address")
ErrFormat is wrapped by every Normalize failure.
var ErrNoSiteConfig = errors.New("adminpath: no site config row")
ErrNoSiteConfig means the singleton site config row does not exist yet (first boot seeds it).
var ReservedPrefixes = []string{
"api", "p", "theme", "media", ".well-known", "sitemap.xml", "robots.txt", "health", "ready",
"llms.txt", "plugin-ui", "feed", "feed.xml", "atom.xml", "sitemap", "forms", "auth", "-", "favicon.ico",
}
ReservedPrefixes are the first segments the site always serves (or must keep free) at the top level. The server test checks that every fixed route prefix appears here or is exempt. "admin" is deliberately absent: it is the legacy default and may be chosen as a weak address.
var ScannerList = []string{
"admin", "administrator", "admins", "adm", "wp-admin", "wp-login", "wp", "wordpress",
"login", "signin", "sign-in", "auth", "dashboard", "dash", "cms", "backend", "backoffice",
"manage", "manager", "management", "panel", "controlpanel", "cpanel", "cp", "console", "portal",
"user", "users", "account", "accounts", "member", "members", "ghost", "umbraco",
"typo3", "joomla", "drupal", "craft", "hatamoto", "hm", "editor", "staff", "secure", "private",
"root", "sysadmin", "webadmin", "siteadmin",
"admin-panel", "adminpanel", "admin-login", "adminlogin", "moderator", "owner", "config", "setup", "install",
}
ScannerList holds the addresses that automated scanners try first.
Functions ¶
Types ¶
type DB ¶
type DB interface {
QueryRow(ctx context.Context, sql string, args ...any) pgx.Row
Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
}
DB is what Store needs; *pgxpool.Pool satisfies it.
type Level ¶
type Level int
Level says how an address ranks. Higher is better; LevelInvalid and LevelReserved are refused outright, LevelWeak needs an explicit confirm.
type Reason ¶
type Reason struct{ Code, Text string }
Reason explains a level. Code is stable ("format", "scanner", "short", "dictionary", "site-name", "served", "reserved"); Text is for people.
type Result ¶
Result is the outcome of Assess. Path is the normalised form when the input was well formed, else the trimmed input.
func Assess ¶
Assess ranks an admin address. site may be nil. The order is: a shape that is not a single segment is invalid; a first segment the site serves is reserved (checked before the length rule, so "/api" is reserved, not just too short); then the format rules; then the weak rules; then ok or strong.
type Site ¶
type Site interface {
// Serves reports whether the first segment of path collides with a URL
// pattern, entity slug or redirect source, and says what serves it.
Serves(ctx context.Context, path string) (bool, string)
// Name is the site name, or "".
Name() string
// Domain is the host of the public base URL, or "".
Domain() string
}
Site tells Assess what the running site serves and what it is called. Any method may be unhelpful (false, ""), and Assess accepts a nil Site.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store reads and writes the admin address columns of hatamoto_site_config directly. It does not go through siteconfig.Update, whose COALESCE cannot set a column back to NULL.
func (*Store) Ack ¶
Ack records that someone knowingly accepted path as weak, and when, without touching who chose it or when. It writes nothing, and returns ErrNoSiteConfig, when path is not the stored address.
type Stored ¶
type Stored struct {
Path *string
AckBy *string
AckAt *time.Time
// SetBy and SetAt record who last chose the address and when. They are
// nil for a server-generated address (SetIfPending) and for rows that
// predate the columns.
SetBy *string
SetAt *time.Time
}
Stored is the persisted admin address. A nil Path means pending: nothing has been chosen yet.