mirror of
https://github.com/librespot-org/librespot.git
synced 2024-12-18 17:11:53 +00:00
Save reusable credentials to disk.
After the first login, credentials may be omitted from the command line and the stored ones will be used instead.
This commit is contained in:
parent
39af43728a
commit
4b73f83c5e
4 changed files with 91 additions and 17 deletions
15
Cargo.lock
generated
15
Cargo.lock
generated
|
@ -71,6 +71,11 @@ name = "byteorder"
|
|||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.2.20"
|
||||
|
@ -319,7 +324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
[[package]]
|
||||
name = "portaudio"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/mvdnes/portaudio-rs#840b1096780c069fd54b4a425bcfebec99ef9c1a"
|
||||
source = "git+https://github.com/mvdnes/portaudio-rs#0b228f54a16814c52ba1ef449ac439af59f8cab0"
|
||||
dependencies = [
|
||||
"bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -329,7 +334,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "portaudio_sys"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/mvdnes/portaudio-rs#840b1096780c069fd54b4a425bcfebec99ef9c1a"
|
||||
source = "git+https://github.com/mvdnes/portaudio-rs#0b228f54a16814c52ba1ef449ac439af59f8cab0"
|
||||
dependencies = [
|
||||
"libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -441,7 +446,7 @@ name = "shannon"
|
|||
version = "0.1.1"
|
||||
source = "git+https://github.com/plietar/rust-shannon#7000b3e49a53daaa890727ba2b2bd5a43cc4ffef"
|
||||
dependencies = [
|
||||
"byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"shannon-sys 0.1.0 (git+https://github.com/plietar/rust-shannon)",
|
||||
]
|
||||
|
@ -555,7 +560,7 @@ name = "tremor"
|
|||
version = "0.1.0"
|
||||
source = "git+https://github.com/plietar/rust-tremor#5ced876f3cffb041fcf31238da7f3273178029fe"
|
||||
dependencies = [
|
||||
"libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tremor-sys 0.1.0 (git+https://github.com/plietar/rust-tremor)",
|
||||
]
|
||||
|
||||
|
@ -565,7 +570,7 @@ version = "0.1.0"
|
|||
source = "git+https://github.com/plietar/rust-tremor#5ced876f3cffb041fcf31238da7f3273178029fe"
|
||||
dependencies = [
|
||||
"gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
|
|
@ -7,17 +7,29 @@ use crypto::mac::Mac;
|
|||
use crypto::pbkdf2::pbkdf2;
|
||||
use crypto::sha1::Sha1;
|
||||
use protobuf::ProtobufEnum;
|
||||
use std::io::{self, Read};
|
||||
use rustc_serialize::base64::FromBase64;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use rustc_serialize::base64::{self, FromBase64, ToBase64};
|
||||
use rustc_serialize::json;
|
||||
|
||||
use protocol::authentication::AuthenticationType;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Credentials {
|
||||
pub username: String,
|
||||
pub auth_type: AuthenticationType,
|
||||
pub auth_data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(RustcDecodable, RustcEncodable)]
|
||||
struct StoredCredentials {
|
||||
pub username: String,
|
||||
pub auth_type: i32,
|
||||
pub auth_data: String,
|
||||
}
|
||||
|
||||
impl Credentials {
|
||||
pub fn with_password(username: String, password: String) -> Credentials {
|
||||
Credentials {
|
||||
|
@ -108,4 +120,47 @@ impl Credentials {
|
|||
auth_data: auth_data,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_reader<R: Read>(mut reader: R) -> Credentials {
|
||||
let mut contents = String::new();
|
||||
reader.read_to_string(&mut contents).unwrap();
|
||||
|
||||
json::decode::<StoredCredentials>(&contents).unwrap().into()
|
||||
}
|
||||
|
||||
pub fn from_file<P: AsRef<Path>>(path: P) -> Credentials {
|
||||
let file = File::open(path).unwrap();
|
||||
Credentials::from_reader(file)
|
||||
}
|
||||
|
||||
pub fn save_to_writer<W: Write>(&self, writer: &mut W) {
|
||||
let contents = json::encode::<StoredCredentials>(&self.clone().into()).unwrap();
|
||||
writer.write_all(contents.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
pub fn save_to_file<P: AsRef<Path>>(&self, path: P) {
|
||||
let mut file = File::create(path).unwrap();
|
||||
self.save_to_writer(&mut file)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Credentials> for StoredCredentials {
|
||||
fn from(credentials: Credentials) -> StoredCredentials {
|
||||
StoredCredentials {
|
||||
username: credentials.username,
|
||||
auth_type: credentials.auth_type.value(),
|
||||
auth_data: credentials.auth_data.to_base64(base64::STANDARD),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredCredentials> for Credentials {
|
||||
fn from(credentials: StoredCredentials) -> Credentials {
|
||||
Credentials {
|
||||
username: credentials.username,
|
||||
auth_type: AuthenticationType::from_i32(credentials.auth_type).unwrap(),
|
||||
auth_data: credentials.auth_data.from_base64().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
21
src/main.rs
21
src/main.rs
|
@ -55,7 +55,7 @@ fn main() {
|
|||
};
|
||||
|
||||
let username = matches.opt_str("u");
|
||||
let cache_location = matches.opt_str("c").unwrap();
|
||||
let cache_location = PathBuf::from(matches.opt_str("c").unwrap());
|
||||
let name = matches.opt_str("n").unwrap();
|
||||
|
||||
let credentials = username.map(|u| {
|
||||
|
@ -84,23 +84,30 @@ fn main() {
|
|||
application_key: appkey,
|
||||
user_agent: version_string(),
|
||||
device_name: name,
|
||||
cache_location: PathBuf::from(cache_location),
|
||||
cache_location: cache_location.clone(),
|
||||
bitrate: bitrate,
|
||||
};
|
||||
|
||||
let session = Session::new(config);
|
||||
|
||||
let credentials = credentials.map_or_else(|| {
|
||||
let credentials_path = cache_location.join("credentials.json");
|
||||
|
||||
let credentials = credentials.map(|(username, password)| {
|
||||
Credentials::with_password(username, password)
|
||||
}).or_else(|| {
|
||||
File::open(&credentials_path).map(|file| {
|
||||
Credentials::from_reader(file)
|
||||
}).ok()
|
||||
}).unwrap_or_else(|| {
|
||||
let mut discovery = DiscoveryManager::new(session.clone());
|
||||
discovery.run()
|
||||
}, |(username, password)| {
|
||||
Credentials::with_password(username, password)
|
||||
});
|
||||
|
||||
session.login(credentials).unwrap();
|
||||
let reusable_credentials = session.login(credentials).unwrap();
|
||||
reusable_credentials.save_to_file(credentials_path);
|
||||
|
||||
let player = Player::new(session.clone());
|
||||
let mut spirc = SpircManager::new(session.clone(), player);
|
||||
let spirc = SpircManager::new(session.clone(), player);
|
||||
thread::spawn(move || spirc.run());
|
||||
|
||||
loop {
|
||||
|
|
|
@ -180,7 +180,7 @@ impl Session {
|
|||
&recv_key)
|
||||
}
|
||||
|
||||
pub fn login(&self, credentials: Credentials) -> Result<(), ()> {
|
||||
pub fn login(&self, credentials: Credentials) -> Result<Credentials, ()> {
|
||||
let packet = protobuf_init!(protocol::authentication::ClientResponseEncrypted::new(), {
|
||||
login_credentials => {
|
||||
username: credentials.username,
|
||||
|
@ -213,12 +213,19 @@ impl Session {
|
|||
protobuf::parse_from_bytes(&data).unwrap();
|
||||
|
||||
let username = welcome_data.get_canonical_username().to_owned();
|
||||
self.0.data.write().unwrap().canonical_username = username;
|
||||
self.0.data.write().unwrap().canonical_username = username.clone();
|
||||
*self.0.rx_connection.lock().unwrap() = Some(connection.clone());
|
||||
*self.0.tx_connection.lock().unwrap() = Some(connection);
|
||||
|
||||
eprintln!("Authenticated !");
|
||||
Ok(())
|
||||
|
||||
let reusable_credentials = Credentials {
|
||||
username: username,
|
||||
auth_type: welcome_data.get_reusable_auth_credentials_type(),
|
||||
auth_data: welcome_data.get_reusable_auth_credentials().to_owned(),
|
||||
};
|
||||
|
||||
Ok(reusable_credentials)
|
||||
}
|
||||
|
||||
0xad => {
|
||||
|
|
Loading…
Reference in a new issue