-
Notifications
You must be signed in to change notification settings - Fork 147
/
auth.rs
101 lines (91 loc) · 3.25 KB
/
auth.rs
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use std::io::Write;
use anyhow::{anyhow, Result};
use librespot_core::{
authentication::Credentials,
cache::Cache,
config::SessionConfig,
session::{Session, SessionError},
};
fn read_user_auth_details(user: Option<String>) -> Result<(String, String)> {
let mut username = String::new();
let mut stdout = std::io::stdout();
match user {
None => write!(stdout, "Username: ")?,
Some(ref u) => write!(stdout, "Username (default: {}): ", u)?,
}
stdout.flush()?;
std::io::stdin().read_line(&mut username)?;
username = username.trim_end().to_string();
if username.is_empty() {
username = user.unwrap_or_default();
}
let password = rpassword::prompt_password(&format!("Password for {}: ", username))?;
Ok((username, password))
}
async fn new_session_with_new_creds(cache: &Cache) -> Result<Session> {
tracing::info!("Creating a new session with new authentication credentials");
println!("Authentication token not found or invalid, please reauthenticate.");
let mut user: Option<String> = None;
for i in 0..3 {
let (username, password) = read_user_auth_details(user)?;
user = Some(username.clone());
match Session::connect(
SessionConfig::default(),
Credentials::with_password(username, password),
Some(cache.clone()),
true,
)
.await
{
Ok((session, _)) => {
println!("Successfully authenticated as {}", user.unwrap_or_default());
return Ok(session);
}
Err(err) => {
println!("Failed to authenticate, {} tries left", 2 - i);
tracing::warn!("Failed to authenticate: {err:#}")
}
}
}
Err(anyhow!("authentication failed!"))
}
/// creates new Librespot session
pub async fn new_session(cache_folder: &std::path::Path, audio_cache: bool) -> Result<Session> {
// specifying `audio_cache` to `None` to disable audio cache
let audio_cache_folder = if audio_cache {
Some(cache_folder.join("audio"))
} else {
None
};
let cache = Cache::new(
Some(cache_folder),
None,
audio_cache_folder.as_deref(),
None,
)?;
// create a new session if either
// - there is no cached credentials or
// - the cached credentials are expired or invalid
match cache.credentials() {
None => new_session_with_new_creds(&cache).await,
Some(creds) => {
match Session::connect(SessionConfig::default(), creds, Some(cache.clone()), true).await
{
Ok((session, _)) => {
tracing::info!("Use the cached credentials");
Ok(session)
}
Err(err) => match err {
SessionError::AuthenticationError(err) => {
tracing::warn!("Failed to authenticate: {err:#}");
new_session_with_new_creds(&cache).await
}
SessionError::IoError(err) => Err(anyhow!(format!(
"{}\nPlease check your internet connection.",
err
))),
},
}
}
}
}