Remove the need for a application key.

This commit is contained in:
Paul Lietar 2016-07-06 08:32:43 +01:00
parent e9aad29ae4
commit 4cca541339
5 changed files with 6 additions and 56 deletions

View file

@ -70,5 +70,4 @@ with-tremor = ["tremor"]
facebook = ["hyper/ssl", "openssl"] facebook = ["hyper/ssl", "openssl"]
portaudio-backend = ["portaudio"] portaudio-backend = ["portaudio"]
pulseaudio-backend= ["libpulse-sys"] pulseaudio-backend= ["libpulse-sys"]
static-appkey = []
default = ["with-syntex", "portaudio-backend"] default = ["with-syntex", "portaudio-backend"]

View file

@ -37,7 +37,7 @@ cargo build --release
A sample program implementing a headless Spotify Connect receiver is provided. A sample program implementing a headless Spotify Connect receiver is provided.
Once you've built *librespot*, run it using : Once you've built *librespot*, run it using :
```shell ```shell
target/release/librespot --appkey APPKEY --username USERNAME --cache CACHEDIR --name DEVICENAME target/release/librespot --username USERNAME --cache CACHEDIR --name DEVICENAME
``` ```
## Discovery mode ## Discovery mode
@ -49,7 +49,7 @@ For that, simply omit the `--username` argument.
```shell ```shell
cargo build --release --features facebook cargo build --release --features facebook
target/release/librespot --appkey APPKEY --cache CACHEDIR --name DEVICENAME --facebook target/release/librespot --cache CACHEDIR --name DEVICENAME --facebook
``` ```
This will print a link to the console, which must be visited on the same computer *librespot* is running on. This will print a link to the console, which must be visited on the same computer *librespot* is running on.
@ -78,8 +78,8 @@ cargo build --no-default-features --features "nightly portaudio-backend"
This produces better compilation error messages than with the default configuration. This produces better compilation error messages than with the default configuration.
## Disclaimer ## Disclaimer
Using this code to connect to Spotify's API is probably forbidden by them, and Using this code to connect to Spotify's API is probably forbidden by them.
might result in your application key getting banned. Use at your own risk Use at your own risk.
## Contact ## Contact
Come and hang out on gitter if you need help or want to offer some. Come and hang out on gitter if you need help or want to offer some.

View file

@ -60,11 +60,6 @@ pub mod version {
} }
} }
#[cfg(feature = "static-appkey")]
static APPKEY: Option<&'static [u8]> = Some(include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/spotify_appkey.key")));
#[cfg(not(feature = "static-appkey"))]
static APPKEY: Option<&'static [u8]> = None;
#[cfg(feature = "with-syntex")] #[cfg(feature = "with-syntex")]
include!(concat!(env!("OUT_DIR"), "/lib.rs")); include!(concat!(env!("OUT_DIR"), "/lib.rs"));

View file

@ -1,9 +1,7 @@
use getopts; use getopts;
use rpassword; use rpassword;
use std::fs::File; use std::io::{stdout, Write};
use std::io::{stdout, Read, Write};
use std::path::PathBuf; use std::path::PathBuf;
use std::path::Path;
use std::process::exit; use std::process::exit;
use audio_backend::{BACKENDS, Sink}; use audio_backend::{BACKENDS, Sink};
@ -12,7 +10,6 @@ use cache::{Cache, DefaultCache, NoCache};
use player::Player; use player::Player;
use session::{Bitrate, Config, Session}; use session::{Bitrate, Config, Session};
use version; use version;
use APPKEY;
pub fn find_backend(name: Option<&str>) -> &'static (Fn() -> Box<Sink> + Send + Sync) { pub fn find_backend(name: Option<&str>) -> &'static (Fn() -> Box<Sink> + Send + Sync) {
match name { match name {
@ -37,27 +34,10 @@ pub fn find_backend(name: Option<&str>) -> &'static (Fn() -> Box<Sink> + Send +
} }
} }
pub fn load_appkey<P: AsRef<Path>>(path: Option<P>) -> Vec<u8> {
path.map(|path| {
let mut file = File::open(path).expect("Could not open app key.");
let mut data = Vec::new();
file.read_to_end(&mut data).unwrap();
data
}).or_else(|| APPKEY.map(ToOwned::to_owned)).unwrap()
}
pub fn add_session_arguments(opts: &mut getopts::Options) { pub fn add_session_arguments(opts: &mut getopts::Options) {
opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE") opts.optopt("c", "cache", "Path to a directory where files will be cached.", "CACHE")
.reqopt("n", "name", "Device name", "NAME") .reqopt("n", "name", "Device name", "NAME")
.optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE"); .optopt("b", "bitrate", "Bitrate (96, 160 or 320). Defaults to 160", "BITRATE");
if APPKEY.is_none() {
opts.reqopt("a", "appkey", "Path to a spotify appkey", "APPKEY");
} else {
opts.optopt("a", "appkey", "Path to a spotify appkey", "APPKEY");
};
} }
pub fn add_authentication_arguments(opts: &mut getopts::Options) { pub fn add_authentication_arguments(opts: &mut getopts::Options) {
@ -79,7 +59,6 @@ pub fn create_session(matches: &getopts::Matches) -> Session {
version::commit_date(), version::commit_date(),
version::short_now()); version::short_now());
let appkey = load_appkey(matches.opt_str("a"));
let name = matches.opt_str("n").unwrap(); let name = matches.opt_str("n").unwrap();
let bitrate = match matches.opt_str("b").as_ref().map(String::as_ref) { let bitrate = match matches.opt_str("b").as_ref().map(String::as_ref) {
None => Bitrate::Bitrate160, // default value None => Bitrate::Bitrate160, // default value
@ -98,7 +77,6 @@ pub fn create_session(matches: &getopts::Matches) -> Session {
}).unwrap_or_else(|| Box::new(NoCache) as Box<Cache + Send + Sync>); }).unwrap_or_else(|| Box::new(NoCache) as Box<Cache + Send + Sync>);
let config = Config { let config = Config {
application_key: appkey,
user_agent: version::version_string(), user_agent: version::version_string(),
device_name: name, device_name: name,
bitrate: bitrate, bitrate: bitrate,

View file

@ -36,7 +36,6 @@ pub enum Bitrate {
} }
pub struct Config { pub struct Config {
pub application_key: Vec<u8>,
pub user_agent: String, pub user_agent: String,
pub device_name: String, pub device_name: String,
pub bitrate: Bitrate, pub bitrate: Bitrate,
@ -102,33 +101,19 @@ impl Session {
let request = protobuf_init!(protocol::keyexchange::ClientHello::new(), { let request = protobuf_init!(protocol::keyexchange::ClientHello::new(), {
build_info => { build_info => {
product: protocol::keyexchange::Product::PRODUCT_LIBSPOTIFY_EMBEDDED, product: protocol::keyexchange::Product::PRODUCT_PARTNER,
platform: protocol::keyexchange::Platform::PLATFORM_LINUX_X86, platform: protocol::keyexchange::Platform::PLATFORM_LINUX_X86,
version: 0x10800000000, version: 0x10800000000,
}, },
/*
fingerprints_supported => [
protocol::keyexchange::Fingerprint::FINGERPRINT_GRAIN
],
*/
cryptosuites_supported => [ cryptosuites_supported => [
protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON, protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON,
//protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_RC4_SHA1_HMAC
], ],
/*
powschemes_supported => [
protocol::keyexchange::Powscheme::POW_HASH_CASH
],
*/
login_crypto_hello.diffie_hellman => { login_crypto_hello.diffie_hellman => {
gc: local_keys.public_key(), gc: local_keys.public_key(),
server_keys_known: 1, server_keys_known: 1,
}, },
client_nonce: util::rand_vec(&mut thread_rng(), 0x10), client_nonce: util::rand_vec(&mut thread_rng(), 0x10),
padding: vec![0x1e], padding: vec![0x1e],
feature_set => {
autoupdate2: true,
}
}); });
let init_client_packet = connection.send_packet_prefix(&[0, 4], let init_client_packet = connection.send_packet_prefix(&[0, 4],
@ -196,13 +181,6 @@ impl Session {
device_id: self.device_id().to_owned(), device_id: self.device_id().to_owned(),
}, },
version_string: version::version_string(), version_string: version::version_string(),
appkey => {
version: self.config().application_key[0] as u32,
devkey: self.config().application_key[0x1..0x81].to_vec(),
signature: self.config().application_key[0x81..0x141].to_vec(),
useragent: self.config().user_agent.clone(),
callback_hash: vec![0; 20],
}
}); });
let mut connection = self.connect(); let mut connection = self.connect();