mirror of
https://git.gaycatgirl.sex/husky/free_twitter_api.git
synced 2024-12-21 22:51:23 -05:00
initial stuffz
This commit is contained in:
commit
7bb560b89b
4 changed files with 173 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
/Cargo.lock
|
12
Cargo.toml
Normal file
12
Cargo.toml
Normal 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
159
src/lib.rs
Normal 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
0
src/token_generator.rs
Normal file
Loading…
Reference in a new issue