Reorganized package tree and added doc comments

This commit is contained in:
Sasha Koshka 2023-05-26 01:18:16 -04:00
parent c300567c0c
commit 60e5a1c729
11 changed files with 48 additions and 44 deletions

View File

@ -1,7 +1,9 @@
// Config provides a configuration system for routers.
package config package config
import "crypto/tls" import "crypto/tls"
// Config is an interface that configuration objects must fulfill.
type Config interface { type Config interface {
User (name string) User User (name string) User
OverUsers (func (name string, user User) bool) OverUsers (func (name string, user User) bool)
@ -22,6 +24,7 @@ type Config interface {
OverAliases (func (alias, target string) bool) OverAliases (func (alias, target string) bool)
} }
// User represents a Hnakra user.
type User interface { type User interface {
Validate (key []byte) bool Validate (key []byte) bool
RconAllow () bool RconAllow () bool

View File

@ -3,10 +3,12 @@ package mux
import "net/url" import "net/url"
import "net/http" import "net/http"
// HTTP is an HTTP request multiplexer.
type HTTP struct { type HTTP struct {
Mux[http.Handler] Mux[http.Handler]
} }
// NewHTTP creates a new HTTP request multiplexer.
func NewHTTP (resolver Resolver) *HTTP { func NewHTTP (resolver Resolver) *HTTP {
mux := &HTTP { } mux := &HTTP { }
mux.Mux.Redirect = mux.newRedirect mux.Mux.Redirect = mux.newRedirect

View File

@ -1,3 +1,4 @@
// Package mux provides request multiplexers for all protocols Hnakra supports.
package mux package mux
import "net" import "net"
@ -8,6 +9,8 @@ import "errors"
import "strings" import "strings"
import "net/url" import "net/url"
// Resolver represents an object capable of transforming a hosname alias into
// another hostname.
type Resolver interface { type Resolver interface {
ResolveAlias (alias string) string ResolveAlias (alias string) string
} }
@ -68,6 +71,7 @@ func stripHostPort (h string) string {
return host return host
} }
// Handler returns the handler for a particular URL.
func (mux *Mux[HANDLER]) Handler (where *url.URL) (h HANDLER, pattern string) { func (mux *Mux[HANDLER]) Handler (where *url.URL) (h HANDLER, pattern string) {
// All other requests have any port stripped and path cleaned // All other requests have any port stripped and path cleaned
// before passing to mux.handler. // before passing to mux.handler.
@ -144,6 +148,10 @@ func (mux *Mux[HANDLER]) match (path string, original *url.URL) (h HANDLER, patt
return mux.NotFound(original), "" return mux.NotFound(original), ""
} }
// Handle registers a handler on the specified pattern. If a pattern ends in
// '/', all requests for URLS under the pattern will be directed to the handler,
// as well as the pattern itself. Additionally, requests for the pattern without
// the trailing slash will be redirected to the pattern with the trailing slash.
func (mux *Mux[HANDLER]) Handle (pattern string, handler HANDLER) error { func (mux *Mux[HANDLER]) Handle (pattern string, handler HANDLER) error {
mux.mutex.Lock() mux.mutex.Lock()
defer mux.mutex.Unlock() defer mux.mutex.Unlock()
@ -176,6 +184,7 @@ func (mux *Mux[HANDLER]) Handle (pattern string, handler HANDLER) error {
return nil return nil
} }
// Unhandler removes the handler that was registered on the specified pattern.
func (mux *Mux[HANDLER]) Unhandle (pattern string) error { func (mux *Mux[HANDLER]) Unhandle (pattern string) error {
mux.mutex.Lock() mux.mutex.Lock()
defer mux.mutex.Unlock() defer mux.mutex.Unlock()
@ -199,6 +208,7 @@ func (mux *Mux[HANDLER]) Unhandle (pattern string) error {
return nil return nil
} }
// OverHandlers calls a function for each registered handler.
func (mux *Mux[HANDLER]) OverHandlers (callback func (pattern string, handler HANDLER) bool) { func (mux *Mux[HANDLER]) OverHandlers (callback func (pattern string, handler HANDLER) bool) {
overSorted (mux.exactEntries, func (pattern string, entry muxEntry[HANDLER]) bool { overSorted (mux.exactEntries, func (pattern string, entry muxEntry[HANDLER]) bool {
return callback(pattern, entry.handler) return callback(pattern, entry.handler)

View File

@ -8,10 +8,10 @@ import "io"
import "fmt" import "fmt"
import "net/url" import "net/url"
import "net/http" import "net/http"
import "hnakra/config"
import "hnakra/router" import "hnakra/router"
import "hnakra/rotate" import "hnakra/rotate"
import "hnakra/protocol" import "hnakra/protocol"
import "hnakra/router/config"
const css = ` const css = `
body { background-color: #161815; color: #aea894; margin: 3em; } body { background-color: #161815; color: #aea894; margin: 3em; }
@ -200,7 +200,7 @@ func (rcon *Rcon) serveServices (res http.ResponseWriter, req *http.Request) {
service.Name(), service.Name(),
service.Name(), service.Name(),
service.Description(), service.Description(),
service.Pattern()))) router.FormatPattern(service.Pattern()))))
return true return true
}) })

View File

@ -1,32 +1,13 @@
// Package router provides a reusable router implementation.
package router package router
import "log" import "log"
import "net" import "net"
// import "errors" // import "errors"
import "net/http" import "net/http"
import "hnakra/config"
import "hnakra/protocol" import "hnakra/protocol"
import "hnakra/router/mux" import "hnakra/router/mux"
import "hnakra/router/config"
type Pattern struct {
Scheme string
Host string
Path string
}
func (pattern Pattern) MuxPattern () string {
return pattern.Host + pattern.Path
}
func (pattern Pattern) String () string {
return pattern.Scheme + "://" + pattern.Host + pattern.Path
}
func (pattern *Pattern) FillDefaults () {
if pattern.Scheme == "" { pattern.Scheme = "https" }
if pattern.Host == "" { pattern.Host = "@" }
if pattern.Path == "" { pattern.Path = "/" }
}
type Router struct { type Router struct {
config config.Config config config.Config
@ -81,13 +62,17 @@ func (router *Router) unlist (service *Service) {
delete(router.services, service) delete(router.services, service)
} }
func (router *Router) Validate (name string, key []byte, pattern Pattern) protocol.Status { func (router *Router) Validate (name string, key []byte, scheme, host, path string) protocol.Status {
user := router.config.User(name) user := router.config.User(name)
if user == nil || !user.Validate(key) { if user == nil || !user.Validate(key) {
return protocol.StatusBadCredentials return protocol.StatusBadCredentials
} }
if !user.CanMountOn(pattern.Scheme, pattern.Host, pattern.Path) { if !user.CanMountOn(scheme, host, path) {
return protocol.StatusBadMount return protocol.StatusBadMount
} }
return protocol.StatusOk return protocol.StatusOk
} }
func FormatPattern (scheme, host, path string) string {
return scheme + "://" + host + path
}

View File

@ -38,8 +38,7 @@ func (request *activeRequest) ensureHeader () {
type Service struct { type Service struct {
router *Router router *Router
validate func (user string, key []byte, pattern Pattern) protocol.Status scheme, host, path string
pattern Pattern
user, name, description string user, name, description string
@ -57,7 +56,6 @@ func (router *Router) newService (conn net.Conn) (service *Service) {
service = &Service { service = &Service {
idFactory: protocol.NewRouterIDFactory(), idFactory: protocol.NewRouterIDFactory(),
router: router, router: router,
validate: router.Validate,
conn: conn, conn: conn,
requests: make(map[protocol.ID] *activeRequest), requests: make(map[protocol.ID] *activeRequest),
connReadWriter: bufio.NewReadWriter ( connReadWriter: bufio.NewReadWriter (
@ -88,8 +86,8 @@ func (service *Service) Description () string {
return service.description return service.description
} }
func (service *Service) Pattern () Pattern { func (service *Service) Pattern () (user, name, description string) {
return service.pattern return service.user, service.name, service.description
} }
func (service *Service) Close () error { func (service *Service) Close () error {
@ -104,9 +102,9 @@ func (service *Service) Shutdown () error {
func (service *Service) ServeHTTP (res http.ResponseWriter, req *http.Request) { func (service *Service) ServeHTTP (res http.ResponseWriter, req *http.Request) {
// if we are only accepting https requests and we recieve an http one, // if we are only accepting https requests and we recieve an http one,
// redirect to the https version // redirect to the https version
if req.TLS == nil && service.pattern.Scheme == "https" { if req.TLS == nil && service.scheme == "https" {
newURL := req.URL newURL := req.URL
newURL.Scheme = service.pattern.Scheme newURL.Scheme = service.scheme
http.Redirect(res, req, newURL.String(), http.StatusPermanentRedirect) http.Redirect(res, req, newURL.String(), http.StatusPermanentRedirect)
return return
} }
@ -326,15 +324,17 @@ func (service *Service) authenticate () (func(), bool) {
} }
// create pattern // create pattern
service.pattern = Pattern { service.scheme = login.Scheme
Scheme: login.Scheme, service.host = login.Host
Host: login.Host, service.path = login.Path
Path: login.Path, if service.scheme == "" { service.scheme = "https://" }
} if service.host == "" { service.host = "@" }
service.pattern.FillDefaults() if service.path == "" { service.path = "/" }
// validate credentials // validate credentials
status := service.validate(login.User, login.Key, service.pattern) status := service.router.Validate (
login.User, login.Key,
service.scheme, service.host, service.path)
service.send(protocol.MessageStatus { Status: status }) service.send(protocol.MessageStatus { Status: status })
if status == protocol.StatusOk { if status == protocol.StatusOk {
service.user = login.User service.user = login.User
@ -343,19 +343,21 @@ func (service *Service) authenticate () (func(), bool) {
log.Println ( log.Println (
"-->", service.conn.RemoteAddr(), "-->", service.conn.RemoteAddr(),
"logged in as", login.User, "on", service.pattern) "logged in as", login.User, "on",
FormatPattern(service.scheme, service.host, service.path))
} else { } else {
log.Println ( log.Println (
"ERR", service.conn.RemoteAddr(), "ERR", service.conn.RemoteAddr(),
"failed login as", login.User, "on", service.pattern) "failed login as", login.User, "on",
FormatPattern(service.scheme, service.host, service.path))
service.conn.Close() service.conn.Close()
return nil, false return nil, false
} }
// mount service on the mux. // mount service on the mux.
var unhandle func () var unhandle func ()
muxPattern := service.pattern.MuxPattern() muxPattern := service.host + service.path
switch service.pattern.Scheme { switch service.scheme {
case "http", "https": case "http", "https":
err = service.router.HTTPMux().Handle(muxPattern, service) err = service.router.HTTPMux().Handle(muxPattern, service)
unhandle = func () { unhandle = func () {
@ -367,7 +369,8 @@ func (service *Service) authenticate () (func(), bool) {
if err != nil { if err != nil {
log.Println ( log.Println (
"ERR", service.name, "ERR", service.name,
"sent bad mount pattern:", service.pattern) "sent bad mount pattern:",
FormatPattern(service.scheme, service.host, service.path))
service.send(protocol.MessageStatus { service.send(protocol.MessageStatus {
Status: protocol.StatusBadMount, Status: protocol.StatusBadMount,
}) })

View File

@ -1,3 +1,4 @@
// Package service provides a toolkit for creating Hnakra services.
package service package service
import "os" import "os"