diff options
| author | Jason Cameron <git@jasoncameron.dev> | 2025-04-27 09:36:39 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-27 13:36:39 +0000 |
| commit | 301c7a42bde10cad814f9caa9f6320356734f499 (patch) | |
| tree | 5aaf8d8a79bc77662cf3abf6ad9a97e9f4bb5502 /lib/config.go | |
| parent | 755c18a9a76cf07e71f4c8e5f6cbc890411cf38f (diff) | |
| download | anubis-301c7a42bde10cad814f9caa9f6320356734f499.tar.xz anubis-301c7a42bde10cad814f9caa9f6320356734f499.zip | |
refactor(lib): Split up anubis.go into some smaller files. (#379)
* refactor(logging): centralize logger creation in GetLogger function
Signed-off-by: Jason Cameron <git@jasoncameron.dev>
* refactor(logging): rename GetLogger to GetRequestLogger for clarity
Signed-off-by: Jason Cameron <git@jasoncameron.dev>
* refactor: streamline error handling and response methods
Signed-off-by: Jason Cameron <git@jasoncameron.dev>
* refactor(lib): Split anubis.go up into some smaller specialized methods
Signed-off-by: Jason Cameron <git@jasoncameron.dev>
* refactor(http): simplify error response handling by using respondWithStatus
Signed-off-by: Jason Cameron <git@jasoncameron.dev>
* chore(lib): run goimports
Signed-off-by: Xe Iaso <me@xeiaso.net>
---------
Signed-off-by: Jason Cameron <git@jasoncameron.dev>
Signed-off-by: Xe Iaso <me@xeiaso.net>
Co-authored-by: Xe Iaso <me@xeiaso.net>
Diffstat (limited to 'lib/config.go')
| -rw-r--r-- | lib/config.go | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/lib/config.go b/lib/config.go new file mode 100644 index 0000000..81d2bcd --- /dev/null +++ b/lib/config.go @@ -0,0 +1,138 @@ +package lib + +import ( + "crypto/ed25519" + "crypto/rand" + "fmt" + "io" + "log/slog" + "net/http" + "os" + "strings" + "time" + + "github.com/TecharoHQ/anubis" + "github.com/TecharoHQ/anubis/data" + "github.com/TecharoHQ/anubis/decaymap" + "github.com/TecharoHQ/anubis/internal" + "github.com/TecharoHQ/anubis/internal/dnsbl" + "github.com/TecharoHQ/anubis/internal/ogtags" + "github.com/TecharoHQ/anubis/lib/policy" + "github.com/TecharoHQ/anubis/web" + "github.com/TecharoHQ/anubis/xess" +) + +type Options struct { + Next http.Handler + Policy *policy.ParsedConfig + RedirectDomains []string + ServeRobotsTXT bool + PrivateKey ed25519.PrivateKey + + CookieDomain string + CookieName string + CookiePartitioned bool + + OGPassthrough bool + OGTimeToLive time.Duration + Target string + + WebmasterEmail string + BasePrefix string +} + +func LoadPoliciesOrDefault(fname string, defaultDifficulty int) (*policy.ParsedConfig, error) { + var fin io.ReadCloser + var err error + + if fname != "" { + fin, err = os.Open(fname) + if err != nil { + return nil, fmt.Errorf("can't parse policy file %s: %w", fname, err) + } + } else { + fname = "(data)/botPolicies.yaml" + fin, err = data.BotPolicies.Open("botPolicies.yaml") + if err != nil { + return nil, fmt.Errorf("[unexpected] can't parse builtin policy file %s: %w", fname, err) + } + } + + defer func(fin io.ReadCloser) { + err := fin.Close() + if err != nil { + slog.Error("failed to close policy file", "file", fname, "err", err) + } + }(fin) + + anubisPolicy, err := policy.ParseConfig(fin, fname, defaultDifficulty) + + return anubisPolicy, err +} + +func New(opts Options) (*Server, error) { + if opts.PrivateKey == nil { + slog.Debug("opts.PrivateKey not set, generating a new one") + _, priv, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return nil, fmt.Errorf("lib: can't generate private key: %v", err) + } + opts.PrivateKey = priv + } + + anubis.BasePrefix = opts.BasePrefix + + result := &Server{ + next: opts.Next, + priv: opts.PrivateKey, + pub: opts.PrivateKey.Public().(ed25519.PublicKey), + policy: opts.Policy, + opts: opts, + DNSBLCache: decaymap.New[string, dnsbl.DroneBLResponse](), + OGTags: ogtags.NewOGTagCache(opts.Target, opts.OGPassthrough, opts.OGTimeToLive), + } + + mux := http.NewServeMux() + xess.Mount(mux) + + // Helper to add global prefix + registerWithPrefix := func(pattern string, handler http.Handler, method string) { + if method != "" { + method = method + " " // methods must end with a space to register with them + } + + // Ensure there's no double slash when concatenating BasePrefix and pattern + basePrefix := strings.TrimSuffix(anubis.BasePrefix, "/") + prefix := method + basePrefix + + // If pattern doesn't start with a slash, add one + if !strings.HasPrefix(pattern, "/") { + pattern = "/" + pattern + } + + mux.Handle(prefix+pattern, handler) + } + + // Ensure there's no double slash when concatenating BasePrefix and StaticPath + stripPrefix := strings.TrimSuffix(anubis.BasePrefix, "/") + anubis.StaticPath + registerWithPrefix(anubis.StaticPath, internal.UnchangingCache(internal.NoBrowsing(http.StripPrefix(stripPrefix, http.FileServerFS(web.Static)))), "") + + if opts.ServeRobotsTXT { + registerWithPrefix("/robots.txt", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.ServeFileFS(w, r, web.Static, "static/robots.txt") + }), "GET") + registerWithPrefix("/.well-known/robots.txt", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.ServeFileFS(w, r, web.Static, "static/robots.txt") + }), "GET") + } + + registerWithPrefix(anubis.APIPrefix+"make-challenge", http.HandlerFunc(result.MakeChallenge), "POST") + registerWithPrefix(anubis.APIPrefix+"pass-challenge", http.HandlerFunc(result.PassChallenge), "GET") + registerWithPrefix(anubis.APIPrefix+"check", http.HandlerFunc(result.maybeReverseProxyHttpStatusOnly), "") + registerWithPrefix(anubis.APIPrefix+"test-error", http.HandlerFunc(result.TestError), "GET") + registerWithPrefix("/", http.HandlerFunc(result.maybeReverseProxyOrPage), "") + + result.mux = mux + + return result, nil +} |
