initial stuffz

This commit is contained in:
fekhesk 2023-02-11 08:43:29 -08:00
commit 7bb560b89b
No known key found for this signature in database
GPG key ID: 6B3D8CB511646891
4 changed files with 173 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
/Cargo.lock

12
Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "free_twitter_api"
version = "0.1.0"
edition = "2021"
[dependencies]
isahc = "1.7.2"
rand = "0.8.5"
log = "0.4.17"
[dev-dependencies]
env_logger = "0.10.0"

159
src/lib.rs Normal file
View file

@ -0,0 +1,159 @@
use std::net::SocketAddr;
use std::str::FromStr;
use std::sync::Arc;
use isahc::auth::{Authentication, Credentials};
use isahc::{Body, Request, Response};
use isahc::http::HeaderMap;
use isahc::prelude::*;
use log::debug;
const USER_AGENTS: [&str; 5] = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 13_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.41",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
];
/// this is what we look for to find the bearer token
const SEARCH_STRING: &str = "AAAAAAAAA";
/// this is what we look for to find the main.*.js file
const MAIN_JS_SEARCH_STRING: &str = "main.";
struct Proxy {
address: String,
credentials: Option<Credentials>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ProxyError {
InvalidProxyFormat,
}
#[derive(Clone, Debug)]
pub enum BearerError {
CouldntGetTwitterDotCom(isahc::Error),
CouldntFindMainJsUrl,
CouldntGetMainDotJs(isahc::Error),
CouldntFindBearerToken,
}
impl FromStr for Proxy {
type Err = ProxyError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut parts = s.split(':');
let host = parts.next().ok_or(ProxyError::InvalidProxyFormat)?;
let port = parts.next().ok_or(ProxyError::InvalidProxyFormat)?;
let auth = if let Some(user) = parts.next() {
let pass = parts.next().ok_or(ProxyError::InvalidProxyFormat)?;
Some(Credentials::new(user, pass))
} else {
None
};
Ok(Proxy {
address: format!("{}:{}", host, port),
credentials: auth,
})
}
}
#[derive(Clone)]
pub struct Client {
http_client: Arc<isahc::HttpClient>,
proxy: Option<Arc<Proxy>>,
}
impl Default for Client {
fn default() -> Self {
Self::new()
}
}
impl Client {
pub fn new() -> Self {
Client {
http_client: Arc::new(isahc::HttpClient::new().expect("failed to create http client")),
proxy: None,
}
}
pub fn new_with_proxy(proxy: &str) -> Self {
let proxy = proxy.parse().unwrap();
Client {
http_client: Arc::new(isahc::HttpClient::new().expect("failed to create http client")),
proxy: Some(Arc::new(proxy)),
}
}
fn get(&self, url: &str, headers: &HeaderMap) -> Result<Response<Body>, isahc::Error> {
let mut request = Request::get(url);
if let Some(proxy) = &self.proxy {
request = request.proxy(Some(proxy.address.parse().expect("error parsing proxy!")));
if let Some(creds) = &proxy.credentials {
request = request.proxy_authentication(Authentication::basic());
request = request.proxy_credentials(creds.clone());
}
}
let mut request = request.body(())?;
request.headers_mut().extend(headers.iter().map(|(k, v)| (k.clone(), v.clone())));
self.http_client.send(request)
}
fn get_twitter_bearer_token(&self) -> Result<String, BearerError> {
let url = "https://twitter.com";
let mut headers = HeaderMap::new();
let user_agent = USER_AGENTS[rand::random::<usize>() % USER_AGENTS.len()];
headers.insert("user-agent", user_agent.parse().unwrap());
let mut response = self.get(url, &headers).map_err(BearerError::CouldntGetTwitterDotCom)?;
let body = response.text().unwrap();
let mut mainjs_url = None;
// fixme! this is really fucking cursed
for line in body.lines() {
if line.contains(MAIN_JS_SEARCH_STRING) {
let main_js_start = line.find(MAIN_JS_SEARCH_STRING).unwrap();
let main_js_end = line[main_js_start..].find('"').unwrap() + main_js_start;
let main_js_url_start = line[0..main_js_start].rfind('"').unwrap();
let main_js_url = &line[main_js_url_start + 1..main_js_end];
mainjs_url = Some(main_js_url.to_string());
}
}
let mainjs_url = mainjs_url.ok_or(BearerError::CouldntFindMainJsUrl)?;
debug!("mainjs_url: {}", mainjs_url);
// now get the main.js file
let mut response = self.get(&mainjs_url, &headers).map_err(BearerError::CouldntGetMainDotJs)?;
let body = response.text().unwrap();
let mut token = None;
for line in body.lines() {
if line.contains(SEARCH_STRING) {
let bearer_token_start = line.find(SEARCH_STRING).unwrap();
let bearer_token_end = line[bearer_token_start..].find('"').unwrap() + bearer_token_start;
let bearer_token = &line[bearer_token_start..bearer_token_end];
token = Some(bearer_token.to_string());
}
}
let token = token.ok_or(BearerError::CouldntFindBearerToken)?;
Ok(token)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn world_normal() {
let result = 2 + 2;
assert_eq!(result, 4);
}
#[test]
fn get_bearer_token() {
env_logger::init();
let client = Client::new();
let bearer_token = client.get_twitter_bearer_token();
println!("{:?}", bearer_token);
}
}

0
src/token_generator.rs Normal file
View file