feat: improve support for proxy auth

pull/273/head
Travis Fischer 2023-01-15 03:53:31 -06:00
rodzic 1d784766c5
commit 0c11a4d766
2 zmienionych plików z 59 dodań i 37 usunięć

Wyświetl plik

@ -4,7 +4,7 @@ import { v4 as uuidv4 } from 'uuid'
import * as types from './types' import * as types from './types'
import { AChatGPTAPI } from './abstract-chatgpt-api' import { AChatGPTAPI } from './abstract-chatgpt-api'
import { getBrowser, getOpenAIAuth } from './openai-auth' import { getBrowser, getOpenAIAuth, getPage } from './openai-auth'
import { import {
browserPostEventStream, browserPostEventStream,
isRelevantRequest, isRelevantRequest,
@ -129,25 +129,10 @@ export class ChatGPTAPIBrowser extends AChatGPTAPI {
proxyServer: this._proxyServer, proxyServer: this._proxyServer,
minimize: this._minimize minimize: this._minimize
}) })
this._page =
(await this._browser.pages())[0] || (await this._browser.newPage())
if (this._proxyServer && this._proxyServer.includes('@')) { this._page = await getPage(this._browser, {
try { proxyServer: this._proxyServer
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()
)
}
}
// bypass annoying popup modals // bypass annoying popup modals
this._page.evaluateOnNewDocument(() => { this._page.evaluateOnNewDocument(() => {
@ -238,6 +223,12 @@ export class ChatGPTAPIBrowser extends AChatGPTAPI {
} while (true) } while (true)
if (!(await this.getIsAuthenticated())) { 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') 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 (url.endsWith('/conversation')) {
if (status === 403) { if (status >= 400) {
console.log(`ChatGPT "${this._email}" error 403...`) console.warn(`ChatGPT "${this._email}" error ${status};`, detail)
// this will be handled in the sendMessage error handler // this will be handled in the sendMessage error handler
// await this.refreshSession() // await this.refreshSession()
} }
} else if (url.endsWith('api/auth/session')) { } else if (url.endsWith('api/auth/session')) {
if (status === 401) { if (status >= 400) {
console.log(`ChatGPT "${this._email}" error 401...`) console.warn(`ChatGPT "${this._email}" error ${status};`, detail)
// this will be handled in the sendMessage error handler // this will be handled in the sendMessage error handler
// await this.resetSession() // 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 { } else {
const session: types.SessionResult = body 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. // response handler or if the user has closed the page manually.
if (++numTries >= 2) { 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.statusCode = err.response?.statusCode
error.statusText = err.response?.statusText error.statusText = err.response?.statusText
cleanup() cleanup()

Wyświetl plik

@ -30,7 +30,6 @@ export type OpenAIAuth = {
userAgent: string userAgent: string
clearanceToken: string clearanceToken: string
sessionToken: string sessionToken: string
cookies?: Record<string, Protocol.Network.Cookie>
} }
/** /**
@ -91,7 +90,7 @@ export async function getOpenAIAuth({
const userAgent = await browser.userAgent() const userAgent = await browser.userAgent()
if (!page) { if (!page) {
page = (await browser.pages())[0] || (await browser.newPage()) page = await getPage(browser, { proxyServer })
page.setDefaultTimeout(timeoutMs) page.setDefaultTimeout(timeoutMs)
if (minimize) { if (minimize) {
@ -240,8 +239,7 @@ export async function getOpenAIAuth({
const authInfo: OpenAIAuth = { const authInfo: OpenAIAuth = {
userAgent, userAgent,
clearanceToken: cookies['cf_clearance']?.value, clearanceToken: cookies['cf_clearance']?.value,
sessionToken: cookies['__Secure-next-auth.session-token']?.value, sessionToken: cookies['__Secure-next-auth.session-token']?.value
cookies
} }
return authInfo 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 * 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 * 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) { if (process.env.PROXY_VALIDATE_IP) {
const page = (await browser.pages())[0] || (await browser.newPage()) const page = await getPage(browser, { proxyServer })
if (minimize) { if (minimize) {
await minimizePage(page) await minimizePage(page)
} }
@ -378,7 +408,9 @@ export async function getBrowser(
ip = res?.ip ip = res?.ip
} catch (err) { } 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) { if (!ip || ip !== process.env.PROXY_VALIDATE_IP) {
@ -392,7 +424,8 @@ export async function getBrowser(
nopechaKey, nopechaKey,
minimize, minimize,
debug, debug,
timeoutMs timeoutMs,
proxyServer
}) })
return browser return browser
@ -401,16 +434,17 @@ export async function getBrowser(
export async function initializeNopechaExtension( export async function initializeNopechaExtension(
browser: Browser, browser: Browser,
opts: { opts: {
proxyServer?: string
nopechaKey?: string nopechaKey?: string
minimize?: boolean minimize?: boolean
debug?: boolean debug?: boolean
timeoutMs?: number timeoutMs?: number
} }
) { ) {
const { minimize = false, debug = false, nopechaKey } = opts const { minimize = false, debug = false, nopechaKey, proxyServer } = opts
if (hasNopechaExtension) { if (hasNopechaExtension) {
const page = (await browser.pages())[0] || (await browser.newPage()) const page = await getPage(browser, { proxyServer })
if (minimize) { if (minimize) {
await minimizePage(page) await minimizePage(page)
} }