use crate::Error;
use omnisette::{obf, AnisetteConfiguration, AnisetteHeaders};
use std::{collections::HashMap, time::SystemTime};
#[derive(Debug, Clone)]
pub struct AnisetteData {
pub base_headers: HashMap<String, String>,
pub generated_at: SystemTime,
pub config: AnisetteConfiguration,
}
impl AnisetteData {
pub async fn new(config: AnisetteConfiguration) -> Result<Self, crate::Error> {
let mut b = AnisetteHeaders::get_anisette_headers_provider(config.clone())?;
let base_headers = b.provider.get_authentication_headers().await?;
Ok(AnisetteData {
base_headers,
generated_at: SystemTime::now(),
config,
})
}
pub fn needs_refresh(&self) -> bool {
let elapsed = self.generated_at.elapsed().unwrap();
elapsed.as_secs() > 60
}
pub fn is_valid(&self) -> bool {
let elapsed = self.generated_at.elapsed().unwrap();
elapsed.as_secs() < 90
}
pub async fn refresh(&self) -> Result<Self, crate::Error> {
Self::new(self.config.clone()).await
}
pub fn generate_headers(
&self,
cpd: bool,
client_info: bool,
app_info: bool,
) -> HashMap<String, String> {
if !self.is_valid() {
panic!("Invalid data!")
}
let mut headers = self.base_headers.clone();
let old_client_info = headers.remove("X-Mme-Client-Info");
if client_info {
let client_info = match old_client_info {
Some(v) => {
let temp = v.as_str();
temp.replace(
temp.split('<').nth(3).unwrap().split('>').nth(0).unwrap(),
obf!("com.apple.AuthKit/1 (com.apple.dt.Xcode/3594.4.19)"),
)
}
None => {
return headers;
}
};
headers.insert(
obf!("X-Mme-Client-Info").to_string(),
client_info.to_owned(),
);
}
if app_info {
headers.insert(
obf!("X-Apple-App-Info").to_string(),
obf!("com.apple.gs.xcode.auth").to_string(),
);
headers.insert(
obf!("X-Xcode-Version").to_string(),
obf!("11.2 (11B41)").to_string(),
);
}
if cpd {
headers.insert(obf!("bootstrap").to_string(), obf!("true").to_string());
headers.insert(obf!("icscrec").to_string(), obf!("true").to_string());
headers.insert(obf!("loc").to_string(), obf!("en_GB").to_string());
headers.insert(obf!("pbe").to_string(), obf!("false").to_string());
headers.insert(obf!("prkgen").to_string(), obf!("true").to_string());
headers.insert(obf!("svct").to_string(), obf!("iCloud").to_string());
}
headers
}
pub fn to_plist(&self, cpd: bool, client_info: bool, app_info: bool) -> plist::Dictionary {
let mut plist = plist::Dictionary::new();
for (key, value) in self.generate_headers(cpd, client_info, app_info).iter() {
plist.insert(key.to_owned(), plist::Value::String(value.to_owned()));
}
plist
}
pub fn get_header(&self, header: &str) -> Result<String, Error> {
let headers = self
.generate_headers(true, true, true)
.iter()
.map(|(k, v)| (k.to_lowercase(), v.to_lowercase()))
.collect::<HashMap<String, String>>();
match headers.get(&header.to_lowercase()) {
Some(v) => Ok(v.to_string()),
None => Err(Error::Parse),
}
}
}