feat: initial commit
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
// Package anubis implements a native Go client for getting past the Anubis
|
||||
// (TecharoHQ) proof-of-work anti-scraper proxy without a headless browser.
|
||||
//
|
||||
// The challenge is embedded in the interstitial HTML as a JSON document inside
|
||||
// a <script id="anubis_challenge"> element. The client must find an integer
|
||||
// nonce such that SHA-256(randomData + nonce) has `difficulty` leading hex-zero
|
||||
// digits, then submit it to the pass-challenge endpoint to obtain a signed-JWT
|
||||
// auth cookie.
|
||||
package anubis
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// sha256Hex returns the hex-encoded SHA-256 of s. This is the answer to a
|
||||
// "preact" Anubis challenge: result = SHA256(randomData).
|
||||
func sha256Hex(s string) string {
|
||||
sum := sha256.Sum256([]byte(s))
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
// Solve performs the Anubis proof-of-work: it searches for the smallest nonce
|
||||
// (starting at 0) such that SHA-256(randomData + nonce) has `difficulty`
|
||||
// leading hex-zero digits. It returns the hex-encoded hash and the nonce.
|
||||
//
|
||||
// The zero check mirrors the Anubis worker: the first floor(difficulty/2)
|
||||
// bytes must be zero and, when difficulty is odd, the high nibble of the next
|
||||
// byte must also be zero.
|
||||
func Solve(randomData string, difficulty int) (hash string, nonce uint64) {
|
||||
prefix := []byte(randomData)
|
||||
zeroBytes := difficulty / 2
|
||||
oddNibble := difficulty%2 != 0
|
||||
|
||||
// Reusable buffer: challenge prefix + decimal nonce, refilled each round.
|
||||
buf := make([]byte, 0, len(prefix)+20)
|
||||
|
||||
for n := uint64(0); ; n++ {
|
||||
buf = append(buf[:0], prefix...)
|
||||
buf = strconv.AppendUint(buf, n, 10)
|
||||
sum := sha256.Sum256(buf)
|
||||
|
||||
if leadingZeros(sum[:], zeroBytes, oddNibble) {
|
||||
return hex.EncodeToString(sum[:]), n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// leadingZeros reports whether sum has the required number of leading hex-zero
|
||||
// digits: zeroBytes fully-zero bytes, plus (when oddNibble) a zero high nibble
|
||||
// in the following byte.
|
||||
func leadingZeros(sum []byte, zeroBytes int, oddNibble bool) bool {
|
||||
for i := range zeroBytes {
|
||||
if sum[i] != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if oddNibble {
|
||||
return sum[zeroBytes]>>4 == 0
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user