This commit is contained in:
WeebDataHoarder
2025-04-25 12:08:55 +02:00
parent bc0eaeca21
commit 4d7436c51b
9 changed files with 125 additions and 357 deletions

View File

@@ -1,13 +1,13 @@
package challenge
import (
http_cel "codeberg.org/gone/http-cel"
"context"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
"git.gammaspectra.live/git/go-away/lib/condition"
"git.gammaspectra.live/git/go-away/utils"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
@@ -73,8 +73,8 @@ func CreateRequestData(r *http.Request, state StateInterface) (*http.Request, *R
}
}
data.query = condition.NewValuesMap(r.URL.Query())
data.header = condition.NewMIMEMap(textproto.MIMEHeader(r.Header))
data.query = http_cel.NewValuesMap(r.URL.Query())
data.header = http_cel.NewMIMEMap(textproto.MIMEHeader(r.Header))
sum := sha256.New()
sum.Write([]byte(r.Host))

View File

@@ -2,10 +2,10 @@ package challenge
import (
"bytes"
http_cel "codeberg.org/gone/http-cel"
"crypto/ed25519"
"errors"
"fmt"
"git.gammaspectra.live/git/go-away/lib/condition"
"git.gammaspectra.live/git/go-away/lib/policy"
"github.com/go-jose/go-jose/v4"
"github.com/go-jose/go-jose/v4/jwt"
@@ -67,11 +67,11 @@ func (r Register) Create(state StateInterface, name string, pol policy.Challenge
}
if len(conditions) > 0 {
ast, err := condition.FromStrings(state.ProgramEnv(), condition.OperatorOr, conditions...)
ast, err := http_cel.NewAst(state.ProgramEnv(), http_cel.OperatorOr, conditions...)
if err != nil {
return nil, 0, fmt.Errorf("error compiling conditions: %v", err)
}
reg.Condition, err = condition.Program(state.ProgramEnv(), ast)
reg.Condition, err = http_cel.ProgramAst(state.ProgramEnv(), ast)
if err != nil {
return nil, 0, fmt.Errorf("error compiling program: %v", err)
}

View File

@@ -1,177 +0,0 @@
package condition
import (
"fmt"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/ext"
"github.com/yl2chen/cidranger"
"log/slog"
"net"
"strings"
)
type Condition struct {
Expression *cel.Ast
}
const (
OperatorOr = "||"
OperatorAnd = "&&"
)
func NewRulesEnvironment(networks map[string]cidranger.Ranger) (*cel.Env, error) {
return cel.NewEnv(
ext.Strings(
ext.StringsLocale("en_US"),
ext.StringsValidateFormatCalls(true),
),
cel.DefaultUTCTimeZone(true),
//TODO: custom type for remoteAddress
cel.Variable("remoteAddress", cel.BytesType),
cel.Variable("host", cel.StringType),
cel.Variable("method", cel.StringType),
cel.Variable("userAgent", cel.StringType),
cel.Variable("path", cel.StringType),
cel.Variable("query", cel.MapType(cel.StringType, cel.StringType)),
cel.Variable("fp", cel.MapType(cel.StringType, cel.StringType)),
// http.Header
cel.Variable("headers", cel.MapType(cel.StringType, cel.StringType)),
//TODO: dynamic type?
cel.Function("inDNSBL",
cel.Overload("inDNSBL_ip",
[]*cel.Type{cel.AnyType},
cel.BoolType,
cel.UnaryBinding(func(val ref.Val) ref.Val {
slog.Error("inDNSBL function has been deprecated, replace with dnsbl challenge")
return types.Bool(false)
}),
),
),
cel.Function("network",
cel.MemberOverload("netIP_network_string",
[]*cel.Type{cel.BytesType, cel.StringType},
cel.BoolType,
cel.BinaryBinding(func(lhs ref.Val, rhs ref.Val) ref.Val {
var ip net.IP
switch v := lhs.Value().(type) {
case []byte:
ip = v
case net.IP:
ip = v
}
if ip == nil {
panic(fmt.Errorf("invalid ip %v", lhs.Value()))
}
val, ok := rhs.Value().(string)
if !ok {
panic(fmt.Errorf("invalid network value %v", rhs.Value()))
}
network, ok := networks[val]
if !ok {
_, ipNet, err := net.ParseCIDR(val)
if err != nil {
panic("network not found")
}
return types.Bool(ipNet.Contains(ip))
} else {
ok, err := network.Contains(ip)
if err != nil {
panic(err)
}
return types.Bool(ok)
}
}),
),
),
cel.Function("inNetwork",
cel.Overload("inNetwork_string_ip",
[]*cel.Type{cel.StringType, cel.BytesType},
cel.BoolType,
cel.BinaryBinding(func(lhs ref.Val, rhs ref.Val) ref.Val {
var ip net.IP
switch v := rhs.Value().(type) {
case []byte:
ip = v
case net.IP:
ip = v
}
if ip == nil {
panic(fmt.Errorf("invalid ip %v", rhs.Value()))
}
val, ok := lhs.Value().(string)
if !ok {
panic(fmt.Errorf("invalid value %v", lhs.Value()))
}
slog.Debug(fmt.Sprintf("inNetwork function has been deprecated and will be removed in a future release, use remoteAddress.network(\"%s\") instead", val))
network, ok := networks[val]
if !ok {
_, ipNet, err := net.ParseCIDR(val)
if err != nil {
panic("network not found")
}
return types.Bool(ipNet.Contains(ip))
} else {
ok, err := network.Contains(ip)
if err != nil {
panic(err)
}
return types.Bool(ok)
}
}),
),
),
)
}
func Program(env *cel.Env, ast *cel.Ast) (cel.Program, error) {
return env.Program(ast,
cel.EvalOptions(cel.OptOptimize),
)
}
func FromStrings(env *cel.Env, operator string, conditions ...string) (*cel.Ast, error) {
var asts []*cel.Ast
for _, c := range conditions {
ast, issues := env.Compile(c)
if issues != nil && issues.Err() != nil {
return nil, fmt.Errorf("condition %s: %s", issues.Err(), c)
}
asts = append(asts, ast)
}
return Merge(env, operator, asts...)
}
func Merge(env *cel.Env, operator string, conditions ...*cel.Ast) (*cel.Ast, error) {
if len(conditions) == 0 {
return nil, nil
} else if len(conditions) == 1 {
return conditions[0], nil
}
var asts []string
for _, c := range conditions {
ast, err := cel.AstToString(c)
if err != nil {
return nil, err
}
asts = append(asts, "("+ast+")")
}
condition := strings.Join(asts, " "+operator+" ")
ast, issues := env.Compile(condition)
if issues != nil && issues.Err() != nil {
return nil, issues.Err()
}
return ast, nil
}

View File

@@ -1,158 +0,0 @@
package condition
import (
"fmt"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"github.com/google/cel-go/common/types/traits"
"net/textproto"
"reflect"
"strings"
)
type mimeLike struct {
m textproto.MIMEHeader
}
func (a mimeLike) ConvertToNative(typeDesc reflect.Type) (any, error) {
return nil, fmt.Errorf("type conversion error from map to '%v'", typeDesc)
}
func (a mimeLike) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case types.MapType:
return a
case types.TypeType:
return types.MapType
}
return types.NewErr("type conversion error from '%s' to '%s'", types.MapType, typeVal)
}
func (a mimeLike) Equal(other ref.Val) ref.Val {
return types.Bool(false)
}
func (a mimeLike) Type() ref.Type {
return types.MapType
}
func (a mimeLike) Value() any {
return a.m
}
func (a mimeLike) Contains(key ref.Val) ref.Val {
_, found := a.Find(key)
return types.Bool(found)
}
func (a mimeLike) Get(key ref.Val) ref.Val {
v, found := a.Find(key)
if !found {
return types.ValOrErr(v, "no such key: %v", key)
}
return v
}
func (a mimeLike) Iterator() traits.Iterator {
panic("implement me")
}
func (a mimeLike) IsZeroValue() bool {
return len(a.m) == 0
}
func (a mimeLike) Size() ref.Val {
return types.Int(len(a.m))
}
func (a mimeLike) Find(key ref.Val) (ref.Val, bool) {
k, ok := key.(types.String)
if !ok {
return nil, false
}
return singleVal(a.m.Values(string(k)), true)
}
type valuesLike struct {
m map[string][]string
}
func (a valuesLike) ConvertToNative(typeDesc reflect.Type) (any, error) {
return nil, fmt.Errorf("type conversion error from map to '%v'", typeDesc)
}
func (a valuesLike) ConvertToType(typeVal ref.Type) ref.Val {
switch typeVal {
case types.MapType:
return a
case types.TypeType:
return types.MapType
}
return types.NewErr("type conversion error from '%s' to '%s'", types.MapType, typeVal)
}
func (a valuesLike) Equal(other ref.Val) ref.Val {
return types.Bool(false)
}
func (a valuesLike) Type() ref.Type {
return types.MapType
}
func (a valuesLike) Value() any {
return a.m
}
func (a valuesLike) Contains(key ref.Val) ref.Val {
_, found := a.Find(key)
return types.Bool(found)
}
func (a valuesLike) Get(key ref.Val) ref.Val {
v, found := a.Find(key)
if !found {
return types.ValOrErr(v, "no such key: %v", key)
}
return v
}
func (a valuesLike) Iterator() traits.Iterator {
panic("implement me")
}
func (a valuesLike) IsZeroValue() bool {
return len(a.m) == 0
}
func (a valuesLike) Size() ref.Val {
return types.Int(len(a.m))
}
func (a valuesLike) Find(key ref.Val) (ref.Val, bool) {
k, ok := key.(types.String)
if !ok {
return nil, false
}
val, ok := a.m[string(k)]
return singleVal(val, ok)
}
func singleVal(values []string, ok bool) (ref.Val, bool) {
if len(values) == 0 || !ok {
return nil, false
}
if len(values) > 1 {
return types.String(strings.Join(values, ",")), true
}
return types.String(values[0]), true
}
func NewMIMEMap(m textproto.MIMEHeader) traits.Mapper {
return mimeLike{m: m}
}
func NewValuesMap(m map[string][]string) traits.Mapper {
return valuesLike{m: m}
}

View File

@@ -1,11 +1,111 @@
package lib
import (
"git.gammaspectra.live/git/go-away/lib/condition"
http_cel "codeberg.org/gone/http-cel"
"fmt"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
"log/slog"
"net"
)
func (state *State) initConditions() (err error) {
state.programEnv, err = condition.NewRulesEnvironment(state.networks)
state.programEnv, err = http_cel.NewEnvironment(
cel.Variable("fp", cel.MapType(cel.StringType, cel.StringType)),
cel.Function("inDNSBL",
cel.Overload("inDNSBL_ip",
[]*cel.Type{cel.AnyType},
cel.BoolType,
cel.UnaryBinding(func(val ref.Val) ref.Val {
slog.Error("inDNSBL function has been deprecated, replace with dnsbl challenge")
return types.Bool(false)
}),
),
),
cel.Function("network",
cel.MemberOverload("netIP_network_string",
[]*cel.Type{cel.BytesType, cel.StringType},
cel.BoolType,
cel.BinaryBinding(func(lhs ref.Val, rhs ref.Val) ref.Val {
var ip net.IP
switch v := lhs.Value().(type) {
case []byte:
ip = v
case net.IP:
ip = v
}
if ip == nil {
panic(fmt.Errorf("invalid ip %v", lhs.Value()))
}
val, ok := rhs.Value().(string)
if !ok {
panic(fmt.Errorf("invalid network value %v", rhs.Value()))
}
network, ok := state.networks[val]
if !ok {
_, ipNet, err := net.ParseCIDR(val)
if err != nil {
panic("network not found")
}
return types.Bool(ipNet.Contains(ip))
} else {
ok, err := network.Contains(ip)
if err != nil {
panic(err)
}
return types.Bool(ok)
}
}),
),
),
cel.Function("inNetwork",
cel.Overload("inNetwork_string_ip",
[]*cel.Type{cel.StringType, cel.BytesType},
cel.BoolType,
cel.BinaryBinding(func(lhs ref.Val, rhs ref.Val) ref.Val {
var ip net.IP
switch v := rhs.Value().(type) {
case []byte:
ip = v
case net.IP:
ip = v
}
if ip == nil {
panic(fmt.Errorf("invalid ip %v", rhs.Value()))
}
val, ok := lhs.Value().(string)
if !ok {
panic(fmt.Errorf("invalid value %v", lhs.Value()))
}
slog.Debug(fmt.Sprintf("inNetwork function has been deprecated and will be removed in a future release, use remoteAddress.network(\"%s\") instead", val))
network, ok := state.networks[val]
if !ok {
_, ipNet, err := net.ParseCIDR(val)
if err != nil {
panic("network not found")
}
return types.Bool(ipNet.Contains(ip))
} else {
ok, err := network.Contains(ip)
if err != nil {
panic(err)
}
return types.Bool(ok)
}
}),
),
),
)
if err != nil {
return err
}

View File

@@ -1,12 +1,12 @@
package lib
import (
http_cel "codeberg.org/gone/http-cel"
"crypto/sha256"
"encoding/hex"
"fmt"
"git.gammaspectra.live/git/go-away/lib/action"
"git.gammaspectra.live/git/go-away/lib/challenge"
"git.gammaspectra.live/git/go-away/lib/condition"
"git.gammaspectra.live/git/go-away/lib/policy"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
@@ -66,12 +66,12 @@ func NewRuleState(state challenge.StateInterface, r policy.Rule, replacer *strin
conditions = append(conditions, cond)
}
ast, err := condition.FromStrings(state.ProgramEnv(), condition.OperatorOr, conditions...)
ast, err := http_cel.NewAst(state.ProgramEnv(), http_cel.OperatorOr, conditions...)
if err != nil {
return RuleState{}, fmt.Errorf("error compiling conditions: %w", err)
}
program, err := condition.Program(state.ProgramEnv(), ast)
program, err := http_cel.ProgramAst(state.ProgramEnv(), ast)
if err != nil {
return RuleState{}, fmt.Errorf("error compiling program: %w", err)
}

View File

@@ -1,12 +1,12 @@
package lib
import (
http_cel "codeberg.org/gone/http-cel"
"crypto/ed25519"
"crypto/rand"
"encoding/json"
"fmt"
"git.gammaspectra.live/git/go-away/lib/challenge"
"git.gammaspectra.live/git/go-away/lib/condition"
"git.gammaspectra.live/git/go-away/lib/policy"
"git.gammaspectra.live/git/go-away/lib/settings"
"git.gammaspectra.live/git/go-away/utils"
@@ -191,7 +191,7 @@ func NewState(p policy.Policy, opt settings.Settings, settings policy.StateSetti
var replacements []string
for k, entries := range p.Conditions {
ast, err := condition.FromStrings(state.programEnv, condition.OperatorOr, entries...)
ast, err := http_cel.NewAst(state.programEnv, http_cel.OperatorOr, entries...)
if err != nil {
return nil, fmt.Errorf("conditions %s: error compiling conditions: %v", k, err)
}