Fix golint issues

This commit is contained in:
Tyler
2022-10-03 01:39:02 -04:00
parent b629efe1ce
commit 4799ab7ede
8 changed files with 82 additions and 28 deletions

View File

@@ -15,19 +15,27 @@ import (
)
var (
ErrHttpsRedirect = errors.New("unexpected forced https redirect")
ErrHttpRedirect = errors.New("unexpected redirect to insecure url")
ErrCertExpired = errors.New("certificate is expired")
// ErrHTTPSRedirect is an error thrown when the webserver returns
// an https redirect for an http url.
ErrHTTPSRedirect = errors.New("unexpected forced https redirect")
// ErrHTTPRedirect is an error thrown when the webserver returns
// a redirect to a non-https url from an https request.
ErrHTTPRedirect = errors.New("unexpected redirect to insecure url")
// ErrCertExpired is a fatal error thrown when the webserver's
// certificate is expired.
ErrCertExpired = errors.New("certificate is expired")
)
func (r *Redirector) checkHttp(scheme string) ServerCheck {
func (r *Redirector) checkHTTP(scheme string) ServerCheck {
return func(server *Server, logFields log.Fields) (bool, error) {
return r.checkHttpScheme(server, scheme, logFields)
return r.checkHTTPScheme(server, scheme, logFields)
}
}
// checkHttp checks a URL for validity, and checks redirects
func (r *Redirector) checkHttpScheme(server *Server, scheme string, logFields log.Fields) (bool, error) {
// checkHTTPScheme checks a URL for validity, and checks redirects
func (r *Redirector) checkHTTPScheme(server *Server, scheme string, logFields log.Fields) (bool, error) {
u := &url.URL{
Scheme: scheme,
Host: server.Host,
@@ -82,7 +90,7 @@ func (r *Redirector) checkHttpScheme(server *Server, scheme string, logFields lo
}
func (r *Redirector) checkProtocol(server *Server, scheme string) {
res, err := r.checkHttpScheme(server, scheme, log.Fields{})
res, err := r.checkHTTPScheme(server, scheme, log.Fields{})
if !res || err != nil {
return
@@ -95,16 +103,16 @@ func (r *Redirector) checkProtocol(server *Server, scheme string) {
// checkRedirect parses a location header response and checks the scheme
func (r *Redirector) checkRedirect(originatingScheme, locationHeader string) (bool, error) {
newUrl, err := url.Parse(locationHeader)
newURL, err := url.Parse(locationHeader)
if err != nil {
return false, err
}
if newUrl.Scheme == "https" {
return false, ErrHttpsRedirect
} else if originatingScheme == "https" && newUrl.Scheme == "http" {
return false, ErrHttpRedirect
if newURL.Scheme == "https" {
return false, ErrHTTPSRedirect
} else if originatingScheme == "https" && newURL.Scheme == "http" {
return false, ErrHTTPRedirect
}
return true, nil

View File

@@ -92,7 +92,7 @@ var _ = Describe("Check suite", func() {
w.WriteHeader(http.StatusOK)
}
res, err := r.checkHttpScheme(server, "http", log.Fields{})
res, err := r.checkHTTPScheme(server, "http", log.Fields{})
Expect(res).To(BeTrue())
Expect(err).To(BeNil())
@@ -146,11 +146,11 @@ var _ = Describe("Check suite", func() {
logFields := log.Fields{}
res, err := r.checkHttpScheme(server, "https", logFields)
res, err := r.checkHTTPScheme(server, "https", logFields)
Expect(logFields["url"]).ToNot(BeEmpty())
Expect(logFields["url"]).ToNot(Equal(httpServer.URL))
Expect(err).To(Equal(ErrHttpRedirect))
Expect(err).To(Equal(ErrHTTPRedirect))
Expect(res).To(BeFalse())
})
})

View File

@@ -17,17 +17,39 @@ import (
"time"
)
// Config represents our application's configuration.
type Config struct {
BindAddress string `mapstructure:"bind"`
GeoDBPath string `mapstructure:"geodb"`
ASNDBPath string `mapstructure:"asndb"`
MapFile string `mapstructure:"dl_map"`
CacheSize int `mapstructure:"cacheSize"`
TopChoices int `mapstructure:"topChoices"`
ReloadToken string `mapstructure:"reloadToken"`
ServerList []ServerConfig `mapstructure:"servers"`
ReloadFunc func()
RootCAs *x509.CertPool
// BindAddress is the address to bind our webserver to.
BindAddress string `mapstructure:"bind"`
// GeoDBPath is the path to the MaxMind GeoLite2 City DB.
GeoDBPath string `mapstructure:"geodb"`
// ASNDBPath is the path to the GeoLite2 ASN DB.
ASNDBPath string `mapstructure:"asndb"`
// MapFile is a file used to map download urls via redirect.
MapFile string `mapstructure:"dl_map"`
// CacheSize is the number of items to keep in the LRU cache.
CacheSize int `mapstructure:"cacheSize"`
// TopChoices is the number of servers to use in a rotation.
// With the default being 3, the top 3 servers will be rotated based on weight.
TopChoices int `mapstructure:"topChoices"`
// ReloadToken is a secret token used for web-based reload.
ReloadToken string `mapstructure:"reloadToken"`
// ServerList is a list of ServerConfig structs, which gets parsed into servers.
ServerList []ServerConfig `mapstructure:"servers"`
// ReloadFunc is called when a reload is done via http api.
ReloadFunc func()
// RootCAs is a list of CA certificates, which we parse from Mozilla directly.
RootCAs *x509.CertPool
checkClient *http.Client
}
@@ -51,8 +73,11 @@ func (c *Config) SetRootCAs(cas *x509.CertPool) {
}
}
// ASNList is a list of Autonomous System Numbers (in int)
// It can be used to include or exclude specific ASNs from requests.
type ASNList []uint
// Contains checks if an ASN is in the list.
func (a ASNList) Contains(value uint) bool {
for _, val := range a {
if value == val {
@@ -63,8 +88,10 @@ func (a ASNList) Contains(value uint) bool {
return false
}
// ProtocolList is a list of supported protocols.
type ProtocolList []string
// Contains checks if the specified protocol exists in the list.
func (p ProtocolList) Contains(value string) bool {
for _, val := range p {
if value == val {
@@ -75,10 +102,12 @@ func (p ProtocolList) Contains(value string) bool {
return false
}
// Append adds a supported protocol to the list.
func (p ProtocolList) Append(value string) ProtocolList {
return append(p, value)
}
// Remove a specific protocol from the list.
func (p ProtocolList) Remove(value string) ProtocolList {
index := -1
@@ -97,6 +126,7 @@ func (p ProtocolList) Remove(value string) ProtocolList {
return p[:len(p)-1]
}
// ReloadConfig is called to reload the server's configuration.
func (r *Redirector) ReloadConfig() error {
log.Info("Loading configuration...")

View File

@@ -1,6 +1,7 @@
package redirector
import (
// embed is a blank import for Go's embedding, used for image files.
_ "embed"
"encoding/json"
"github.com/go-chi/chi/v5"

View File

@@ -25,6 +25,7 @@ var (
})
)
// Redirector is our application instance.
type Redirector struct {
config *Config
db *maxminddb.Reader
@@ -39,6 +40,8 @@ type Redirector struct {
checkClient *http.Client
}
// LocationLookup is a specific GeoIP lookup on the maxminddb side,
// used for finding the closest servers.
type LocationLookup struct {
Location struct {
Latitude float64 `maxminddb:"latitude"`
@@ -46,7 +49,8 @@ type LocationLookup struct {
} `maxminddb:"location"`
}
// City represents a MaxmindDB city
// City represents a MaxmindDB city, used only when loading servers,
// or returning a GeoIP response.
type City struct {
Continent struct {
Code string `maxminddb:"code" json:"code"`
@@ -76,6 +80,8 @@ type ASN struct {
AutonomousSystemOrganization string `maxminddb:"autonomous_system_organization"`
}
// ServerConfig is a configuration struct holding basic server configuration.
// This is used for initial loading of server information before parsing into Server.
type ServerConfig struct {
Server string `mapstructure:"server" yaml:"server"`
Latitude float64 `mapstructure:"latitude" yaml:"latitude"`
@@ -92,13 +98,15 @@ func New(config *Config) *Redirector {
}
r.checks = []ServerCheck{
r.checkHttp("http"),
r.checkHTTP("http"),
r.checkTLS,
}
return r
}
// Start registers the routes, loggers, and server checks,
// then returns the http.Handler.
func (r *Redirector) Start() http.Handler {
if err := r.ReloadConfig(); err != nil {
log.WithError(err).Fatalln("Unable to load configuration")

View File

@@ -27,6 +27,7 @@ type Server struct {
LastChange time.Time `json:"lastChange"`
}
// ServerCheck is a check function which can return information about a status.
type ServerCheck func(server *Server, logFields log.Fields) (bool, error)
// checkStatus runs all status checks against a server
@@ -70,8 +71,12 @@ func (server *Server) checkStatus(checks []ServerCheck) {
}
}
// ServerList is a wrapper for a Server slice.
// It implements features like server checks.
type ServerList []*Server
// checkLoop is a loop function which checks server statuses
// every 60 seconds.
func (s ServerList) checkLoop(checks []ServerCheck) {
t := time.NewTicker(60 * time.Second)

View File

@@ -4,6 +4,7 @@ import "math/rand"
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
// RandomSequence is an insecure, but "good enough" random generator.
func RandomSequence(n int) string {
b := make([]rune, n)
for i := range b {

View File

@@ -11,6 +11,7 @@ const (
defaultDownloadURL = "https://github.com/mozilla/gecko-dev/blob/master/security/nss/lib/ckfw/builtins/certdata.txt?raw=true"
)
// LoadCACerts loads the certdata from Mozilla and parses it into a CertPool.
func LoadCACerts() (*x509.CertPool, error) {
res, err := http.Get(defaultDownloadURL)