mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-05 16:28:17 +00:00
Compare commits
3 Commits
Xe/smoke-t
...
Xe/valkey-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0c4fcc398 | ||
|
|
9d05ea6430 | ||
|
|
21ee6e3406 |
2
.github/actions/spelling/expect.txt
vendored
2
.github/actions/spelling/expect.txt
vendored
@@ -199,6 +199,7 @@ qwant
|
||||
qwantbot
|
||||
rac
|
||||
rcvar
|
||||
rdb
|
||||
redir
|
||||
redirectscheme
|
||||
relayd
|
||||
@@ -252,6 +253,7 @@ unmarshal
|
||||
uuidgen
|
||||
uvx
|
||||
UXP
|
||||
valkey
|
||||
Varis
|
||||
Velen
|
||||
vendored
|
||||
|
||||
@@ -67,6 +67,7 @@ var (
|
||||
ogCacheConsiderHost = flag.Bool("og-cache-consider-host", false, "enable or disable the use of the host in the Open Graph tag cache")
|
||||
extractResources = flag.String("extract-resources", "", "if set, extract the static resources to the specified folder")
|
||||
webmasterEmail = flag.String("webmaster-email", "", "if set, displays webmaster's email on the reject page for appeals")
|
||||
valkeyURL = flag.String("valkey-url", "", "Valkey URL for Anubis' state layer")
|
||||
versionFlag = flag.Bool("version", false, "print Anubis version")
|
||||
xffStripPrivate = flag.Bool("xff-strip-private", true, "if set, strip private addresses from X-Forwarded-For")
|
||||
)
|
||||
|
||||
2
go.mod
2
go.mod
@@ -9,6 +9,7 @@ require (
|
||||
github.com/google/cel-go v0.25.0
|
||||
github.com/playwright-community/playwright-go v0.5200.0
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/redis/go-redis/v9 v9.9.0
|
||||
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a
|
||||
github.com/yl2chen/cidranger v1.0.2
|
||||
golang.org/x/net v0.41.0
|
||||
@@ -41,6 +42,7 @@ require (
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/deckarep/golang-set/v2 v2.8.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dlclark/regexp2 v1.11.4 // indirect
|
||||
github.com/dop251/goja v0.0.0-20250309171923-bcd7cc6bf64c // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
|
||||
8
go.sum
8
go.sum
@@ -46,6 +46,10 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4=
|
||||
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/caarlos0/testfs v0.4.4 h1:3PHvzHi5Lt+g332CiShwS8ogTgS3HjrmzZxCm6JCDr8=
|
||||
github.com/caarlos0/testfs v0.4.4/go.mod h1:bRN55zgG4XCUVVHZCeU+/Tz1Q6AxEJOEJTliBy+1DMk=
|
||||
github.com/cavaliergopher/cpio v1.0.1 h1:KQFSeKmZhv0cr+kawA3a0xTQCU4QxXF1vhU7P7av2KM=
|
||||
@@ -75,6 +79,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ=
|
||||
github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
|
||||
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dop251/goja v0.0.0-20250309171923-bcd7cc6bf64c h1:mxWGS0YyquJ/ikZOjSrRjjFIbUqIP9ojyYQ+QZTU3Rg=
|
||||
@@ -228,6 +234,8 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/redis/go-redis/v9 v9.9.0 h1:URbPQ4xVQSQhZ27WMQVmZSo3uT3pL+4IdHVcYq2nVfM=
|
||||
github.com/redis/go-redis/v9 v9.9.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
|
||||
10
internal/store/store.go
Normal file
10
internal/store/store.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package store
|
||||
|
||||
import "context"
|
||||
|
||||
type Impl interface {
|
||||
GetInt(ctx context.Context, segments []string) (int, error)
|
||||
MultiGetInt(ctx context.Context, segments [][]string) ([]int, error)
|
||||
|
||||
Increment(ctx context.Context, segments []string) error
|
||||
}
|
||||
91
internal/store/valkey/valkey.go
Normal file
91
internal/store/valkey/valkey.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package valkey
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/TecharoHQ/anubis/internal/store"
|
||||
valkey "github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
var (
|
||||
_ store.Impl = &Store{}
|
||||
)
|
||||
|
||||
type Store struct {
|
||||
rdb *valkey.Client
|
||||
}
|
||||
|
||||
func New(rdb *valkey.Client) *Store {
|
||||
return &Store{rdb: rdb}
|
||||
}
|
||||
|
||||
func (s *Store) Increment(ctx context.Context, segments []string) error {
|
||||
key := fmt.Sprintf("anubis:%s", strings.Join(segments, ":"))
|
||||
if err := s.rdb.Incr(ctx, key).Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) GetInt(ctx context.Context, segments []string) (int, error) {
|
||||
key := fmt.Sprintf("anubis:%s", strings.Join(segments, ":"))
|
||||
numStr, err := s.rdb.Get(ctx, key).Result()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
num, err := strconv.Atoi(numStr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return num, nil
|
||||
}
|
||||
|
||||
func (s *Store) MultiGetInt(ctx context.Context, segments [][]string) ([]int, error) {
|
||||
var keys []string
|
||||
for _, segment := range segments {
|
||||
key := fmt.Sprintf("anubis:%s", strings.Join(segment, ":"))
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
values, err := s.rdb.MGet(ctx, keys...).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var errs []error
|
||||
|
||||
result := make([]int, len(values))
|
||||
for i, val := range values {
|
||||
if val == nil {
|
||||
result[i] = 0
|
||||
errs = append(errs, fmt.Errorf("can't get key %s: value is null", keys[i]))
|
||||
continue
|
||||
}
|
||||
|
||||
switch v := val.(type) {
|
||||
case string:
|
||||
num, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("can't parse key %s: %w", keys[i], err))
|
||||
continue
|
||||
}
|
||||
|
||||
result[i] = num
|
||||
default:
|
||||
errs = append(errs, fmt.Errorf("can't parse key %s: wanted type string but got type %T", keys[i], val))
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) != 0 {
|
||||
return nil, fmt.Errorf("can't read from valkey: %w", errors.Join(errs...))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/TecharoHQ/anubis/internal"
|
||||
"github.com/TecharoHQ/anubis/internal/dnsbl"
|
||||
"github.com/TecharoHQ/anubis/internal/ogtags"
|
||||
"github.com/TecharoHQ/anubis/internal/store"
|
||||
"github.com/TecharoHQ/anubis/lib/challenge"
|
||||
"github.com/TecharoHQ/anubis/lib/policy"
|
||||
"github.com/TecharoHQ/anubis/lib/policy/config"
|
||||
@@ -70,6 +71,7 @@ type Server struct {
|
||||
priv ed25519.PrivateKey
|
||||
pub ed25519.PublicKey
|
||||
opts Options
|
||||
store store.Impl
|
||||
}
|
||||
|
||||
func (s *Server) challengeFor(r *http.Request, difficulty int) string {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
@@ -18,10 +19,12 @@ import (
|
||||
"github.com/TecharoHQ/anubis/internal"
|
||||
"github.com/TecharoHQ/anubis/internal/dnsbl"
|
||||
"github.com/TecharoHQ/anubis/internal/ogtags"
|
||||
"github.com/TecharoHQ/anubis/internal/store/valkey"
|
||||
"github.com/TecharoHQ/anubis/lib/challenge"
|
||||
"github.com/TecharoHQ/anubis/lib/policy"
|
||||
"github.com/TecharoHQ/anubis/web"
|
||||
"github.com/TecharoHQ/anubis/xess"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
@@ -40,6 +43,7 @@ type Options struct {
|
||||
OGPassthrough bool
|
||||
CookiePartitioned bool
|
||||
ServeRobotsTXT bool
|
||||
ValkeyURL string
|
||||
}
|
||||
|
||||
func LoadPoliciesOrDefault(fname string, defaultDifficulty int) (*policy.ParsedConfig, error) {
|
||||
@@ -114,6 +118,23 @@ func New(opts Options) (*Server, error) {
|
||||
cookieName: cookieName,
|
||||
}
|
||||
|
||||
if opts.ValkeyURL != "" {
|
||||
vkOpts, err := redis.ParseURL(opts.ValkeyURL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't parse valkey URL: %q: %w", opts.ValkeyURL, err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||
defer cancel()
|
||||
|
||||
cli := redis.NewClient(vkOpts)
|
||||
if _, err := cli.Ping(ctx).Result(); err != nil {
|
||||
return nil, fmt.Errorf("can't ping valkey: %w", err)
|
||||
}
|
||||
|
||||
result.store = valkey.New(cli)
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
xess.Mount(mux)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user