mirror of
https://github.com/verssache/chatgpt-creator.git
synced 2026-05-16 21:59:33 +00:00
feat: add sentinel token generation for account creation
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
http "github.com/bogdanfinn/fhttp"
|
||||
"github.com/verssache/chatgpt-creator/internal/email"
|
||||
"github.com/verssache/chatgpt-creator/internal/sentinel"
|
||||
"github.com/verssache/chatgpt-creator/internal/util"
|
||||
)
|
||||
|
||||
@@ -228,11 +229,17 @@ func (c *Client) createAccount(name, birthdate string) (int, map[string]interfac
|
||||
}
|
||||
jsonPayload, _ := json.Marshal(payload)
|
||||
|
||||
sentinelCreateAccount, err := sentinel.BuildSentinelToken(c.session, c.deviceID, "create_account", c.ua, c.secChUA, c.impersonate)
|
||||
if err != nil {
|
||||
return 0, nil, fmt.Errorf("failed to get sentinel auth: %v", err)
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest("POST", createURL, strings.NewReader(string(jsonPayload)))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("Referer", authURL+"/about-you")
|
||||
req.Header.Set("Origin", authURL)
|
||||
req.Header.Set("openai-sentinel-token", sentinelCreateAccount)
|
||||
|
||||
traceHeaders := util.MakeTraceHeaders()
|
||||
for k, v := range traceHeaders {
|
||||
|
||||
107
internal/sentinel/challenge.go
Normal file
107
internal/sentinel/challenge.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package sentinel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
fhttp "github.com/bogdanfinn/fhttp"
|
||||
tls_client "github.com/bogdanfinn/tls-client"
|
||||
)
|
||||
|
||||
func FetchSentinelChallenge(session tls_client.HttpClient, deviceID, flow, ua, secChUA, impersonate string) (map[string]any, error) {
|
||||
generator := NewGenerator(deviceID, ua)
|
||||
reqBody := map[string]any{
|
||||
"p": generator.GenerateRequirementsToken(),
|
||||
"id": deviceID,
|
||||
"flow": flow,
|
||||
}
|
||||
|
||||
bodyBytes, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := fhttp.NewRequest("POST", "https://sentinel.openai.com/backend-api/sentinel/req", bytes.NewBuffer(bodyBytes))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "text/plain;charset=UTF-8")
|
||||
req.Header.Set("Referer", "https://sentinel.openai.com/sentinel/20260124ceb8/frame.html")
|
||||
req.Header.Set("Origin", "https://sentinel.openai.com")
|
||||
req.Header.Set("User-Agent", ua)
|
||||
if secChUA != "" {
|
||||
req.Header.Set("sec-ch-ua", secChUA)
|
||||
} else {
|
||||
req.Header.Set("sec-ch-ua", "\"Not:A-Brand\";v=\"99\", \"Google Chrome\";v=\"145\", \"Chromium\";v=\"145\"")
|
||||
}
|
||||
req.Header.Set("sec-ch-ua-mobile", "?0")
|
||||
req.Header.Set("sec-ch-ua-platform", "\"Windows\"")
|
||||
req.Header.Set("oai-device-id", deviceID)
|
||||
req.Header.Set("oai-language", "en-US")
|
||||
|
||||
resp, err := session.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != fhttp.StatusOK {
|
||||
return nil, fmt.Errorf("sentinel challenge request failed with status: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result map[string]any
|
||||
if err := json.Unmarshal(respBody, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func BuildSentinelToken(session tls_client.HttpClient, deviceID, flow, ua, secChUA, impersonate string) (string, error) {
|
||||
challenge, err := FetchSentinelChallenge(session, deviceID, flow, ua, secChUA, impersonate)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cValue, ok := challenge["token"].(string)
|
||||
if !ok || cValue == "" {
|
||||
return "", fmt.Errorf("invalid sentinel challenge token")
|
||||
}
|
||||
|
||||
var pValue string
|
||||
generator := NewGenerator(deviceID, ua)
|
||||
|
||||
powData, _ := challenge["proofofwork"].(map[string]any)
|
||||
required, _ := powData["required"].(bool)
|
||||
seed, _ := powData["seed"].(string)
|
||||
|
||||
if required && seed != "" {
|
||||
difficulty, _ := powData["difficulty"].(string)
|
||||
pValue = generator.GenerateToken(seed, difficulty)
|
||||
} else {
|
||||
pValue = generator.GenerateRequirementsToken()
|
||||
}
|
||||
|
||||
tokenData := map[string]string{
|
||||
"p": pValue,
|
||||
"t": "",
|
||||
"c": cValue,
|
||||
"id": deviceID,
|
||||
"flow": flow,
|
||||
}
|
||||
|
||||
resultBytes, err := json.Marshal(tokenData)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(resultBytes), nil
|
||||
}
|
||||
21
internal/sentinel/fnv.go
Normal file
21
internal/sentinel/fnv.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package sentinel
|
||||
|
||||
import "fmt"
|
||||
|
||||
// fnv1a32 computes a 32-bit FNV-1a hash with avalanche finalizer.
|
||||
// This is a custom implementation independent of hash/fnv, matching
|
||||
// the Python reference implementation exactly.
|
||||
func FNV1a32(text string) string {
|
||||
var h uint32 = 2166136261
|
||||
for _, c := range text {
|
||||
h ^= uint32(c)
|
||||
h *= 16777619
|
||||
}
|
||||
// Avalanche finalizer (murmur3-style)
|
||||
h ^= h >> 16
|
||||
h *= 2246822507
|
||||
h ^= h >> 13
|
||||
h *= 3266489909
|
||||
h ^= h >> 16
|
||||
return fmt.Sprintf("%08x", h)
|
||||
}
|
||||
117
internal/sentinel/generator.go
Normal file
117
internal/sentinel/generator.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package sentinel
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type SentinelTokenGenerator struct {
|
||||
DeviceID string
|
||||
UserAgent string
|
||||
RequirementsSeed string
|
||||
SID string
|
||||
}
|
||||
|
||||
func NewGenerator(deviceID, ua string) *SentinelTokenGenerator {
|
||||
if deviceID == "" {
|
||||
deviceID = uuid.New().String()
|
||||
}
|
||||
if ua == "" {
|
||||
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36"
|
||||
}
|
||||
return &SentinelTokenGenerator{
|
||||
DeviceID: deviceID,
|
||||
UserAgent: ua,
|
||||
RequirementsSeed: fmt.Sprintf("%f", rand.Float64()),
|
||||
SID: uuid.New().String(),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *SentinelTokenGenerator) getConfig() []any {
|
||||
now := time.Now().UTC()
|
||||
nowStr := now.Format("Mon Jan 02 2006 15:04:05 GMT+0000 (Coordinated Universal Time)")
|
||||
perfNow := rand.Float64()*49000 + 1000
|
||||
timeOrigin := float64(now.UnixNano()/1e6) - perfNow
|
||||
|
||||
navProps := []string{
|
||||
"vendorSub", "productSub", "vendor", "maxTouchPoints",
|
||||
"scheduling", "userActivation", "doNotTrack", "geolocation",
|
||||
"connection", "plugins", "mimeTypes", "pdfViewerEnabled",
|
||||
"webkitTemporaryStorage", "webkitPersistentStorage",
|
||||
"hardwareConcurrency", "cookieEnabled", "credentials",
|
||||
"mediaDevices", "permissions", "locks", "ink",
|
||||
}
|
||||
navProp := navProps[rand.Intn(len(navProps))]
|
||||
navVal := fmt.Sprintf("%s-undefined", navProp)
|
||||
|
||||
screenRes := "1920x1080"
|
||||
sdkJS := "https://sentinel.openai.com/sentinel/20260124ceb8/sdk.js"
|
||||
|
||||
return []any{
|
||||
screenRes,
|
||||
nowStr,
|
||||
4294705152,
|
||||
0, // nonce placeholder
|
||||
g.UserAgent,
|
||||
sdkJS,
|
||||
nil,
|
||||
nil,
|
||||
"en-US",
|
||||
"en-US,en",
|
||||
rand.Float64(),
|
||||
navVal,
|
||||
[]string{"location", "implementation", "URL", "documentURI", "compatMode"}[rand.Intn(5)],
|
||||
[]string{"Object", "Function", "Array", "Number", "parseFloat", "undefined"}[rand.Intn(6)],
|
||||
perfNow,
|
||||
g.SID,
|
||||
"",
|
||||
[]int{4, 8, 12, 16}[rand.Intn(4)],
|
||||
timeOrigin,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *SentinelTokenGenerator) base64Encode(data any) string {
|
||||
raw, _ := json.Marshal(data)
|
||||
return base64.StdEncoding.EncodeToString(raw)
|
||||
}
|
||||
|
||||
func (g *SentinelTokenGenerator) GenerateToken(seed string, difficulty string) string {
|
||||
if seed == "" {
|
||||
seed = g.RequirementsSeed
|
||||
}
|
||||
if difficulty == "" {
|
||||
difficulty = "0"
|
||||
}
|
||||
|
||||
startTime := time.Now()
|
||||
config := g.getConfig()
|
||||
|
||||
for i := 0; i < 500000; i++ {
|
||||
config[3] = i
|
||||
elapsed := time.Since(startTime).Milliseconds()
|
||||
config[9] = elapsed
|
||||
|
||||
data := g.base64Encode(config)
|
||||
hashHex := FNV1a32(seed + data)
|
||||
|
||||
if hashHex[:len(difficulty)] <= difficulty {
|
||||
return "gAAAAAB" + data + "~S"
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback error token (simplified)
|
||||
return "gAAAAAB" + "wQ8Lk5FbGpA2NcR9dShT6gYjU7VxZ4D" + g.base64Encode("None")
|
||||
}
|
||||
|
||||
func (g *SentinelTokenGenerator) GenerateRequirementsToken() string {
|
||||
config := g.getConfig()
|
||||
config[3] = 1
|
||||
config[9] = rand.Intn(45) + 5
|
||||
data := g.base64Encode(config)
|
||||
return "gAAAAAC" + data
|
||||
}
|
||||
Reference in New Issue
Block a user