1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use std::sync::Arc;
use rootcause::prelude::*;
use tokio::sync::RwLock;
use crate::{
anisette::{AnisetteDataGenerator, AnisetteProvider, remote_v3::RemoteV3AnisetteProvider},
auth::apple_account::AppleAccount,
};
pub struct AppleAccountBuilder {
email: String,
debug: Option<bool>,
anisette_generator: Option<AnisetteDataGenerator>,
}
impl AppleAccountBuilder {
/// Create a new AppleAccountBuilder with the given email
///
/// # Arguments
/// - `email`: The Apple ID email address
pub fn new(email: &str) -> Self {
Self {
email: email.to_string(),
debug: None,
anisette_generator: None,
}
}
/// DANGER Set whether to enable debug mode
///
/// # Arguments
/// - `debug`: If true, accept invalid certificates and enable verbose connection logging
pub fn danger_debug(mut self, debug: bool) -> Self {
self.debug = Some(debug);
self
}
pub fn anisette_provider(
mut self,
anisette_provider: impl AnisetteProvider + Send + Sync + 'static,
) -> Self {
self.anisette_generator = Some(AnisetteDataGenerator::new(Arc::new(RwLock::new(
anisette_provider,
))));
self
}
/// Build the AppleAccount without logging in
///
/// # Errors
/// Returns an error if the reqwest client cannot be built
pub async fn build(self) -> Result<AppleAccount, Report> {
let debug = self.debug.unwrap_or(false);
let anisette_generator = match self.anisette_generator {
Some(generator) => generator,
None => {
let provider = RemoteV3AnisetteProvider::default()?;
AnisetteDataGenerator::new(Arc::new(RwLock::new(provider)))
}
};
AppleAccount::new(&self.email, anisette_generator, debug).await
}
/// Build the AppleAccount and log in
///
/// # Arguments
/// - `password`: The Apple ID password
/// - `two_factor_callback`: A callback function that returns the two-factor authentication code
/// # Errors
/// Returns an error if the reqwest client cannot be built
pub async fn login<F, Fut>(
self,
password: &str,
two_factor_callback: F,
) -> Result<AppleAccount, Report>
where
F: Fn() -> Fut,
Fut: Future<Output = Option<String>>,
{
let mut account = self.build().await?;
account.login(password, two_factor_callback).await?;
Ok(account)
}
}