Skip to content

Commit

Permalink
refactor and working
Browse files Browse the repository at this point in the history
  • Loading branch information
Antonio committed Apr 29, 2023
1 parent a33f0a7 commit 76240bf
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 241 deletions.
226 changes: 144 additions & 82 deletions auth/OpenAiAuth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,15 @@ package auth

import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/url"
"regexp"
"strings"

"crypto/rand"

http "github.com/bogdanfinn/fhttp"
tls_client "github.com/bogdanfinn/tls-client"
pkce "github.com/nirasan/go-oauth-pkce-code-verifier"
)

type Error struct {
Expand All @@ -33,56 +30,20 @@ func NewError(location string, statusCode int, details string, err error) *Error
}

type Authenticator struct {
EmailAddress string
Password string
Proxy string
Session tls_client.HttpClient
AccessToken string
UserAgent string
State string
URL string
Verifier_code string
Verifier *pkce.CodeVerifier
Verifier_challenge string
AuthDetails AuthDetails
}

type AuthDetails struct {
ClientID string `json:"client_id"`
Scope string `json:"scope"`
ResponseType string `json:"response_type"`
RedirectURL string `json:"redirect_url"`
Audience string `json:"audience"`
Prompt string `json:"prompt"`
State string `json:"state"`
CodeChallenge string `json:"code_challenge"`
CodeChallengeMethod string `json:"code_challenge_method"`
}

func NewAuthDetails(challenge string) AuthDetails {
// Generate state (secrets.token_urlsafe(32))
b := make([]byte, 32)
rand.Read(b)
state := base64.URLEncoding.EncodeToString(b)
return AuthDetails{
ClientID: "TdJIcbe16WoTHtN95nyywh5E4yOo6ItG",
Scope: "openid email profile offline_access model.request model.read organization.read",
ResponseType: "code",
RedirectURL: "https://chat.openai.com/api/auth/callback/auth0",
Audience: "https://api.openai.com/v1",
Prompt: "login",
State: state,
CodeChallenge: challenge,
CodeChallengeMethod: "S256",
}
EmailAddress string
Password string
Proxy string
Session tls_client.HttpClient
AccessToken string
UserAgent string
}

func NewAuthenticator(emailAddress, password, proxy string) *Authenticator {
auth := &Authenticator{
EmailAddress: emailAddress,
Password: password,
Proxy: proxy,
UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36",
UserAgent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36",
}
jar := tls_client.NewCookieJar()
options := []tls_client.HttpClientOption{
Expand All @@ -94,14 +55,6 @@ func NewAuthenticator(emailAddress, password, proxy string) *Authenticator {
tls_client.WithProxyUrl(proxy),
}
auth.Session, _ = tls_client.NewHttpClient(tls_client.NewNoopLogger(), options...)

// PKCE
auth.Verifier, _ = pkce.CreateCodeVerifier()
auth.Verifier_code = auth.Verifier.String()
auth.Verifier_challenge = auth.Verifier.CodeChallengeS256()

auth.AuthDetails = NewAuthDetails(auth.Verifier_challenge)

return auth
}

Expand All @@ -110,14 +63,55 @@ func (auth *Authenticator) URLEncode(str string) string {
}

func (auth *Authenticator) Begin() Error {
// Just realized that the client id is hardcoded in the JS file

return auth.partOne()
url := "https://chat.openai.com/api/auth/csrf"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return *NewError("begin", 0, "", err)
}

req.Header.Set("Host", "chat.openai.com")
req.Header.Set("Accept", "*/*")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("User-Agent", auth.UserAgent)
req.Header.Set("Accept-Language", "en-GB,en-US;q=0.9,en;q=0.8")
req.Header.Set("Referer", "https://chat.openai.com/auth/login")
req.Header.Set("Accept-Encoding", "gzip, deflate, br")

resp, err := auth.Session.Do(req)
if err != nil {
return *NewError("begin", 0, "", err)
}
defer resp.Body.Close()

body, err := io.ReadAll(resp.Body)
if err != nil {
return *NewError("begin", 0, "", err)
}

if resp.StatusCode == 200 && strings.Contains(resp.Header.Get("Content-Type"), "json") {

var csrfTokenResponse struct {
CsrfToken string `json:"csrfToken"`
}
err = json.Unmarshal(body, &csrfTokenResponse)
if err != nil {
return *NewError("begin", 0, "", err)
}

csrfToken := csrfTokenResponse.CsrfToken
return auth.partOne(csrfToken)
} else {
err := NewError("begin", resp.StatusCode, string(body), fmt.Errorf("error: Check details"))
return *err
}
}
func (auth *Authenticator) partOne() Error {
func (auth *Authenticator) partOne(token string) Error {

auth_url := "https://auth0.openai.com/authorize"
url := "https://chat.openai.com/api/auth/signin/auth0?prompt=login"
payload := fmt.Sprintf("callbackUrl=%%2F&csrfToken=%s&json=true", token)
headers := map[string]string{
"Host": "chat.openai.com",
"User-Agent": auth.UserAgent,
"Content-Type": "application/x-www-form-urlencoded",
"Accept": "*/*",
Expand All @@ -130,21 +124,8 @@ func (auth *Authenticator) partOne() Error {
"Referer": "https://chat.openai.com/auth/login",
"Accept-Encoding": "gzip, deflate",
}
// Construct payload
// URL encoded form - client_id=TdJIcbe16WoTHtN95nyywh5E4yOo6ItG&scope=openid email profile offline_access model.request model.read organization.read&response_type=code&redirect_uri=https%3A%2F%2Fchat.openai.com%2Fapi%2Fauth%2Fcallback%2Fauth0&audience=https%3A%2F%2Fapi.openai.com%2Fv1&prompt=login&state=iUxZBeFvcCUrVITrlwKwkBuW3CZ9qn_C3mR5ZZeSDvQ&code_challenge=SNBtqj_N1ssVSAAaE12hrOAR2bU5GHMMQNJYpkUg5fE&code_challenge_method=S256
payload := url.Values{
"client_id": {auth.AuthDetails.ClientID},
"scope": {auth.AuthDetails.Scope},
"response_type": {auth.AuthDetails.ResponseType},
"redirect_uri": {auth.AuthDetails.RedirectURL},
"audience": {auth.AuthDetails.Audience},
"prompt": {auth.AuthDetails.Prompt},
"state": {auth.AuthDetails.State},
"code_challenge": {auth.AuthDetails.CodeChallenge},
"code_challenge_method": {auth.AuthDetails.CodeChallengeMethod},
}
auth_url = auth_url + "?" + payload.Encode()
req, err := http.NewRequest("GET", auth_url, nil)

req, err := http.NewRequest("POST", url, strings.NewReader(payload))
if err != nil {
return *NewError("part_one", 0, "", err)
}
Expand All @@ -163,8 +144,23 @@ func (auth *Authenticator) partOne() Error {
return *NewError("part_one", 0, "", err)
}

if resp.StatusCode == 302 {
return auth.partTwo("https://auth0.openai.com" + resp.Header.Get("Location"))
if resp.StatusCode == 200 && strings.Contains(resp.Header.Get("Content-Type"), "json") {

var urlResponse struct {
URL string `json:"url"`
}
err = json.Unmarshal(body, &urlResponse)
if err != nil {
return *NewError("part_one", 0, "", err)
}

url := urlResponse.URL
if url == "https://chat.openai.com/api/auth/error?error=OAuthSignin" || strings.Contains(url, "error") {
err := NewError("part_one", resp.StatusCode, "You have been rate limited. Please try again later.", fmt.Errorf("error: Check details"))
return *err
}

return auth.partTwo(url)
} else {
err := NewError("part_one", resp.StatusCode, string(body), fmt.Errorf("error: Check details"))
return *err
Expand Down Expand Up @@ -378,18 +374,84 @@ func (auth *Authenticator) partSix(oldState string, redirectURL string) Error {
defer resp.Body.Close()

if resp.StatusCode == 302 {
auth.URL = resp.Header.Get("Location")
return Error{}
redirectURL := resp.Header.Get("Location")
return auth.partSeven(redirectURL, url)
} else {
err := NewError("__part_six", resp.StatusCode, resp.Status, fmt.Errorf("error: Check details"))
return *err
}

}
func (auth *Authenticator) partSeven(redirectURL string, previousURL string) Error {

url := redirectURL

headers := map[string]string{
"Host": "chat.openai.com",
"Accept": "application/json",
"Connection": "keep-alive",
"User-Agent": auth.UserAgent,
"Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8",
"Referer": previousURL,
}

req, err := http.NewRequest("GET", url, nil)
if err != nil {
return *NewError("part_seven", 0, "", err)
}

for k, v := range headers {
req.Header.Set(k, v)
}

resp, err := auth.Session.Do(req)
if err != nil {
return *NewError("part_seven", 0, "", err)
}
defer resp.Body.Close()

if resp.StatusCode == 200 || resp.StatusCode == 302 {
return Error{}
} else {
body, err := io.ReadAll(resp.Body)
if err != nil {
return *NewError("part_seven", 0, "", err)
}
return *NewError("__part_seven", resp.StatusCode, string(body), fmt.Errorf("error: Check details"))
}
}
func (auth *Authenticator) GetAccessToken() (string, Error) {
// Print all cookies
for _, cookie := range auth.Session.GetCookies(&url.URL{Host: "openai.com"}) {
fmt.Printf(" %s: %s\n", cookie.Name, cookie.Value)
url := "https://chat.openai.com/api/auth/session"

req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", *NewError("get_access_token", 0, "", err)
}
// Set user agent
req.Header.Set("User-Agent", auth.UserAgent)

resp, err := auth.Session.Do(req)
if err != nil {
return "", *NewError("get_access_token", 0, "", err)
}
defer resp.Body.Close()

if resp.StatusCode == 200 {
var result map[string]interface{}
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return "", *NewError("get_access_token", 0, "", err)
}
if result["accessToken"] == nil {
return "", *NewError("get_access_token", 0, "", fmt.Errorf("error: accessToken is nil"))
}

auth.AccessToken = result["accessToken"].(string)
return auth.AccessToken, Error{}
} else {
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", *NewError("get_access_token", 0, "", err)
}
return "", *NewError("get_access_token", resp.StatusCode, string(body), fmt.Errorf("error: Check details"))
}
return auth.URL, Error{}
}
3 changes: 0 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ module github.com/acheong08/OpenAIAuth
go 1.20

require (
github.com/PuerkitoBio/goquery v1.8.1
github.com/bogdanfinn/fhttp v0.5.19
github.com/bogdanfinn/tls-client v1.3.8
github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c
)

require (
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/bogdanfinn/utls v1.5.15 // indirect
github.com/klauspost/compress v1.15.12 // indirect
github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 // indirect
Expand Down
33 changes: 0 additions & 33 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM=
github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ=
github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/bogdanfinn/fhttp v0.5.19 h1:/FKuFAtSw3+iZyNkaWXRDSVqMmOvThDjXanlG6/DXos=
github.com/bogdanfinn/fhttp v0.5.19/go.mod h1:emv9FntlC5eAyrIUhCi6oC5NLoBC9d4AJLCq2T1bobY=
github.com/bogdanfinn/tls-client v1.3.8 h1:HIucpArqyqOUIN/7MDJJA9Ngt+lKHUyoQ2y2CUjIDNM=
Expand All @@ -12,42 +8,13 @@ github.com/bogdanfinn/utls v1.5.15 h1:XUUMJZh2AptaouuwUrc/RQOYgyV89rstC5Nj3FSP43
github.com/bogdanfinn/utls v1.5.15/go.mod h1:mHeRCi69cUiEyVBkKONB1cAbLjRcZnlJbGzttmiuK4o=
github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=
github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c h1:4RYnE0ISVwRxm9Dfo7utw1dh0kdRDEmVYq2MFVLy5zI=
github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20220510032225-4f9f17eaec4c/go.mod h1:DvuJJ/w1Y59rG8UTDxsMk5U+UJXJwuvUgbiJSm9yhX8=
github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5 h1:YqAladjX7xpA6BM04leXMWAEjS0mTZ5kUU9KRBriQJc=
github.com/tam7t/hpkp v0.0.0-20160821193359-2b70b4024ed5/go.mod h1:2JjD2zLQYH5HO74y5+aE3remJQvl6q4Sn6aWA2wD1Ng=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Loading

0 comments on commit 76240bf

Please sign in to comment.