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:
Paul Lietar 2016-03-13 22:35:09 +00:00
parent 39af43728a
commit 4b73f83c5e
4 changed files with 91 additions and 17 deletions

15
Cargo.lock generated
View file

@ -71,6 +71,11 @@ name = "byteorder"
version = "0.4.2" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "chrono" name = "chrono"
version = "0.2.20" version = "0.2.20"
@ -319,7 +324,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "portaudio" name = "portaudio"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/mvdnes/portaudio-rs#840b1096780c069fd54b4a425bcfebec99ef9c1a" source = "git+https://github.com/mvdnes/portaudio-rs#0b228f54a16814c52ba1ef449ac439af59f8cab0"
dependencies = [ dependencies = [
"bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -329,7 +334,7 @@ dependencies = [
[[package]] [[package]]
name = "portaudio_sys" name = "portaudio_sys"
version = "0.1.1" version = "0.1.1"
source = "git+https://github.com/mvdnes/portaudio-rs#840b1096780c069fd54b4a425bcfebec99ef9c1a" source = "git+https://github.com/mvdnes/portaudio-rs#0b228f54a16814c52ba1ef449ac439af59f8cab0"
dependencies = [ dependencies = [
"libc 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -441,7 +446,7 @@ name = "shannon"
version = "0.1.1" version = "0.1.1"
source = "git+https://github.com/plietar/rust-shannon#7000b3e49a53daaa890727ba2b2bd5a43cc4ffef" source = "git+https://github.com/plietar/rust-shannon#7000b3e49a53daaa890727ba2b2bd5a43cc4ffef"
dependencies = [ 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)", "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)", "shannon-sys 0.1.0 (git+https://github.com/plietar/rust-shannon)",
] ]
@ -555,7 +560,7 @@ name = "tremor"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/plietar/rust-tremor#5ced876f3cffb041fcf31238da7f3273178029fe" source = "git+https://github.com/plietar/rust-tremor#5ced876f3cffb041fcf31238da7f3273178029fe"
dependencies = [ 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)", "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" source = "git+https://github.com/plietar/rust-tremor#5ced876f3cffb041fcf31238da7f3273178029fe"
dependencies = [ dependencies = [
"gcc 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "ogg-sys 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View file

@ -7,17 +7,29 @@ use crypto::mac::Mac;
use crypto::pbkdf2::pbkdf2; use crypto::pbkdf2::pbkdf2;
use crypto::sha1::Sha1; use crypto::sha1::Sha1;
use protobuf::ProtobufEnum; use protobuf::ProtobufEnum;
use std::io::{self, Read}; use std::io::{self, Read, Write};
use rustc_serialize::base64::FromBase64; use std::fs::File;
use std::path::Path;
use rustc_serialize::base64::{self, FromBase64, ToBase64};
use rustc_serialize::json;
use protocol::authentication::AuthenticationType; use protocol::authentication::AuthenticationType;
#[derive(Debug, Clone)]
pub struct Credentials { pub struct Credentials {
pub username: String, pub username: String,
pub auth_type: AuthenticationType, pub auth_type: AuthenticationType,
pub auth_data: Vec<u8>, 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 { impl Credentials {
pub fn with_password(username: String, password: String) -> Credentials { pub fn with_password(username: String, password: String) -> Credentials {
Credentials { Credentials {
@ -108,4 +120,47 @@ impl Credentials {
auth_data: auth_data, 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(),
}
}
}

View file

@ -55,7 +55,7 @@ fn main() {
}; };
let username = matches.opt_str("u"); 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 name = matches.opt_str("n").unwrap();
let credentials = username.map(|u| { let credentials = username.map(|u| {
@ -84,23 +84,30 @@ fn main() {
application_key: appkey, application_key: appkey,
user_agent: version_string(), user_agent: version_string(),
device_name: name, device_name: name,
cache_location: PathBuf::from(cache_location), cache_location: cache_location.clone(),
bitrate: bitrate, bitrate: bitrate,
}; };
let session = Session::new(config); 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()); let mut discovery = DiscoveryManager::new(session.clone());
discovery.run() 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 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()); thread::spawn(move || spirc.run());
loop { loop {

View file

@ -180,7 +180,7 @@ impl Session {
&recv_key) &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(), { let packet = protobuf_init!(protocol::authentication::ClientResponseEncrypted::new(), {
login_credentials => { login_credentials => {
username: credentials.username, username: credentials.username,
@ -213,12 +213,19 @@ impl Session {
protobuf::parse_from_bytes(&data).unwrap(); protobuf::parse_from_bytes(&data).unwrap();
let username = welcome_data.get_canonical_username().to_owned(); 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.rx_connection.lock().unwrap() = Some(connection.clone());
*self.0.tx_connection.lock().unwrap() = Some(connection); *self.0.tx_connection.lock().unwrap() = Some(connection);
eprintln!("Authenticated !"); 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 => { 0xad => {