aboutsummaryrefslogtreecommitdiff
path: root/lib/config.go
diff options
context:
space:
mode:
authorJason Cameron <git@jasoncameron.dev>2025-04-27 09:36:39 -0400
committerGitHub <noreply@github.com>2025-04-27 13:36:39 +0000
commit301c7a42bde10cad814f9caa9f6320356734f499 (patch)
tree5aaf8d8a79bc77662cf3abf6ad9a97e9f4bb5502 /lib/config.go
parent755c18a9a76cf07e71f4c8e5f6cbc890411cf38f (diff)
downloadanubis-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.go138
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
+}