diff --git a/Cargo.lock b/Cargo.lock index eb5d0cff..4c807534 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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)", ] diff --git a/src/authentication.rs b/src/authentication.rs index ce9d70ed..e6a80642 100644 --- a/src/authentication.rs +++ b/src/authentication.rs @@ -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, } +#[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(mut reader: R) -> Credentials { + let mut contents = String::new(); + reader.read_to_string(&mut contents).unwrap(); + + json::decode::(&contents).unwrap().into() + } + + pub fn from_file>(path: P) -> Credentials { + let file = File::open(path).unwrap(); + Credentials::from_reader(file) + } + + pub fn save_to_writer(&self, writer: &mut W) { + let contents = json::encode::(&self.clone().into()).unwrap(); + writer.write_all(contents.as_bytes()).unwrap(); + } + + pub fn save_to_file>(&self, path: P) { + let mut file = File::create(path).unwrap(); + self.save_to_writer(&mut file) + } } + +impl From 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 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(), + } + } +} + diff --git a/src/main.rs b/src/main.rs index 4eafa1e8..959108c6 100644 --- a/src/main.rs +++ b/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 { diff --git a/src/session.rs b/src/session.rs index 37dab6fd..331e4b00 100644 --- a/src/session.rs +++ b/src/session.rs @@ -180,7 +180,7 @@ impl Session { &recv_key) } - pub fn login(&self, credentials: Credentials) -> Result<(), ()> { + pub fn login(&self, credentials: Credentials) -> Result { 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 => {