#[macro_use]
extern crate tracing;
#[macro_use]
extern crate anyhow;
mod config;
mod maps;
mod signers;
mod ticket;
use anyhow::Context;
use axum::{
body::{Body, Bytes, HttpBody},
http::{Request, StatusCode},
routing::post,
Router,
};
use clap::{arg, command, value_parser};
use config::{Config, RuntimeConfig};
use plist::Value as PlistValue;
use signers::Signers;
use std::{collections::BTreeMap, path::PathBuf};
use tracing_subscriber::FmtSubscriber;
#[tokio::main]
#[instrument]
async fn main() -> anyhow::Result<()> {
let matches = command!()
.arg(
arg!(-c --config <FILE> "Sets path to a config file.")
.value_parser(value_parser!(PathBuf)),
)
.get_matches();
let config_path: &PathBuf = matches.get_one("config").expect("missing required arg");
let Config { setup, runtime } =
plist::from_file(config_path).context("while loading config file")?;
FmtSubscriber::builder().init();
let signers = Signers::load(&setup.signers).await?;
let app = Router::new().route(
"/TSS/controller",
post(move |req: Request<Body>| async move {
handle(&runtime, req, &signers).await.map_err(|e| {
println!("{e}");
StatusCode::BAD_REQUEST
})
}),
);
axum::Server::bind(&setup.listen_addr)
.serve(app.into_make_service())
.await?;
Ok(())
}
const DEFAULT_USER_AGENT: &str = "libauthinstall-836.0.0.111.3";
async fn handle(
config: &RuntimeConfig,
mut req: Request<Body>,
signers: &Signers,
) -> anyhow::Result<Bytes> {
let data = req.data().await.ok_or_else(|| anyhow!("no data"))??;
let req: BTreeMap<String, PlistValue> = plist::from_bytes(&data)?;
if config.forward_local_policy && req.contains_key("Ap,LocalPolicy") {
let client = reqwest::Client::new();
let resp = client
.post("http://gs.apple.com/TSS/controller?action=2")
.header("Content-Type", "text/xml; charset=\"utf-8\"")
.header(
"User-Agent",
config.user_agent.as_deref().unwrap_or(DEFAULT_USER_AGENT),
)
.body(data)
.send()
.await?;
return Ok(resp.bytes().await?);
}
let mut resp = BTreeMap::new();
resp.insert("@ServerVersion".to_string(), "2.1.0".into());
if req.get("@ApImg4Ticket") == Some(&PlistValue::Boolean(true)) {
ticket::append_ap_img4_ticket(&req, &mut resp, signers, "ApImg4Ticket")?;
}
if req.get("@Cryptex1,Ticket") == Some(&PlistValue::Boolean(true)) {
ticket::append_ap_img4_ticket(&req, &mut resp, signers, "Cryptex1,Ticket")?;
}
let mut bytes = Vec::new();
bytes.extend_from_slice(b"STATUS=0&MESSAGE=SUCCESS&REQUEST_STRING=");
plist::to_writer_xml(&mut bytes, &resp)?;
Ok(bytes.into())
}