Don't overwrite existing CheckRedirect

This commit is contained in:
y a t s
2026-02-14 11:51:36 -05:00
parent 8f868a3930
commit 66e6f74a4b
5 changed files with 48 additions and 68 deletions

View File

@@ -6,7 +6,7 @@ For technical details, you can try asking Josh (not me) or reverse engineer the
<hr> <hr>
Donations are always appreciated but never expected nor required: I do this shit for free, sometimes to my own detriment, for no good reason. Consider donating if you appreciate this monumental waste of my time.
XMR: `8BjCARiV2uB2gZTbbiMUetfRxcAYZgVM5fXxjEbpmb2nAu8ND1grazZ1EhMGdRqVerAtvEJeiy7SzA3SLXpg2CtRDtCAFfn` XMR: `8BjCARiV2uB2gZTbbiMUetfRxcAYZgVM5fXxjEbpmb2nAu8ND1grazZ1EhMGdRqVerAtvEJeiy7SzA3SLXpg2CtRDtCAFfn`

View File

@@ -30,8 +30,6 @@ type Solution struct {
Nonce uint32 // Solution nonce. This is the "answer" to the problem. Nonce uint32 // Solution nonce. This is the "answer" to the problem.
Redirect string // Relative path to redirect to after Solution is accepted. Redirect string // Relative path to redirect to after Solution is accepted.
Steps int8 // Steps, as described in Challenge.
// TODO: Maybe make the redirect shit auto, idk. // TODO: Maybe make the redirect shit auto, idk.
host *url.URL host *url.URL
@@ -102,7 +100,6 @@ func genHashes(ctx context.Context, c Challenge) <-chan Solution {
Salt: c.Salt, Salt: c.Salt,
Nonce: nonce, Nonce: nonce,
Redirect: "/", // Use sensible default for placeholder, for now. Redirect: "/", // Use sensible default for placeholder, for now.
Steps: c.Steps - 1,
} }
// Ensure we don't hang if out channel is full on ctx close. // Ensure we don't hang if out channel is full on ctx close.
select { select {

View File

@@ -4,9 +4,11 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"io"
"log" "log"
"net" "net"
"net/http" "net/http"
"net/http/cookiejar"
"strings" "strings"
"testing" "testing"
@@ -31,26 +33,33 @@ func solveTest(ctx context.Context, hc http.Client, host string) error {
connType = "tor" connType = "tor"
} }
log.Printf("Fetching new %s challenge...", connType) steps := int8(1)
c, err := NewChallenge(ctx, hc, host)
if err != nil {
return err
}
log.Printf("Challenge: %s, Difficulty: %d, Steps: %d\n", c.Salt, c.Diff, c.Steps)
s, err := Solve(ctx, c) for steps > 0 {
if err != nil { log.Printf("Fetching new %s challenge...", connType)
return err c, err := NewChallenge(ctx, hc, host)
} if err != nil {
log.Printf("Solution hash: %x, nonce: %d\n", s.Hash, s.Nonce) return err
}
log.Printf("Challenge: %s, Difficulty: %d, Steps: %d\n", c.Salt, c.Diff, c.Steps)
steps = c.Steps
resp, err := Submit(ctx, hc, s, "") s, err := Solve(ctx, c)
if err != nil { if err != nil {
return err return err
} }
defer resp.Body.Close() log.Printf("Solution hash: %x, nonce: %d\n", s.Hash, s.Nonce)
log.Printf("Response: %s\n\n", resp.Header.Get("Set-Cookie")) resp, err := Submit(ctx, hc, s, "")
if err != nil {
return err
}
b, err := io.ReadAll(resp.Body)
log.Printf("Response: %s\n\n", b[:60])
resp.Body.Close()
}
return nil return nil
} }
@@ -67,9 +76,16 @@ func newProxyTransport() *http.Transport {
func TestSubmit(t *testing.T) { func TestSubmit(t *testing.T) {
ctx := t.Context() ctx := t.Context()
err := solveTest(ctx, http.Client{}, _TEST_HOST) jar, err := cookiejar.New(nil)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return
}
err = solveTest(ctx, http.Client{Jar: jar}, _TEST_HOST)
if err != nil {
t.Error(err)
return
} }
var dnsErr *net.DNSError var dnsErr *net.DNSError

4
go.mod
View File

@@ -1,6 +1,6 @@
module github.com/y-a-t-s/cerberus module gitgud.io/yats/cerberus
go 1.25.5 go 1.25.6
require ( require (
github.com/minio/sha256-simd v1.0.1 github.com/minio/sha256-simd v1.0.1

55
http.go
View File

@@ -34,14 +34,16 @@ func NewChallenge(ctx context.Context, hc http.Client, host string) (Challenge,
return Challenge{}, err return Challenge{}, err
} }
// Update host url in case we get redirected across domains. if hc.CheckRedirect == nil {
hc.CheckRedirect = func(req *http.Request, via []*http.Request) error { // Update host url in case we get redirected across domains.
rh := req.URL.Host hc.CheckRedirect = func(req *http.Request, via []*http.Request) error {
if rh != u.Host && strings.HasPrefix(rh, "kiwifarms") { rh := req.URL.Host
u.Host = rh if rh != u.Host && strings.HasPrefix(rh, "kiwifarms") {
} u.Host = rh
}
return nil return nil
}
} }
req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil) req, err := http.NewRequestWithContext(ctx, "GET", u.String(), nil)
@@ -95,31 +97,7 @@ func Submit(ctx context.Context, hc http.Client, s Solution, redirect string) (*
s.Redirect = redirect s.Redirect = redirect
} }
resp, err := postSolution(ctx, hc, s) return postSolution(ctx, hc, s)
if err != nil {
return nil, err
}
// This feels gross, but it works.
for s.Steps > 0 {
resp.Body.Close()
c, err := NewChallenge(ctx, hc, s.host.String())
if err != nil {
return nil, err
}
s, err = Solve(ctx, c)
if err != nil {
return nil, err
}
resp, err = Submit(ctx, hc, s, redirect)
if err != nil {
return nil, err
}
}
return resp, nil
} }
func parseHost(addr string) (*url.URL, error) { func parseHost(addr string) (*url.URL, error) {
@@ -144,18 +122,7 @@ func postSolution(ctx context.Context, hc http.Client, s Solution) (*http.Respon
return nil, err return nil, err
} }
resp, err := hc.Do(req) return hc.Do(req)
if err != nil {
return nil, err
}
// TODO: Additionally verify failure from response JSON. Maybe include resp body in err type.
// Rejected solution response: status=400 body={"success":false,"reason":"invalid_solution","action":"retry"}
if resp.StatusCode == 400 {
return resp, &ErrInvalidSolution{s}
}
return resp, nil
} }
func parseTags(r io.Reader) (Challenge, error) { func parseTags(r io.Reader) (Challenge, error) {