mirror of
https://github.com/TecharoHQ/anubis.git
synced 2026-04-11 02:58:49 +00:00
Merge branch 'main' into Xe/metarefresh-randomly-refresh-header
Signed-off-by: Xe Iaso <xe.iaso@techaro.lol>
This commit is contained in:
@@ -299,6 +299,7 @@ func TestCookieSettings(t *testing.T) {
|
||||
CookieDomain: "127.0.0.1",
|
||||
CookiePartitioned: true,
|
||||
CookieSecure: true,
|
||||
CookieSameSite: http.SameSiteNoneMode,
|
||||
CookieExpiration: anubis.CookieDefaultExpirationTime,
|
||||
})
|
||||
|
||||
@@ -339,6 +340,65 @@ func TestCookieSettings(t *testing.T) {
|
||||
if ckie.Secure != srv.opts.CookieSecure {
|
||||
t.Errorf("wanted secure flag %v, got: %v", srv.opts.CookieSecure, ckie.Secure)
|
||||
}
|
||||
if ckie.SameSite != srv.opts.CookieSameSite {
|
||||
t.Errorf("wanted same site option %v, got: %v", srv.opts.CookieSameSite, ckie.SameSite)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCookieSettingsSameSiteNoneModeDowngradedToLaxWhenUnsecure(t *testing.T) {
|
||||
pol := loadPolicies(t, "testdata/zero_difficulty.yaml", 0)
|
||||
|
||||
srv := spawnAnubis(t, Options{
|
||||
Next: http.NewServeMux(),
|
||||
Policy: pol,
|
||||
|
||||
CookieDomain: "127.0.0.1",
|
||||
CookiePartitioned: true,
|
||||
CookieSecure: false,
|
||||
CookieSameSite: http.SameSiteNoneMode,
|
||||
CookieExpiration: anubis.CookieDefaultExpirationTime,
|
||||
})
|
||||
|
||||
ts := httptest.NewServer(internal.RemoteXRealIP(true, "tcp", srv))
|
||||
defer ts.Close()
|
||||
|
||||
cli := httpClient(t)
|
||||
chall := makeChallenge(t, ts, cli)
|
||||
|
||||
resp := handleChallengeZeroDifficulty(t, ts, cli, chall)
|
||||
|
||||
if resp.StatusCode != http.StatusFound {
|
||||
resp.Write(os.Stderr)
|
||||
t.Errorf("wanted %d, got: %d", http.StatusFound, resp.StatusCode)
|
||||
}
|
||||
|
||||
var ckie *http.Cookie
|
||||
for _, cookie := range resp.Cookies() {
|
||||
t.Logf("%#v", cookie)
|
||||
if cookie.Name == anubis.CookieName {
|
||||
ckie = cookie
|
||||
break
|
||||
}
|
||||
}
|
||||
if ckie == nil {
|
||||
t.Errorf("Cookie %q not found", anubis.CookieName)
|
||||
return
|
||||
}
|
||||
|
||||
if ckie.Domain != "127.0.0.1" {
|
||||
t.Errorf("cookie domain is wrong, wanted 127.0.0.1, got: %s", ckie.Domain)
|
||||
}
|
||||
|
||||
if ckie.Partitioned != srv.opts.CookiePartitioned {
|
||||
t.Errorf("wanted partitioned flag %v, got: %v", srv.opts.CookiePartitioned, ckie.Partitioned)
|
||||
}
|
||||
|
||||
if ckie.Secure != srv.opts.CookieSecure {
|
||||
t.Errorf("wanted secure flag %v, got: %v", srv.opts.CookieSecure, ckie.Secure)
|
||||
}
|
||||
if ckie.SameSite != http.SameSiteLaxMode {
|
||||
t.Errorf("wanted same site Lax option %v, got: %v", http.SameSiteLaxMode, ckie.SameSite)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCheckDefaultDifficultyMatchesPolicy(t *testing.T) {
|
||||
|
||||
@@ -43,6 +43,7 @@ type Options struct {
|
||||
OpenGraph config.OpenGraph
|
||||
ServeRobotsTXT bool
|
||||
CookieSecure bool
|
||||
CookieSameSite http.SameSite
|
||||
Logger *slog.Logger
|
||||
PublicUrl string
|
||||
JWTRestrictionHeader string
|
||||
|
||||
15
lib/http.go
15
lib/http.go
@@ -56,6 +56,8 @@ func (s *Server) SetCookie(w http.ResponseWriter, cookieOpts CookieOpts) {
|
||||
var domain = s.opts.CookieDomain
|
||||
var name = anubis.CookieName
|
||||
var path = "/"
|
||||
var sameSite = s.opts.CookieSameSite
|
||||
|
||||
if cookieOpts.Name != "" {
|
||||
name = cookieOpts.Name
|
||||
}
|
||||
@@ -72,11 +74,15 @@ func (s *Server) SetCookie(w http.ResponseWriter, cookieOpts CookieOpts) {
|
||||
cookieOpts.Expiry = s.opts.CookieExpiration
|
||||
}
|
||||
|
||||
if s.opts.CookieSameSite == http.SameSiteNoneMode && !s.opts.CookieSecure {
|
||||
sameSite = http.SameSiteLaxMode
|
||||
}
|
||||
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: name,
|
||||
Value: cookieOpts.Value,
|
||||
Expires: time.Now().Add(cookieOpts.Expiry),
|
||||
SameSite: http.SameSiteNoneMode,
|
||||
SameSite: sameSite,
|
||||
Domain: domain,
|
||||
Secure: s.opts.CookieSecure,
|
||||
Partitioned: s.opts.CookiePartitioned,
|
||||
@@ -88,6 +94,8 @@ func (s *Server) ClearCookie(w http.ResponseWriter, cookieOpts CookieOpts) {
|
||||
var domain = s.opts.CookieDomain
|
||||
var name = anubis.CookieName
|
||||
var path = "/"
|
||||
var sameSite = s.opts.CookieSameSite
|
||||
|
||||
if cookieOpts.Name != "" {
|
||||
name = cookieOpts.Name
|
||||
}
|
||||
@@ -99,13 +107,16 @@ func (s *Server) ClearCookie(w http.ResponseWriter, cookieOpts CookieOpts) {
|
||||
domain = etld
|
||||
}
|
||||
}
|
||||
if s.opts.CookieSameSite == http.SameSiteNoneMode && !s.opts.CookieSecure {
|
||||
sameSite = http.SameSiteLaxMode
|
||||
}
|
||||
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: name,
|
||||
Value: "",
|
||||
MaxAge: -1,
|
||||
Expires: time.Now().Add(-1 * time.Minute),
|
||||
SameSite: http.SameSiteNoneMode,
|
||||
SameSite: sameSite,
|
||||
Partitioned: s.opts.CookiePartitioned,
|
||||
Domain: domain,
|
||||
Secure: s.opts.CookieSecure,
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"iters_b": "Iters B",
|
||||
"static_check_endpoint": "Dit is gewoon een controle-eindpunt voor uw reverse proxy om te gebruiken.",
|
||||
"authorization_required": "Autorisatie vereist",
|
||||
"cookies_disabled": "Uw browser is geconfigureerd om koekjes uit te schakelen. Anubis heeft koekjes nodig om er zeker van te zijn dat u een geldige klant bent. Schakel cookies in voor dit domein",
|
||||
"cookies_disabled": "Uw browser is geconfigureerd om cookies uit te schakelen. Anubis heeft cookies nodig om er zeker van te zijn dat u een geldige klant bent. Schakel cookies in voor dit domein",
|
||||
"access_denied": "Toegang geweigerd: foutcode",
|
||||
"dronebl_entry": "DroneBL meldde een item",
|
||||
"see_dronebl_lookup": "zie",
|
||||
@@ -45,7 +45,7 @@
|
||||
"celphase": "CELPHASE",
|
||||
"js_web_crypto_error": "Uw browser heeft geen werkend web.crypto-element. Bekijkt u dit via een beveiligde context?",
|
||||
"js_web_workers_error": "Je browser ondersteunt geen web-takers (Anubis gebruikt dit om te voorkomen dat je browser bevriest). Heb je een plugin zoals JShelter geïnstalleerd?",
|
||||
"js_cookies_error": "Uw browser slaat geen cookies op. Anubis gebruikt cookies om te bepalen welke klanten geslaagd zijn voor uitdagingen door een ondertekend token in een koekje op te slaan. Schakel het opslaan van koekjes voor dit domein in. De namen van de koekjes die Anubis opslaat, kunnen zonder voorafgaande kennisgeving variëren. Koekjesnamen en -waarden maken geen deel uit van de openbare API.",
|
||||
"js_cookies_error": "Uw browser slaat geen cookies op. Anubis gebruikt cookies om te bepalen welke klanten geslaagd zijn voor uitdagingen door een ondertekend token in een cookie op te slaan. Schakel het opslaan van cookies voor dit domein in. De namen van de cookies die Anubis opslaat, kunnen zonder voorafgaande kennisgeving variëren. cookiesnamen en -waarden maken geen deel uit van de openbare API.",
|
||||
"js_context_not_secure": "Je context is niet veilig!",
|
||||
"js_context_not_secure_msg": "Probeer verbinding te maken via HTTPS of laat de beheerder weten dat HTTPS moet worden ingesteld. Zie <a href=\"https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts#when_is_a_context_considered_secure\">MDN</a> voor meer informatie.",
|
||||
"js_calculating": "Berekenen...",
|
||||
|
||||
@@ -61,6 +61,8 @@ func (cr *CELRequest) ResolveName(name string) (any, bool) {
|
||||
switch name {
|
||||
case "remoteAddress":
|
||||
return cr.Header.Get("X-Real-Ip"), true
|
||||
case "contentLength":
|
||||
return cr.ContentLength, true
|
||||
case "host":
|
||||
return cr.Host, true
|
||||
case "method":
|
||||
|
||||
@@ -19,6 +19,7 @@ func BotEnvironment() (*cel.Env, error) {
|
||||
return New(
|
||||
// Variables exposed to CEL programs:
|
||||
cel.Variable("remoteAddress", cel.StringType),
|
||||
cel.Variable("contentLength", cel.IntType),
|
||||
cel.Variable("host", cel.StringType),
|
||||
cel.Variable("method", cel.StringType),
|
||||
cel.Variable("userAgent", cel.StringType),
|
||||
|
||||
82
lib/store/actorifiedstore.go
Normal file
82
lib/store/actorifiedstore.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/TecharoHQ/anubis/internal/actorify"
|
||||
)
|
||||
|
||||
type unit struct{}
|
||||
|
||||
type ActorifiedStore struct {
|
||||
Interface
|
||||
|
||||
deleteActor *actorify.Actor[string, unit]
|
||||
getActor *actorify.Actor[string, []byte]
|
||||
setActor *actorify.Actor[*actorSetReq, unit]
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
type actorSetReq struct {
|
||||
key string
|
||||
value []byte
|
||||
expiry time.Duration
|
||||
}
|
||||
|
||||
func NewActorifiedStore(backend Interface) *ActorifiedStore {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
result := &ActorifiedStore{
|
||||
Interface: backend,
|
||||
cancel: cancel,
|
||||
}
|
||||
|
||||
result.deleteActor = actorify.New(ctx, result.actorDelete)
|
||||
result.getActor = actorify.New(ctx, backend.Get)
|
||||
result.setActor = actorify.New(ctx, result.actorSet)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (a *ActorifiedStore) Close() { a.cancel() }
|
||||
|
||||
func (a *ActorifiedStore) Delete(ctx context.Context, key string) error {
|
||||
if _, err := a.deleteActor.Call(ctx, key); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *ActorifiedStore) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
return a.getActor.Call(ctx, key)
|
||||
}
|
||||
|
||||
func (a *ActorifiedStore) Set(ctx context.Context, key string, value []byte, expiry time.Duration) error {
|
||||
if _, err := a.setActor.Call(ctx, &actorSetReq{
|
||||
key: key,
|
||||
value: value,
|
||||
expiry: expiry,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *ActorifiedStore) actorDelete(ctx context.Context, key string) (unit, error) {
|
||||
if err := a.Interface.Delete(ctx, key); err != nil {
|
||||
return unit{}, err
|
||||
}
|
||||
|
||||
return unit{}, nil
|
||||
}
|
||||
|
||||
func (a *ActorifiedStore) actorSet(ctx context.Context, req *actorSetReq) (unit, error) {
|
||||
if err := a.Interface.Set(ctx, req.key, req.value, req.expiry); err != nil {
|
||||
return unit{}, err
|
||||
}
|
||||
|
||||
return unit{}, nil
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func (Factory) Build(ctx context.Context, data json.RawMessage) (store.Interface
|
||||
|
||||
go result.cleanupThread(ctx)
|
||||
|
||||
return result, nil
|
||||
return store.NewActorifiedStore(result), nil
|
||||
}
|
||||
|
||||
// Valid parses and validates the bbolt store Config or returns
|
||||
|
||||
Reference in New Issue
Block a user