use std::string::ToString;
use std::sync::Arc;
use regex::Regex;
use reqwest::cookie::{self};
use reqwest::header::{self, HeaderMap, HeaderValue};
use reqwest::Proxy;
pub struct Authenticator {
pub session_token: Option<String>,
email_address: String,
password: String,
session: reqwest::Client,
pub access_token: Option<String>,
user_agent: String,
cookie_store: Arc<cookie::Jar>,
}
impl Authenticator {
pub fn new(email_address: Option<&str>, password: Option<&str>, proxy: Option<Proxy>) -> Self {
let cookie_store = Arc::new(cookie::Jar::default());
let mut client = reqwest::Client::builder()
.cookie_store(true)
.cookie_provider(cookie_store.clone());
if let Some(proxy) = proxy {
client = client.proxy(proxy);
}
Self {
session_token: None,
email_address: email_address.unwrap_or("").to_string(),
password: password.unwrap_or("").to_string(),
session: client.build().unwrap(),
access_token: None,
user_agent: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 \
Safari/537.36"
.to_string(),
cookie_store,
}
}
fn url_encode(string: &str) -> String {
urlencoding::encode(string).to_string()
}
pub async fn begin(&mut self) {
let url = "https://explorer.api.openai.com/api/auth/csrf";
let headers: HeaderMap<HeaderValue> = [
(header::HOST, "explorer.api.openai.com".parse().unwrap()),
(header::ACCEPT, "*/*".parse().unwrap()),
(header::CONNECTION, "keep-alive".parse().unwrap()),
(header::USER_AGENT, self.user_agent.parse().unwrap()),
(header::ACCEPT_LANGUAGE, "en-GB,en-US;q=0.9,en;q=0.8".parse().unwrap()),
(
header::REFERER,
"https://explorer.api.openai.com/auth/login".parse().unwrap(),
),
(header::ACCEPT_ENCODING, "gzip, deflate, br".parse().unwrap()),
]
.into_iter()
.collect();
let response = self.session.get(url).headers(headers).send().await.unwrap();
if response.status().is_success()
&& response
.headers()
.get("Content-Type")
.unwrap()
.to_str()
.unwrap()
.contains("json")
{
let csrf_token = response.json::<serde_json::Value>().await.unwrap()["csrfToken"]
.as_str()
.unwrap()
.to_string();
self.__part_one(&csrf_token).await;
}
else {
panic!("Error: {}", response.text().await.unwrap());
}
}
async fn __part_one(&mut self, token: &str) {
let url = "https://explorer.api.openai.com/api/auth/signin/auth0?prompt=login";
let payload = format!("callbackUrl=%2F&csrfToken={token}&json=true");
let headers: HeaderMap<HeaderValue> = [
(header::HOST, "explorer.api.openai.com".parse().unwrap()),
(header::USER_AGENT, self.user_agent.parse().unwrap()),
(
header::CONTENT_TYPE,
"application/x-www-form-urlencoded".parse().unwrap(),
),
(header::ACCEPT, "*/*".parse().unwrap()),
(header::HeaderName::from_static("Sec-Gpc"), "1".parse().unwrap()),
(header::ACCEPT_LANGUAGE, "en-US,en;q=0.8".parse().unwrap()),
(header::ORIGIN, "https://explorer.api.openai.com".parse().unwrap()),
(
header::HeaderName::from_static("Sec-Fetch-Site"),
"same-origin".parse().unwrap(),
),
(
header::HeaderName::from_static("Sec-Fetch-Mode"),
"cors".parse().unwrap(),
),
(
header::HeaderName::from_static("Sec-Fetch-Dest"),
"empty".parse().unwrap(),
),
(
header::REFERER,
"https://explorer.api.openai.com/auth/login".parse().unwrap(),
),
(header::ACCEPT_ENCODING, "gzip, deflate".parse().unwrap()),
]
.into_iter()
.collect();
let response = self
.session
.post(url)
.headers(headers)
.body(payload)
.send()
.await
.unwrap();
if response.status().is_success()
&& response
.headers()
.get("Content-Type")
.unwrap()
.to_str()
.unwrap()
.contains("json")
{
let url = response.json::<serde_json::Value>().await.unwrap()["url"]
.as_str()
.unwrap()
.to_string();
assert!(
!(url == "https://explorer.api.openai.com/api/auth/error?error=OAuthSignin" || url.contains("error")),
"You have been rate limited. Please try again later."
);
self.__part_two(&url).await;
}
else {
panic!("Error: {}", response.text().await.unwrap());
}
}
async fn __part_two(&mut self, url: &str) {
let headers: HeaderMap<HeaderValue> = [
(header::HOST, "auth0.openai.com".parse().unwrap()),
(
header::ACCEPT,
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
.parse()
.unwrap(),
),
(header::CONNECTION, "keep-alive".parse().unwrap()),
(header::USER_AGENT, self.user_agent.parse().unwrap()),
(header::ACCEPT_LANGUAGE, "en-US,en;q=0.9".parse().unwrap()),
(header::REFERER, "https://explorer.api.openai.com/".parse().unwrap()),
]
.into_iter()
.collect();
let response = self.session.get(url).headers(headers).send().await.unwrap();
if response.status().is_redirection() || response.status().is_success() {
let state = Regex::new(r"state=(.*)")
.unwrap()
.captures(&response.text().await.unwrap())
.unwrap()[1]
.to_string();
self.__part_three(&state).await;
}
else {
panic!("Error: {}", response.text().await.unwrap());
}
}
async fn __part_three(&mut self, state: &str) {
let url = format!("https://auth0.openai.com/u/login/identifier?state={state}");
let headers: HeaderMap<HeaderValue> = [
(header::HOST, "auth0.openai.com".parse().unwrap()),
(
header::ACCEPT,
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
.parse()
.unwrap(),
),
(header::CONNECTION, "keep-alive".parse().unwrap()),
(header::USER_AGENT, self.user_agent.parse().unwrap()),
(header::ACCEPT_LANGUAGE, "en-US,en;q=0.9".parse().unwrap()),
(header::REFERER, "https://explorer.api.openai.com/".parse().unwrap()),
]
.into_iter()
.collect();
let response = self.session.get(url).headers(headers).send().await.unwrap();
if response.status().is_success() {
self.__part_four(state).await;
}
else {
panic!("Error: {}", response.text().await.unwrap());
}
}
async fn __part_four(&mut self, state: &str) {
let url = format!("https://auth0.openai.com/u/login/identifier?state={state}");
let email_url_encoded = Self::url_encode(&self.email_address);
let payload = format!(
"state={state}&username={email_url_encoded}&js-available=false&webauthn-available=true&is-brave=false&\
webauthn-platform-available=true&action=default"
);
let headers: HeaderMap<HeaderValue> = [
(header::HOST, "auth0.openai.com".parse().unwrap()),
(header::ORIGIN, "https://auth0.openai.com".parse().unwrap()),
(header::CONNECTION, "keep-alive".parse().unwrap()),
(
header::ACCEPT,
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
.parse()
.unwrap(),
),
(header::USER_AGENT, self.user_agent.parse().unwrap()),
(
header::REFERER,
format!("https://auth0.openai.com/u/login/identifier?state={state}")
.parse()
.unwrap(),
),
(header::ACCEPT_LANGUAGE, "en-US,en;q=0.9".parse().unwrap()),
(
header::CONTENT_TYPE,
"application/x-www-form-urlencoded".parse().unwrap(),
),
]
.into_iter()
.collect();
let response = self
.session
.post(url)
.headers(headers)
.body(payload)
.send()
.await
.unwrap();
if response.status().is_redirection() || response.status().is_success() {
self.__part_five(state).await;
}
else {
panic!("Error: {}", response.text().await.unwrap());
}
}
async fn __part_five(&mut self, state: &str) {
let url = format!("https://auth0.openai.com/u/login/password?state={state}");
let email_url_encoded = Self::url_encode(&self.email_address);
let password_url_encoded = Self::url_encode(&self.password);
let payload =
format!("state={state}&username={email_url_encoded}&password={password_url_encoded}&action=default");
let headers: HeaderMap<HeaderValue> = [
(header::HOST, "auth0.openai.com".parse().unwrap()),
(header::ORIGIN, "https://auth0.openai.com".parse().unwrap()),
(header::CONNECTION, "keep-alive".parse().unwrap()),
(
header::ACCEPT,
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
.parse()
.unwrap(),
),
(header::USER_AGENT, self.user_agent.parse().unwrap()),
(
header::REFERER,
format!("https://auth0.openai.com/u/login/password?state={state}")
.parse()
.unwrap(),
),
(header::ACCEPT_LANGUAGE, "en-US,en;q=0.9".parse().unwrap()),
(
header::CONTENT_TYPE,
"application/x-www-form-urlencoded".parse().unwrap(),
),
]
.into_iter()
.collect();
let response = self
.session
.post(url)
.headers(headers)
.body(payload)
.send()
.await
.unwrap();
if response.status().is_redirection() || response.status().is_success() {
let text = response.text().await.unwrap();
let captures = Regex::new(r"state=(.*)").unwrap().captures(&text).unwrap();
let new_state = captures[1].split('"').next().unwrap();
self.__part_six(state, new_state).await;
}
else {
panic!("Error: {}", response.text().await.unwrap());
}
}
async fn __part_six(&mut self, old_state: &str, new_state: &str) {
let url = format!("https://auth0.openai.com/authorize/resume?state={new_state}");
let headers: HeaderMap<HeaderValue> = [
(header::HOST, "auth0.openai.com".parse().unwrap()),
(
header::ACCEPT,
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
.parse()
.unwrap(),
),
(header::CONNECTION, "keep-alive".parse().unwrap()),
(header::USER_AGENT, self.user_agent.parse().unwrap()),
(header::ACCEPT_LANGUAGE, "en-GB,en-US;q=0.9,en;q=0.8".parse().unwrap()),
(
header::REFERER,
format!("https://auth0.openai.com/u/login/password?state={old_state}")
.parse()
.unwrap(),
),
]
.into_iter()
.collect();
let response = self.session.get(&url).headers(headers).send().await.unwrap();
if response.status().is_redirection() {
let redirect_url = response.headers().get("location").unwrap();
self.__part_seven(redirect_url.to_str().unwrap(), &url).await;
}
else {
panic!("Error: {}", response.text().await.unwrap());
}
}
async fn __part_seven(&mut self, redirect_url: &str, previous_url: &str) {
let url = redirect_url;
let headers: HeaderMap<HeaderValue> = [
(header::HOST, "explorer.api.openai.com".parse().unwrap()),
(header::ACCEPT, "application/json".parse().unwrap()),
(header::CONNECTION, "keep-alive".parse().unwrap()),
(header::USER_AGENT, self.user_agent.parse().unwrap()),
(header::ACCEPT_LANGUAGE, "en-GB,en-US;q=0.9,en;q=0.8".parse().unwrap()),
(header::REFERER, previous_url.parse().unwrap()),
]
.into_iter()
.collect();
let response = self.session.get(url).headers(headers).send().await.unwrap();
if response.status().is_redirection() {
self.session_token = Some(
response
.cookies()
.find(|cookie| cookie.name() == "__Secure-next-auth.session-token")
.unwrap()
.value()
.to_string(),
);
self.get_access_token().await;
}
else {
panic!("Error: {}", response.text().await.unwrap());
}
}
pub async fn get_access_token(&mut self) {
let url = "https://explorer.api.openai.com/api/auth/session".parse().unwrap();
let cookie = format!(
"{}={}",
"__Secure-next-auth.session-token",
self.session_token.as_ref().unwrap()
);
self.cookie_store.add_cookie_str(&cookie, &url);
let response = self.session.get(url).send().await.unwrap();
if response.status().is_success() {
self.access_token = Some(
response.json::<serde_json::Value>().await.unwrap()["accessToken"]
.as_str()
.unwrap()
.to_string(),
);
}
else {
panic!("Error: {}", response.text().await.unwrap());
}
}
}