From 0c11a4d7662028dcff76739f68de1a7fd3450056 Mon Sep 17 00:00:00 2001 From: Travis Fischer Date: Sun, 15 Jan 2023 03:53:31 -0600 Subject: [PATCH] feat: improve support for proxy auth --- src/chatgpt-api-browser.ts | 44 ++++++++++++-------------------- src/openai-auth.ts | 52 +++++++++++++++++++++++++++++++------- 2 files changed, 59 insertions(+), 37 deletions(-) diff --git a/src/chatgpt-api-browser.ts b/src/chatgpt-api-browser.ts index 64ea367..2722f23 100644 --- a/src/chatgpt-api-browser.ts +++ b/src/chatgpt-api-browser.ts @@ -4,7 +4,7 @@ import { v4 as uuidv4 } from 'uuid' import * as types from './types' import { AChatGPTAPI } from './abstract-chatgpt-api' -import { getBrowser, getOpenAIAuth } from './openai-auth' +import { getBrowser, getOpenAIAuth, getPage } from './openai-auth' import { browserPostEventStream, isRelevantRequest, @@ -129,25 +129,10 @@ export class ChatGPTAPIBrowser extends AChatGPTAPI { proxyServer: this._proxyServer, minimize: this._minimize }) - this._page = - (await this._browser.pages())[0] || (await this._browser.newPage()) - if (this._proxyServer && this._proxyServer.includes('@')) { - try { - const proxyUsername = this._proxyServer.split('@')[0].split(':')[0] - const proxyPassword = this._proxyServer.split('@')[0].split(':')[1] - - await this._page.authenticate({ - username: proxyUsername, - password: proxyPassword - }) - } catch (err) { - console.error( - `Proxy "${this._proxyServer}" throws an error at authenticating`, - err.toString() - ) - } - } + this._page = await getPage(this._browser, { + proxyServer: this._proxyServer + }) // bypass annoying popup modals this._page.evaluateOnNewDocument(() => { @@ -238,6 +223,12 @@ export class ChatGPTAPIBrowser extends AChatGPTAPI { } while (true) if (!(await this.getIsAuthenticated())) { + if (!this._accessToken) { + console.warn('no access token') + } else { + console.warn('failed to find prompt textarea') + } + throw new types.ChatGPTError('Failed to authenticate session') } @@ -313,22 +304,19 @@ export class ChatGPTAPIBrowser extends AChatGPTAPI { } }) } + const detail = body?.detail || '' if (url.endsWith('/conversation')) { - if (status === 403) { - console.log(`ChatGPT "${this._email}" error 403...`) + if (status >= 400) { + console.warn(`ChatGPT "${this._email}" error ${status};`, detail) // this will be handled in the sendMessage error handler // await this.refreshSession() } } else if (url.endsWith('api/auth/session')) { - if (status === 401) { - console.log(`ChatGPT "${this._email}" error 401...`) + if (status >= 400) { + console.warn(`ChatGPT "${this._email}" error ${status};`, detail) // this will be handled in the sendMessage error handler // await this.resetSession() - } else if (status === 403) { - console.log(`ChatGPT "${this._email}" error 403...`) - // this will be handled in the sendMessage error handler - // await this.refreshSession() } else { const session: types.SessionResult = body @@ -581,7 +569,7 @@ export class ChatGPTAPIBrowser extends AChatGPTAPI { // response handler or if the user has closed the page manually. if (++numTries >= 2) { - const error = new types.ChatGPTError(err.toString()) + const error = new types.ChatGPTError(err.toString(), { cause: err }) error.statusCode = err.response?.statusCode error.statusText = err.response?.statusText cleanup() diff --git a/src/openai-auth.ts b/src/openai-auth.ts index dd75776..e977a65 100644 --- a/src/openai-auth.ts +++ b/src/openai-auth.ts @@ -30,7 +30,6 @@ export type OpenAIAuth = { userAgent: string clearanceToken: string sessionToken: string - cookies?: Record } /** @@ -91,7 +90,7 @@ export async function getOpenAIAuth({ const userAgent = await browser.userAgent() if (!page) { - page = (await browser.pages())[0] || (await browser.newPage()) + page = await getPage(browser, { proxyServer }) page.setDefaultTimeout(timeoutMs) if (minimize) { @@ -240,8 +239,7 @@ export async function getOpenAIAuth({ const authInfo: OpenAIAuth = { userAgent, clearanceToken: cookies['cf_clearance']?.value, - sessionToken: cookies['__Secure-next-auth.session-token']?.value, - cookies + sessionToken: cookies['__Secure-next-auth.session-token']?.value } return authInfo @@ -261,6 +259,38 @@ export async function getOpenAIAuth({ } } +export async function getPage( + browser: Browser, + opts: { + proxyServer?: string + } +) { + const { proxyServer = process.env.PROXY_SERVER } = opts + const page = (await browser.pages())[0] || (await browser.newPage()) + + if (proxyServer && proxyServer.includes('@')) { + const proxyAuth = proxyServer.split('@')[0].split(':') + const proxyUsername = proxyAuth[0] + const proxyPassword = proxyAuth[1] + + try { + await page.authenticate({ + username: proxyUsername, + password: proxyPassword + }) + } catch (err) { + console.error( + `ChatGPT "${this._email}" error authenticating proxy "${this._proxyServer}"`, + err.toString() + ) + + throw err + } + } + + return page +} + /** * Launches a non-puppeteer instance of Chrome. Note that in my testing, I wasn't * able to use the built-in `puppeteer` version of Chromium because Cloudflare @@ -359,7 +389,7 @@ export async function getBrowser( }) if (process.env.PROXY_VALIDATE_IP) { - const page = (await browser.pages())[0] || (await browser.newPage()) + const page = await getPage(browser, { proxyServer }) if (minimize) { await minimizePage(page) } @@ -378,7 +408,9 @@ export async function getBrowser( ip = res?.ip } catch (err) { - throw new Error(`Proxy IP validation failed: ${err.toString()}`) + throw new Error(`Proxy IP validation failed: ${err.toString()}`, { + cause: err + }) } if (!ip || ip !== process.env.PROXY_VALIDATE_IP) { @@ -392,7 +424,8 @@ export async function getBrowser( nopechaKey, minimize, debug, - timeoutMs + timeoutMs, + proxyServer }) return browser @@ -401,16 +434,17 @@ export async function getBrowser( export async function initializeNopechaExtension( browser: Browser, opts: { + proxyServer?: string nopechaKey?: string minimize?: boolean debug?: boolean timeoutMs?: number } ) { - const { minimize = false, debug = false, nopechaKey } = opts + const { minimize = false, debug = false, nopechaKey, proxyServer } = opts if (hasNopechaExtension) { - const page = (await browser.pages())[0] || (await browser.newPage()) + const page = await getPage(browser, { proxyServer }) if (minimize) { await minimizePage(page) }