mirror of
https://github.com/nab138/isideload.git
synced 2026-03-02 14:36:16 +01:00
Use storage provider for anisette and provide fs-storage implementation
This commit is contained in:
@@ -9,7 +9,6 @@ use isideload::{
|
||||
teams::DeveloperTeam,
|
||||
},
|
||||
sideload::{SideloaderBuilder, TeamSelection, builder::MaxCertsBehavior},
|
||||
util::keyring_storage::KeyringStorage,
|
||||
};
|
||||
|
||||
use tracing::Level;
|
||||
@@ -120,9 +119,6 @@ async fn main() {
|
||||
let mut sideloader = SideloaderBuilder::new(dev_session, apple_id.to_string())
|
||||
.team_selection(TeamSelection::Prompt(team_selection_prompt))
|
||||
.max_certs_behavior(MaxCertsBehavior::Prompt(cert_selection_prompt))
|
||||
.storage(Box::new(KeyringStorage::new(
|
||||
"isideload-minimal".to_string(),
|
||||
)))
|
||||
.machine_name("isideload-minimal".to_string())
|
||||
.build();
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ readme = "../README.md"
|
||||
default = ["install", "keyring-storage"]
|
||||
install = ["dep:idevice"]
|
||||
keyring-storage = ["keyring"]
|
||||
fs-storage = []
|
||||
|
||||
# Unfortunately, dependencies are kinda a mess rn, since this requires a beta version of the srp crate.
|
||||
# Once that becomes stable, hopefuly duplicate dependencies should clean up.\
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
mod state;
|
||||
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::SystemTime;
|
||||
|
||||
@@ -11,13 +9,14 @@ use reqwest::header::{CONTENT_TYPE, HeaderMap, HeaderValue};
|
||||
use rootcause::prelude::*;
|
||||
use serde::Deserialize;
|
||||
use tokio_tungstenite::tungstenite::Message;
|
||||
use tracing::{debug, info};
|
||||
use tracing::{debug, info, warn};
|
||||
|
||||
use crate::SideloadError;
|
||||
use crate::anisette::remote_v3::state::AnisetteState;
|
||||
use crate::anisette::{AnisetteClientInfo, AnisetteData, AnisetteProvider};
|
||||
use crate::auth::grandslam::GrandSlam;
|
||||
use crate::util::plist::PlistDataExtract;
|
||||
use crate::util::storage::{SideloadingStorage, new_storage};
|
||||
use futures_util::{SinkExt, StreamExt};
|
||||
|
||||
pub const DEFAULT_ANISETTE_V3_URL: &str = "https://ani.stikstore.app";
|
||||
@@ -25,7 +24,7 @@ pub const DEFAULT_ANISETTE_V3_URL: &str = "https://ani.stikstore.app";
|
||||
pub struct RemoteV3AnisetteProvider {
|
||||
pub state: Option<AnisetteState>,
|
||||
url: String,
|
||||
config_path: PathBuf,
|
||||
storage: Box<dyn SideloadingStorage>,
|
||||
serial_number: String,
|
||||
client_info: Option<AnisetteClientInfo>,
|
||||
client: reqwest::Client,
|
||||
@@ -36,14 +35,14 @@ impl RemoteV3AnisetteProvider {
|
||||
///
|
||||
/// # Arguments
|
||||
/// - `url`: The URL of the remote anisette service
|
||||
/// - `config_path`: The path to the config file
|
||||
/// - `storage`: The storage backend for anisette data
|
||||
/// - `serial_number`: The serial number of the device
|
||||
///
|
||||
pub fn new(url: &str, config_path: PathBuf, serial_number: String) -> Self {
|
||||
pub fn new(url: &str, storage: Box<dyn SideloadingStorage>, serial_number: String) -> Self {
|
||||
Self {
|
||||
state: None,
|
||||
url: url.to_string(),
|
||||
config_path,
|
||||
storage,
|
||||
serial_number,
|
||||
client_info: None,
|
||||
client: reqwest::ClientBuilder::new()
|
||||
@@ -58,8 +57,8 @@ impl RemoteV3AnisetteProvider {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_config_path(mut self, config_path: PathBuf) -> RemoteV3AnisetteProvider {
|
||||
self.config_path = config_path;
|
||||
pub fn set_storage(mut self, storage: Box<dyn SideloadingStorage>) -> RemoteV3AnisetteProvider {
|
||||
self.storage = storage;
|
||||
self
|
||||
}
|
||||
|
||||
@@ -71,7 +70,11 @@ impl RemoteV3AnisetteProvider {
|
||||
|
||||
impl Default for RemoteV3AnisetteProvider {
|
||||
fn default() -> Self {
|
||||
Self::new(DEFAULT_ANISETTE_V3_URL, PathBuf::new(), "0".to_string())
|
||||
Self::new(
|
||||
DEFAULT_ANISETTE_V3_URL,
|
||||
Box::new(new_storage()),
|
||||
"0".to_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,12 +169,15 @@ impl AnisetteProvider for RemoteV3AnisetteProvider {
|
||||
|
||||
impl RemoteV3AnisetteProvider {
|
||||
async fn get_state(&mut self, gs: Arc<GrandSlam>) -> Result<&mut AnisetteState, Report> {
|
||||
let state_path = self.config_path.join("state.plist");
|
||||
fs::create_dir_all(&self.config_path)?;
|
||||
if self.state.is_none() {
|
||||
if let Ok(state) = plist::from_file(&state_path) {
|
||||
info!("Loaded existing anisette state from {:?}", state_path);
|
||||
self.state = Some(state);
|
||||
if let Ok(Some(state)) = &self.storage.retrieve_data("anisette_state") {
|
||||
if let Ok(state) = plist::from_bytes(state) {
|
||||
info!("Loaded existing anisette state");
|
||||
self.state = Some(state);
|
||||
} else {
|
||||
warn!("Failed to parse existing anisette state, starting fresh");
|
||||
self.state = Some(AnisetteState::new());
|
||||
}
|
||||
} else {
|
||||
info!("No existing anisette state found");
|
||||
self.state = Some(AnisetteState::new());
|
||||
@@ -185,7 +191,11 @@ impl RemoteV3AnisetteProvider {
|
||||
.await
|
||||
.context("Failed to provision")?;
|
||||
}
|
||||
plist::to_file_xml(&state_path, &state)?;
|
||||
let buf = Vec::new();
|
||||
let mut writer = std::io::BufWriter::new(buf);
|
||||
plist::to_writer_xml(&mut writer, &state).unwrap();
|
||||
self.storage
|
||||
.store_data("anisette_state", &writer.into_inner()?)?;
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
53
isideload/src/util/fs_storage.rs
Normal file
53
isideload/src/util/fs_storage.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use rootcause::prelude::*;
|
||||
|
||||
use crate::util::storage::SideloadingStorage;
|
||||
|
||||
pub struct FsStorage {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl FsStorage {
|
||||
pub fn new(path: PathBuf) -> Self {
|
||||
FsStorage { path }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FsStorage {
|
||||
fn default() -> Self {
|
||||
Self::new(PathBuf::from("."))
|
||||
}
|
||||
}
|
||||
|
||||
impl SideloadingStorage for FsStorage {
|
||||
fn store_data(&self, key: &str, data: &[u8]) -> Result<(), Report> {
|
||||
let path = self.path.join(key);
|
||||
let parent = path.parent().unwrap_or(Path::new("."));
|
||||
std::fs::create_dir_all(parent).context("Failed to create storage directory")?;
|
||||
std::fs::write(&path, data).context("Failed to write data to file")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn retrieve_data(&self, key: &str) -> Result<Option<Vec<u8>>, Report> {
|
||||
let path = self.path.join(key);
|
||||
match std::fs::read(&path) {
|
||||
Ok(data) => Ok(Some(data)),
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(None),
|
||||
Err(e) => Err(report!(e).context("Failed to read data from file").into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn store(&self, key: &str, value: &str) -> Result<(), Report> {
|
||||
self.store_data(key, value.as_bytes())
|
||||
}
|
||||
|
||||
fn retrieve(&self, key: &str) -> Result<Option<String>, Report> {
|
||||
match self.retrieve_data(key) {
|
||||
Ok(Some(data)) => Ok(Some(String::from_utf8_lossy(&data).into_owned())),
|
||||
Ok(None) => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
pub mod device;
|
||||
#[cfg(feature = "fs-storage")]
|
||||
pub mod fs_storage;
|
||||
#[cfg(feature = "keyring-storage")]
|
||||
pub mod keyring_storage;
|
||||
pub mod plist;
|
||||
|
||||
@@ -27,11 +27,18 @@ pub trait SideloadingStorage: Send + Sync {
|
||||
pub fn new_storage() -> impl SideloadingStorage {
|
||||
#[cfg(feature = "keyring-storage")]
|
||||
{
|
||||
crate::util::keyring_storage::KeyringStorage::default()
|
||||
return crate::util::keyring_storage::KeyringStorage::default();
|
||||
}
|
||||
#[cfg(not(feature = "keyring-storage"))]
|
||||
#[cfg(feature = "fs-storage")]
|
||||
{
|
||||
InMemoryStorage::new()
|
||||
return crate::util::fs_storage::FsStorage::default();
|
||||
}
|
||||
#[cfg(not(any(feature = "keyring-storage", feature = "fs-storage")))]
|
||||
{
|
||||
tracing::warn!(
|
||||
"Keyring storage not enabled, falling back to in-memory storage. This means that the anisette state and certificates will not be saved across runs. Enable the 'keyring-storage' or 'fs-storage' feature for persistance."
|
||||
);
|
||||
return InMemoryStorage::new();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user