diff --git a/cmd/robots2policy/robots2policy_test.go b/cmd/robots2policy/robots2policy_test.go index e9d90e6..523d69a 100644 --- a/cmd/robots2policy/robots2policy_test.go +++ b/cmd/robots2policy/robots2policy_test.go @@ -22,9 +22,9 @@ type TestCase struct { type TestOptions struct { format string action string - crawlDelayWeight int policyName string deniedAction string + crawlDelayWeight int } func TestDataFileConversion(t *testing.T) { diff --git a/decaymap/decaymap.go b/decaymap/decaymap.go index dd3ea41..37997e1 100644 --- a/decaymap/decaymap.go +++ b/decaymap/decaymap.go @@ -13,13 +13,13 @@ func Zilch[T any]() T { // Impl is a lazy key->value map. It's a wrapper around a map and a mutex. If values exceed their time-to-live, they are pruned at Get time. type Impl[K comparable, V any] struct { data map[K]decayMapEntry[V] - lock sync.RWMutex // deleteCh receives decay-deletion requests from readers. deleteCh chan deleteReq[K] // stopCh stops the background cleanup worker. stopCh chan struct{} wg sync.WaitGroup + lock sync.RWMutex } type decayMapEntry[V any] struct { diff --git a/internal/ogtags/ogtags.go b/internal/ogtags/ogtags.go index 68fb164..37cf79d 100644 --- a/internal/ogtags/ogtags.go +++ b/internal/ogtags/ogtags.go @@ -22,9 +22,10 @@ const ( ) type OGTagCache struct { - cache store.JSON[map[string]string] - targetURL *url.URL - client *http.Client + targetURL *url.URL + client *http.Client + ogOverride map[string]string + cache store.JSON[map[string]string] // Pre-built strings for optimization unixPrefix string // "http://unix" @@ -33,7 +34,6 @@ type OGTagCache struct { ogTimeToLive time.Duration ogCacheConsiderHost bool ogPassthrough bool - ogOverride map[string]string } func NewOGTagCache(target string, conf config.OpenGraph, backend store.Interface) *OGTagCache { diff --git a/lib/anubis.go b/lib/anubis.go index 33a6b53..68dd9bc 100644 --- a/lib/anubis.go +++ b/lib/anubis.go @@ -68,14 +68,14 @@ var ( type Server struct { next http.Handler + store store.Interface mux *http.ServeMux policy *policy.ParsedConfig OGTags *ogtags.OGTagCache + logger *slog.Logger + opts Options ed25519Priv ed25519.PrivateKey hs512Secret []byte - opts Options - store store.Interface - logger *slog.Logger } func (s *Server) getTokenKeyfunc() jwt.Keyfunc { diff --git a/lib/anubis_test.go b/lib/anubis_test.go index 320589d..6df8fc4 100644 --- a/lib/anubis_test.go +++ b/lib/anubis_test.go @@ -154,8 +154,8 @@ func handleChallengeZeroDifficulty(t *testing.T, ts *httptest.Server, cli *http. type loggingCookieJar struct { t *testing.T - lock sync.Mutex cookies map[string][]*http.Cookie + lock sync.Mutex } func (lcj *loggingCookieJar) Cookies(u *url.URL) []*http.Cookie { @@ -747,9 +747,9 @@ func TestStripBasePrefixFromRequest(t *testing.T) { testCases := []struct { name string basePrefix string - stripBasePrefix bool requestPath string expectedPath string + stripBasePrefix bool }{ { name: "strip disabled - no change", diff --git a/lib/challenge/challenge.go b/lib/challenge/challenge.go index ef9a86f..d0cfbf7 100644 --- a/lib/challenge/challenge.go +++ b/lib/challenge/challenge.go @@ -4,12 +4,12 @@ import "time" // Challenge is the metadata about a single challenge issuance. type Challenge struct { - ID string `json:"id"` // UUID identifying the challenge - Method string `json:"method"` // Challenge method - RandomData string `json:"randomData"` // The random data the client processes - IssuedAt time.Time `json:"issuedAt"` // When the challenge was issued - Metadata map[string]string `json:"metadata"` // Challenge metadata such as IP address and user agent - Spent bool `json:"spent"` // Has the challenge already been solved? - Difficulty int `json:"difficulty,omitempty"` // Difficulty that was in effect when issued - PolicyRuleHash string `json:"policyRuleHash,omitempty"` // Hash of the policy rule that issued this challenge + IssuedAt time.Time `json:"issuedAt"` + Metadata map[string]string `json:"metadata"` + ID string `json:"id"` + Method string `json:"method"` + RandomData string `json:"randomData"` + PolicyRuleHash string `json:"policyRuleHash,omitempty"` + Difficulty int `json:"difficulty,omitempty"` + Spent bool `json:"spent"` } diff --git a/lib/config.go b/lib/config.go index 3c220dc..1c5bc7c 100644 --- a/lib/config.go +++ b/lib/config.go @@ -29,24 +29,24 @@ import ( type Options struct { Next http.Handler Policy *policy.ParsedConfig - Target string - CookieDynamicDomain bool + Logger *slog.Logger + OpenGraph config.OpenGraph + PublicUrl string CookieDomain string - CookieExpiration time.Duration - CookiePartitioned bool + JWTRestrictionHeader string BasePrefix string WebmasterEmail string + Target string RedirectDomains []string ED25519PrivateKey ed25519.PrivateKey HS512Secret []byte - StripBasePrefix bool - OpenGraph config.OpenGraph + CookieExpiration time.Duration + CookieSameSite http.SameSite ServeRobotsTXT bool CookieSecure bool - CookieSameSite http.SameSite - Logger *slog.Logger - PublicUrl string - JWTRestrictionHeader string + StripBasePrefix bool + CookiePartitioned bool + CookieDynamicDomain bool DifficultyInJWT bool } diff --git a/lib/http_test.go b/lib/http_test.go index 4bd353e..255344f 100644 --- a/lib/http_test.go +++ b/lib/http_test.go @@ -13,9 +13,9 @@ import ( func TestSetCookie(t *testing.T) { for _, tt := range []struct { name string - options Options host string cookieName string + options Options }{ { name: "basic", diff --git a/lib/policy/config/asn_test.go b/lib/policy/config/asn_test.go index 4967d2c..9653a46 100644 --- a/lib/policy/config/asn_test.go +++ b/lib/policy/config/asn_test.go @@ -8,9 +8,9 @@ import ( func TestASNsValid(t *testing.T) { for _, tt := range []struct { - name string - input *ASNs err error + input *ASNs + name string }{ { name: "basic valid", diff --git a/lib/policy/config/config.go b/lib/policy/config/config.go index 6b5946a..e2c62a2 100644 --- a/lib/policy/config/config.go +++ b/lib/policy/config/config.go @@ -62,13 +62,11 @@ type BotConfig struct { Expression *ExpressionOrList `json:"expression,omitempty" yaml:"expression,omitempty"` Challenge *ChallengeRules `json:"challenge,omitempty" yaml:"challenge,omitempty"` Weight *Weight `json:"weight,omitempty" yaml:"weight,omitempty"` + GeoIP *GeoIP `json:"geoip,omitempty"` + ASNs *ASNs `json:"asns,omitempty"` Name string `json:"name" yaml:"name"` Action Rule `json:"action" yaml:"action"` RemoteAddr []string `json:"remote_addresses,omitempty" yaml:"remote_addresses,omitempty"` - - // Thoth features - GeoIP *GeoIP `json:"geoip,omitempty"` - ASNs *ASNs `json:"asns,omitempty"` } func (b BotConfig) Zero() bool { @@ -324,13 +322,13 @@ func (sc StatusCodes) Valid() error { } type fileConfig struct { - Bots []BotOrImport `json:"bots"` - DNSBL bool `json:"dnsbl"` OpenGraph openGraphFileConfig `json:"openGraph,omitempty"` Impressum *Impressum `json:"impressum,omitempty"` - StatusCodes StatusCodes `json:"status_codes"` Store *Store `json:"store"` + Bots []BotOrImport `json:"bots"` Thresholds []Threshold `json:"thresholds"` + StatusCodes StatusCodes `json:"status_codes"` + DNSBL bool `json:"dnsbl"` } func (c *fileConfig) Valid() error { @@ -462,13 +460,13 @@ func Load(fin io.Reader, fname string) (*Config, error) { } type Config struct { + Impressum *Impressum + Store *Store + OpenGraph OpenGraph Bots []BotConfig Thresholds []Threshold - DNSBL bool - Impressum *Impressum - OpenGraph OpenGraph StatusCodes StatusCodes - Store *Store + DNSBL bool } func (c Config) Valid() error { diff --git a/lib/policy/config/config_test.go b/lib/policy/config/config_test.go index 3a96c9c..c35ceef 100644 --- a/lib/policy/config/config_test.go +++ b/lib/policy/config/config_test.go @@ -15,9 +15,9 @@ func p[V any](v V) *V { return &v } func TestBotValid(t *testing.T) { var tests = []struct { + bot BotConfig err error name string - bot BotConfig }{ { name: "simple user agent", diff --git a/lib/policy/config/expressionorlist_test.go b/lib/policy/config/expressionorlist_test.go index a09baf3..91d4670 100644 --- a/lib/policy/config/expressionorlist_test.go +++ b/lib/policy/config/expressionorlist_test.go @@ -11,10 +11,10 @@ import ( func TestExpressionOrListMarshalJSON(t *testing.T) { for _, tt := range []struct { - name string - input *ExpressionOrList - output []byte err error + input *ExpressionOrList + name string + output []byte }{ { name: "single expression", @@ -74,10 +74,10 @@ func TestExpressionOrListMarshalJSON(t *testing.T) { func TestExpressionOrListMarshalYAML(t *testing.T) { for _, tt := range []struct { - name string - input *ExpressionOrList - output []byte err error + input *ExpressionOrList + name string + output []byte }{ { name: "single expression", @@ -217,8 +217,8 @@ func TestExpressionOrListUnmarshalJSON(t *testing.T) { func TestExpressionOrListString(t *testing.T) { for _, tt := range []struct { name string - in ExpressionOrList out string + in ExpressionOrList }{ { name: "single expression", diff --git a/lib/policy/config/geoip_test.go b/lib/policy/config/geoip_test.go index c20310f..739ada5 100644 --- a/lib/policy/config/geoip_test.go +++ b/lib/policy/config/geoip_test.go @@ -7,9 +7,9 @@ import ( func TestGeoIPValid(t *testing.T) { for _, tt := range []struct { - name string - input *GeoIP err error + input *GeoIP + name string }{ { name: "basic valid", diff --git a/lib/policy/config/impressum_test.go b/lib/policy/config/impressum_test.go index 91424b5..1844ce5 100644 --- a/lib/policy/config/impressum_test.go +++ b/lib/policy/config/impressum_test.go @@ -8,9 +8,9 @@ import ( func TestImpressumValid(t *testing.T) { for _, cs := range []struct { - name string - inp Impressum err error + inp Impressum + name string }{ { name: "basic happy path", diff --git a/lib/policy/config/opengraph.go b/lib/policy/config/opengraph.go index 544647e..087d046 100644 --- a/lib/policy/config/opengraph.go +++ b/lib/policy/config/opengraph.go @@ -13,17 +13,17 @@ var ( ) type openGraphFileConfig struct { + Override map[string]string `json:"override,omitempty" yaml:"override,omitempty"` + TimeToLive string `json:"ttl" yaml:"ttl"` Enabled bool `json:"enabled" yaml:"enabled"` ConsiderHost bool `json:"considerHost" yaml:"enabled"` - TimeToLive string `json:"ttl" yaml:"ttl"` - Override map[string]string `json:"override,omitempty" yaml:"override,omitempty"` } type OpenGraph struct { - Enabled bool `json:"enabled" yaml:"enabled"` - ConsiderHost bool `json:"considerHost" yaml:"enabled"` Override map[string]string `json:"override,omitempty" yaml:"override,omitempty"` TimeToLive time.Duration `json:"ttl" yaml:"ttl"` + Enabled bool `json:"enabled" yaml:"enabled"` + ConsiderHost bool `json:"considerHost" yaml:"enabled"` } func (og *openGraphFileConfig) Valid() error { diff --git a/lib/policy/config/opengraph_test.go b/lib/policy/config/opengraph_test.go index 639549a..27250ff 100644 --- a/lib/policy/config/opengraph_test.go +++ b/lib/policy/config/opengraph_test.go @@ -7,9 +7,9 @@ import ( func TestOpenGraphFileConfigValid(t *testing.T) { for _, tt := range []struct { - name string - input *openGraphFileConfig err error + input *openGraphFileConfig + name string }{ { name: "basic happy path", diff --git a/lib/policy/config/store_test.go b/lib/policy/config/store_test.go index 1c1556e..227b06b 100644 --- a/lib/policy/config/store_test.go +++ b/lib/policy/config/store_test.go @@ -12,9 +12,9 @@ import ( func TestStoreValid(t *testing.T) { for _, tt := range []struct { + err error name string input config.Store - err error }{ { name: "no backend", diff --git a/lib/policy/config/threshold.go b/lib/policy/config/threshold.go index d9a0ed0..dd82892 100644 --- a/lib/policy/config/threshold.go +++ b/lib/policy/config/threshold.go @@ -31,10 +31,10 @@ var ( ) type Threshold struct { - Name string `json:"name" yaml:"name"` Expression *ExpressionOrList `json:"expression" yaml:"expression"` - Action Rule `json:"action" yaml:"action"` Challenge *ChallengeRules `json:"challenge" yaml:"challenge"` + Name string `json:"name" yaml:"name"` + Action Rule `json:"action" yaml:"action"` } func (t Threshold) Valid() error { diff --git a/lib/policy/config/threshold_test.go b/lib/policy/config/threshold_test.go index 1c668b2..fce15d0 100644 --- a/lib/policy/config/threshold_test.go +++ b/lib/policy/config/threshold_test.go @@ -10,9 +10,9 @@ import ( func TestThresholdValid(t *testing.T) { for _, tt := range []struct { - name string - input *Threshold err error + input *Threshold + name string }{ { name: "basic allow", diff --git a/lib/policy/expressions/environment_test.go b/lib/policy/expressions/environment_test.go index 4e7d796..75b0532 100644 --- a/lib/policy/expressions/environment_test.go +++ b/lib/policy/expressions/environment_test.go @@ -14,11 +14,11 @@ func TestBotEnvironment(t *testing.T) { t.Run("missingHeader", func(t *testing.T) { tests := []struct { + headers map[string]string name string expression string - headers map[string]string - expected types.Bool description string + expected types.Bool }{ { name: "missing-header", @@ -167,10 +167,10 @@ func TestBotEnvironment(t *testing.T) { t.Run("invalid", func(t *testing.T) { for _, tt := range []struct { + env any name string description string expression string - env any wantFailCompile bool wantFailEval bool }{ @@ -244,11 +244,11 @@ func TestThresholdEnvironment(t *testing.T) { } tests := []struct { + variables map[string]interface{} name string expression string - variables map[string]interface{} - expected types.Bool description string + expected types.Bool shouldCompile bool }{ { diff --git a/lib/policy/expressions/loadavg.go b/lib/policy/expressions/loadavg.go index 72b0878..cfbb2ae 100644 --- a/lib/policy/expressions/loadavg.go +++ b/lib/policy/expressions/loadavg.go @@ -10,8 +10,8 @@ import ( ) type loadAvg struct { - lock sync.RWMutex data *load.AvgStat + lock sync.RWMutex } func (l *loadAvg) updateThread(ctx context.Context) { diff --git a/lib/policy/policy.go b/lib/policy/policy.go index 5493d8d..27bd666 100644 --- a/lib/policy/policy.go +++ b/lib/policy/policy.go @@ -29,16 +29,15 @@ var ( ) type ParsedConfig struct { - orig *config.Config - - Bots []Bot - Thresholds []*Threshold - DNSBL bool + Store store.Interface + orig *config.Config Impressum *config.Impressum OpenGraph config.OpenGraph - DefaultDifficulty int + Bots []Bot + Thresholds []*Threshold StatusCodes config.StatusCodes - Store store.Interface + DefaultDifficulty int + DNSBL bool } func newParsedConfig(orig *config.Config) *ParsedConfig { diff --git a/lib/redirect_security_test.go b/lib/redirect_security_test.go index e16206a..2bc1690 100644 --- a/lib/redirect_security_test.go +++ b/lib/redirect_security_test.go @@ -13,7 +13,7 @@ import ( func TestRedirectSecurity(t *testing.T) { tests := []struct { - name string + reqHost string testType string // "constructRedirectURL", "serveHTTPNext", "renderIndex" // For constructRedirectURL tests @@ -23,17 +23,16 @@ func TestRedirectSecurity(t *testing.T) { // For serveHTTPNext tests redirParam string - reqHost string + name string + + errorContains string + expectedStatus int // For renderIndex tests returnHTTPStatusOnly bool - - // Expected results - expectedStatus int - shouldError bool - shouldNotRedirect bool - shouldBlock bool - errorContains string + shouldError bool + shouldNotRedirect bool + shouldBlock bool }{ // constructRedirectURL tests - X-Forwarded-Proto validation { diff --git a/lib/store/bbolt/factory_test.go b/lib/store/bbolt/factory_test.go index babc9f2..ac90e5a 100644 --- a/lib/store/bbolt/factory_test.go +++ b/lib/store/bbolt/factory_test.go @@ -17,9 +17,9 @@ func TestFactoryValid(t *testing.T) { t.Run("invalid config", func(t *testing.T) { for _, tt := range []struct { + err error name string cfg Config - err error }{ { name: "missing path", diff --git a/lib/store/s3api/factory.go b/lib/store/s3api/factory.go index 34ac10b..cfed535 100644 --- a/lib/store/s3api/factory.go +++ b/lib/store/s3api/factory.go @@ -88,8 +88,8 @@ func (Factory) Valid(data json.RawMessage) error { } type Config struct { - PathStyle bool `json:"pathStyle"` BucketName string `json:"bucketName"` + PathStyle bool `json:"pathStyle"` } func (c Config) Valid() error { diff --git a/lib/store/s3api/s3api_test.go b/lib/store/s3api/s3api_test.go index 80309dc..5b7a9c6 100644 --- a/lib/store/s3api/s3api_test.go +++ b/lib/store/s3api/s3api_test.go @@ -17,10 +17,10 @@ import ( // mockS3 is an in-memory mock of the methods we use. type mockS3 struct { - mu sync.RWMutex - bucket string data map[string][]byte meta map[string]map[string]string + bucket string + mu sync.RWMutex } func (m *mockS3) PutObject(ctx context.Context, in *s3.PutObjectInput, _ ...func(*s3.Options)) (*s3.PutObjectOutput, error) { diff --git a/lib/store/storetest/storetest.go b/lib/store/storetest/storetest.go index f04ce8a..db7da90 100644 --- a/lib/store/storetest/storetest.go +++ b/lib/store/storetest/storetest.go @@ -21,9 +21,9 @@ func Common(t *testing.T, f store.Factory, config json.RawMessage) { } for _, tt := range []struct { - name string - doer func(t *testing.T, s store.Interface) error err error + doer func(t *testing.T, s store.Interface) error + name string }{ { name: "basic get set delete",