Reorganized package tree and added doc comments
This commit is contained in:
parent
c300567c0c
commit
60e5a1c729
@ -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
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
})
|
})
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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,
|
||||||
})
|
})
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// Package service provides a toolkit for creating Hnakra services.
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import "os"
|
import "os"
|
||||||
|
Loading…
Reference in New Issue
Block a user