From 60e5a1c7294da6ff418ee10d3498083ba6bc94a4 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Fri, 26 May 2023 01:18:16 -0400 Subject: [PATCH] Reorganized package tree and added doc comments --- {srvhnakra => cmd/router/srvhnakra}/hnakra.go | 0 {srvhttps => cmd/router/srvhttps}/https.go | 0 {config => router/config}/config.go | 3 ++ {config => router/config}/file.go | 0 {config => router/config}/tls.go | 0 router/mux/http.go | 2 + router/mux/mux.go | 10 +++++ {rcon => router/rcon}/rcon.go | 4 +- router/router.go | 31 ++++---------- router/service.go | 41 ++++++++++--------- service/service.go | 1 + 11 files changed, 48 insertions(+), 44 deletions(-) rename {srvhnakra => cmd/router/srvhnakra}/hnakra.go (100%) rename {srvhttps => cmd/router/srvhttps}/https.go (100%) rename {config => router/config}/config.go (80%) rename {config => router/config}/file.go (100%) rename {config => router/config}/tls.go (100%) rename {rcon => router/rcon}/rcon.go (99%) diff --git a/srvhnakra/hnakra.go b/cmd/router/srvhnakra/hnakra.go similarity index 100% rename from srvhnakra/hnakra.go rename to cmd/router/srvhnakra/hnakra.go diff --git a/srvhttps/https.go b/cmd/router/srvhttps/https.go similarity index 100% rename from srvhttps/https.go rename to cmd/router/srvhttps/https.go diff --git a/config/config.go b/router/config/config.go similarity index 80% rename from config/config.go rename to router/config/config.go index 32fd6aa..8c39bb0 100644 --- a/config/config.go +++ b/router/config/config.go @@ -1,7 +1,9 @@ +// Config provides a configuration system for routers. package config import "crypto/tls" +// Config is an interface that configuration objects must fulfill. type Config interface { User (name string) User OverUsers (func (name string, user User) bool) @@ -22,6 +24,7 @@ type Config interface { OverAliases (func (alias, target string) bool) } +// User represents a Hnakra user. type User interface { Validate (key []byte) bool RconAllow () bool diff --git a/config/file.go b/router/config/file.go similarity index 100% rename from config/file.go rename to router/config/file.go diff --git a/config/tls.go b/router/config/tls.go similarity index 100% rename from config/tls.go rename to router/config/tls.go diff --git a/router/mux/http.go b/router/mux/http.go index e52c322..7bbc5b8 100644 --- a/router/mux/http.go +++ b/router/mux/http.go @@ -3,10 +3,12 @@ package mux import "net/url" import "net/http" +// HTTP is an HTTP request multiplexer. type HTTP struct { Mux[http.Handler] } +// NewHTTP creates a new HTTP request multiplexer. func NewHTTP (resolver Resolver) *HTTP { mux := &HTTP { } mux.Mux.Redirect = mux.newRedirect diff --git a/router/mux/mux.go b/router/mux/mux.go index 9b035ba..23579f0 100644 --- a/router/mux/mux.go +++ b/router/mux/mux.go @@ -1,3 +1,4 @@ +// Package mux provides request multiplexers for all protocols Hnakra supports. package mux import "net" @@ -8,6 +9,8 @@ import "errors" import "strings" import "net/url" +// Resolver represents an object capable of transforming a hosname alias into +// another hostname. type Resolver interface { ResolveAlias (alias string) string } @@ -68,6 +71,7 @@ func stripHostPort (h string) string { return host } +// Handler returns the handler for a particular URL. func (mux *Mux[HANDLER]) Handler (where *url.URL) (h HANDLER, pattern string) { // All other requests have any port stripped and path cleaned // 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), "" } +// 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 { mux.mutex.Lock() defer mux.mutex.Unlock() @@ -176,6 +184,7 @@ func (mux *Mux[HANDLER]) Handle (pattern string, handler HANDLER) error { return nil } +// Unhandler removes the handler that was registered on the specified pattern. func (mux *Mux[HANDLER]) Unhandle (pattern string) error { mux.mutex.Lock() defer mux.mutex.Unlock() @@ -199,6 +208,7 @@ func (mux *Mux[HANDLER]) Unhandle (pattern string) error { return nil } +// OverHandlers calls a function for each registered handler. func (mux *Mux[HANDLER]) OverHandlers (callback func (pattern string, handler HANDLER) bool) { overSorted (mux.exactEntries, func (pattern string, entry muxEntry[HANDLER]) bool { return callback(pattern, entry.handler) diff --git a/rcon/rcon.go b/router/rcon/rcon.go similarity index 99% rename from rcon/rcon.go rename to router/rcon/rcon.go index d666cb9..f5fa7d6 100644 --- a/rcon/rcon.go +++ b/router/rcon/rcon.go @@ -8,10 +8,10 @@ import "io" import "fmt" import "net/url" import "net/http" -import "hnakra/config" import "hnakra/router" import "hnakra/rotate" import "hnakra/protocol" +import "hnakra/router/config" const css = ` 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.Description(), - service.Pattern()))) + router.FormatPattern(service.Pattern())))) return true }) diff --git a/router/router.go b/router/router.go index afff6b1..10ec8ae 100644 --- a/router/router.go +++ b/router/router.go @@ -1,32 +1,13 @@ +// Package router provides a reusable router implementation. package router import "log" import "net" // import "errors" import "net/http" -import "hnakra/config" import "hnakra/protocol" import "hnakra/router/mux" - -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 = "/" } -} +import "hnakra/router/config" type Router struct { config config.Config @@ -81,13 +62,17 @@ func (router *Router) unlist (service *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) if user == nil || !user.Validate(key) { return protocol.StatusBadCredentials } - if !user.CanMountOn(pattern.Scheme, pattern.Host, pattern.Path) { + if !user.CanMountOn(scheme, host, path) { return protocol.StatusBadMount } return protocol.StatusOk } + +func FormatPattern (scheme, host, path string) string { + return scheme + "://" + host + path +} diff --git a/router/service.go b/router/service.go index d932dd4..14a7b42 100644 --- a/router/service.go +++ b/router/service.go @@ -38,8 +38,7 @@ func (request *activeRequest) ensureHeader () { type Service struct { router *Router - validate func (user string, key []byte, pattern Pattern) protocol.Status - pattern Pattern + scheme, host, path string user, name, description string @@ -57,7 +56,6 @@ func (router *Router) newService (conn net.Conn) (service *Service) { service = &Service { idFactory: protocol.NewRouterIDFactory(), router: router, - validate: router.Validate, conn: conn, requests: make(map[protocol.ID] *activeRequest), connReadWriter: bufio.NewReadWriter ( @@ -88,8 +86,8 @@ func (service *Service) Description () string { return service.description } -func (service *Service) Pattern () Pattern { - return service.pattern +func (service *Service) Pattern () (user, name, description string) { + return service.user, service.name, service.description } func (service *Service) Close () error { @@ -104,9 +102,9 @@ func (service *Service) Shutdown () error { func (service *Service) ServeHTTP (res http.ResponseWriter, req *http.Request) { // if we are only accepting https requests and we recieve an http one, // redirect to the https version - if req.TLS == nil && service.pattern.Scheme == "https" { + if req.TLS == nil && service.scheme == "https" { newURL := req.URL - newURL.Scheme = service.pattern.Scheme + newURL.Scheme = service.scheme http.Redirect(res, req, newURL.String(), http.StatusPermanentRedirect) return } @@ -326,15 +324,17 @@ func (service *Service) authenticate () (func(), bool) { } // create pattern - service.pattern = Pattern { - Scheme: login.Scheme, - Host: login.Host, - Path: login.Path, - } - service.pattern.FillDefaults() + service.scheme = login.Scheme + service.host = login.Host + service.path = login.Path + if service.scheme == "" { service.scheme = "https://" } + if service.host == "" { service.host = "@" } + if service.path == "" { service.path = "/" } // 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 }) if status == protocol.StatusOk { service.user = login.User @@ -343,19 +343,21 @@ func (service *Service) authenticate () (func(), bool) { log.Println ( "-->", 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 { log.Println ( "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() return nil, false } // mount service on the mux. var unhandle func () - muxPattern := service.pattern.MuxPattern() - switch service.pattern.Scheme { + muxPattern := service.host + service.path + switch service.scheme { case "http", "https": err = service.router.HTTPMux().Handle(muxPattern, service) unhandle = func () { @@ -367,7 +369,8 @@ func (service *Service) authenticate () (func(), bool) { if err != nil { log.Println ( "ERR", service.name, - "sent bad mount pattern:", service.pattern) + "sent bad mount pattern:", + FormatPattern(service.scheme, service.host, service.path)) service.send(protocol.MessageStatus { Status: protocol.StatusBadMount, }) diff --git a/service/service.go b/service/service.go index e231b78..c7b7f59 100644 --- a/service/service.go +++ b/service/service.go @@ -1,3 +1,4 @@ +// Package service provides a toolkit for creating Hnakra services. package service import "os"