Skip to content

Commit

Permalink
foobar
Browse files Browse the repository at this point in the history
  • Loading branch information
fionera committed Nov 4, 2023
1 parent f0b39fb commit 3c342ce
Show file tree
Hide file tree
Showing 21 changed files with 728 additions and 60 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.idea
*.iml
*.iml
*.sock
7 changes: 6 additions & 1 deletion DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,9 @@ Cookie

https://challenges.cloudflare.com/turnstile/v0/g/313d8a27/api.js?onload=URXdVe4&render=explicit

https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/g/orchestrate/chl_api/v1?ray=7fb72b3cba9bc4a4
https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/g/orchestrate/chl_api/v1?ray=7fb72b3cba9bc4a4


## HAProxy-Protection

https://gitgud.io/fatchan/haproxy-protection/-/blob/a6f3613b6a4e41860f4916de508de80e47e2ee98/src/js/worker.js
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,12 @@ the other side.
With Berghain in charge, you can be confident that your backend is reserved for the true VIPs of the internet, keeping
out any uninvited guests. It's like the bouncer of the web world, ensuring that your resources are reserved for the
browsers that really know how to dance!

## Supported CAPTCHAs

- None (Simple JS execute)
- POW
- Simple Captcha (Including Sound)
- [hCaptcha](https://www.hcaptcha.com/)
- [reCatpcha](https://developers.google.com/recaptcha?hl=de)
- [Turnstile](https://developers.cloudflare.com/turnstile/)
30 changes: 29 additions & 1 deletion berghain.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package berghain

import (
"crypto/hmac"
"crypto/sha256"
"hash"
"sync"
"time"
)

Expand All @@ -10,8 +14,32 @@ type LevelConfig struct {
}

type Berghain struct {
Secret []byte
Levels []*LevelConfig

secret []byte
hmac sync.Pool
}

var hashAlgo = sha256.New

func NewBerghain(secret []byte) *Berghain {
return &Berghain{
secret: secret,
hmac: sync.Pool{
New: func() any {
return NewZeroHasher(hmac.New(hashAlgo, secret))
},
},
}
}

func (b *Berghain) acquireHMAC() hash.Hash {
return b.hmac.Get().(hash.Hash)
}

func (b *Berghain) releaseHMAC(h hash.Hash) {
h.Reset()
b.hmac.Put(h)
}

func (b *Berghain) LevelConfig(level uint8) *LevelConfig {
Expand Down
47 changes: 47 additions & 0 deletions berghain_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package berghain

import (
"crypto/rand"
"net/netip"
"testing"
"time"
)

func generateSecret(tb testing.TB) []byte {
tb.Helper()
b := make([]byte, 32)
_, err := rand.Read(b)
if err != nil {
tb.Fatal(err)
}
return b
}

func TestBerghain(t *testing.T) {
bh := NewBerghain(generateSecret(t))
bh.Levels = []*LevelConfig{
{
Duration: time.Minute,
Type: ValidationTypeNone,
},
}

req := AcquireValidatorRequest()
req.Identifier = &RequestIdentifier{
SrcAddr: netip.MustParseAddr("1.2.3.4"),
Host: []byte("example.com"),
Level: 1,
}
req.Method = "GET"

resp := AcquireValidatorResponse()
err := bh.LevelConfig(req.Identifier.Level).Type.RunValidator(bh, req, resp)
if err != nil {
t.Errorf("validator failed: %v", err)
}

err = bh.IsValidCookie(*req.Identifier, resp.Token.ReadBytes())
if err != nil {
t.Errorf("invalid cookie: %v", err)
}
}
12 changes: 3 additions & 9 deletions cmd/spop/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,8 @@ type Config struct {

type Secret []byte

func (s *Secret) MarshalYAML() (interface{}, error) {
return base64.StdEncoding.EncodeToString(*s), nil
}

func (s *Secret) UnmarshalYAML(node *yaml.Node) error {
value := node.Value
ba, err := base64.StdEncoding.DecodeString(value)
ba, err := base64.StdEncoding.DecodeString(node.Value)
if err != nil {
return err
}
Expand All @@ -36,12 +31,11 @@ func (s *Secret) UnmarshalYAML(node *yaml.Node) error {
type FrontendConfig []LevelConfig

func (fc FrontendConfig) AsBerghain(s []byte) *berghain.Berghain {
var b berghain.Berghain
b.Secret = s
b := berghain.NewBerghain(s)
for _, c := range fc {
b.Levels = append(b.Levels, c.AsLevelConfig())
}
return &b
return b
}

type LevelConfig struct {
Expand Down
6 changes: 3 additions & 3 deletions cmd/spop/config.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
secret: JMal0XJRROOMsMdPqggG2tR56CTkpgN3r47GgUN/WSQ=

default:
- duration: 30s
- duration: 24h
type: none
- duration: 20s
- duration: 1h
type: pow
- duration: 10s
- duration: 60s
type: pow

frontend:
Expand Down
5 changes: 2 additions & 3 deletions cmd/spop/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package main

import (
"context"
"errors"
"fmt"
"log"
"net/http"
Expand Down Expand Up @@ -84,7 +83,7 @@ func (f *frontend) HandleSPOEValidate(_ context.Context, w *encoding.ActionWrite

readExpectedKVEntry(m, k, "cookie")
err := f.bh.IsValidCookie(ri, k.ValueBytes())
if err != nil && !errors.Is(err, berghain.ErrInvalidCookieLength) {
if err != nil && debug {
log.Println(fmt.Sprintf("IsValidCookie: %v", err))
}
isValidCookie := err == nil
Expand Down Expand Up @@ -152,7 +151,7 @@ func (f *frontend) HandleSPOEChallenge(_ context.Context, w *encoding.ActionWrit
panic(fmt.Errorf("validator failed: %v", err))
}

_ = w.SetStringBytes(encoding.VarScopeTransaction, "response", resp.Body)
_ = w.SetStringBytes(encoding.VarScopeTransaction, "response", resp.Body.ReadBytes())
if resp.Token.Len() > 0 {
_ = w.SetStringBytes(encoding.VarScopeTransaction, "token", resp.Token.ReadBytes())
}
Expand Down
7 changes: 6 additions & 1 deletion cmd/spop/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,19 @@ import (
)

var configPath string
var debug bool

func main() {
flag.StringVar(&configPath, "config", "config.yaml", "Config file to load")
flag.BoolVar(&debug, "debug", false, "Enable debug mode")
flag.Parse()

log.SetFlags(log.LstdFlags | log.Lshortfile)

go http.ListenAndServe(":9001", nil)
// In debug mode start a http server to serve the default pprof handlers.
if debug {
go http.ListenAndServe(":9001", nil)
}

c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ require (
gopkg.in/yaml.v3 v3.0.1
)

require github.com/adrianbrad/queue v1.2.1 // indirect
require (
github.com/adrianbrad/queue v1.2.1 // indirect
)
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
github.com/adrianbrad/queue v1.2.1 h1:CEVsjFQyuR0s5Hty/HJGWBZHsJ3KMmii0kEgLeam/mk=
github.com/adrianbrad/queue v1.2.1/go.mod h1:wYiPC/3MPbyT45QHLrPR4zcqJWPePubM1oEP/xTwhUs=
github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU=
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
43 changes: 43 additions & 0 deletions hasher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package berghain

import "hash"

// zeroHasher provides a wrapper to create zero allocation hashes.
type zeroHasher struct {
h hash.Hash
buf []byte
}

func NewZeroHasher(h hash.Hash) hash.Hash {
return &zeroHasher{
h: h,
buf: make([]byte, 0, h.Size()),
}
}

func (zh *zeroHasher) Sum(b []byte) []byte {
if b != nil {
panic("zeroHasher does not support any parameter for Sum()")
}
if len(zh.buf) != 0 {
panic("invalid buffer state")
}
return zh.h.Sum(zh.buf)
}

func (zh *zeroHasher) Size() int {
return zh.h.Size()
}

func (zh *zeroHasher) BlockSize() int {
return zh.h.BlockSize()
}

func (zh *zeroHasher) Write(p []byte) (int, error) {
return zh.h.Write(p)
}

func (zh *zeroHasher) Reset() {
zh.buf = zh.buf[:0]
zh.h.Reset()
}
Loading

0 comments on commit 3c342ce

Please sign in to comment.