session.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. use crypto::digest::Digest;
  2. use crypto::sha1::Sha1;
  3. use crypto::hmac::Hmac;
  4. use crypto::mac::Mac;
  5. use eventual;
  6. use eventual::Future;
  7. use eventual::Async;
  8. use protobuf::{self, Message};
  9. use rand::thread_rng;
  10. use rand::Rng;
  11. use std::io::{Read, Write, Cursor};
  12. use std::result::Result;
  13. use std::sync::{Mutex, RwLock, Arc, mpsc};
  14. use album_cover::AlbumCover;
  15. use apresolve::apresolve;
  16. use audio_key::{AudioKeyManager, AudioKey, AudioKeyError};
  17. use audio_file::AudioFile;
  18. use authentication::Credentials;
  19. use cache::Cache;
  20. use connection::{self, PlainConnection, CipherConnection};
  21. use diffie_hellman::DHLocalKeys;
  22. use mercury::{MercuryManager, MercuryRequest, MercuryResponse};
  23. use metadata::{MetadataManager, MetadataRef, MetadataTrait};
  24. use protocol;
  25. use stream::StreamManager;
  26. use util::{self, SpotifyId, FileId, ReadSeek};
  27. use version;
  28. use stream;
  29. pub enum Bitrate {
  30. Bitrate96,
  31. Bitrate160,
  32. Bitrate320,
  33. }
  34. pub struct Config {
  35. pub application_key: Vec<u8>,
  36. pub user_agent: String,
  37. pub device_name: String,
  38. pub bitrate: Bitrate,
  39. }
  40. pub struct SessionData {
  41. country: String,
  42. canonical_username: String,
  43. }
  44. pub struct SessionInternal {
  45. config: Config,
  46. device_id: String,
  47. data: RwLock<SessionData>,
  48. cache: Box<Cache + Send + Sync>,
  49. mercury: Mutex<MercuryManager>,
  50. metadata: Mutex<MetadataManager>,
  51. stream: Mutex<StreamManager>,
  52. audio_key: Mutex<AudioKeyManager>,
  53. rx_connection: Mutex<Option<CipherConnection>>,
  54. tx_connection: Mutex<Option<CipherConnection>>,
  55. }
  56. #[derive(Clone)]
  57. pub struct Session(pub Arc<SessionInternal>);
  58. impl Session {
  59. pub fn new(config: Config, cache: Box<Cache + Send + Sync>) -> Session {
  60. let device_id = {
  61. let mut h = Sha1::new();
  62. h.input_str(&config.device_name);
  63. h.result_str()
  64. };
  65. Session(Arc::new(SessionInternal {
  66. config: config,
  67. device_id: device_id,
  68. data: RwLock::new(SessionData {
  69. country: String::new(),
  70. canonical_username: String::new(),
  71. }),
  72. rx_connection: Mutex::new(None),
  73. tx_connection: Mutex::new(None),
  74. cache: cache,
  75. mercury: Mutex::new(MercuryManager::new()),
  76. metadata: Mutex::new(MetadataManager::new()),
  77. stream: Mutex::new(StreamManager::new()),
  78. audio_key: Mutex::new(AudioKeyManager::new()),
  79. }))
  80. }
  81. fn connect(&self) -> CipherConnection {
  82. let local_keys = DHLocalKeys::random(&mut thread_rng());
  83. let aps = apresolve().unwrap();
  84. let ap = thread_rng().choose(&aps).expect("No APs found");
  85. info!("Connecting to AP {}", ap);
  86. let mut connection = PlainConnection::connect(ap).unwrap();
  87. let request = protobuf_init!(protocol::keyexchange::ClientHello::new(), {
  88. build_info => {
  89. product: protocol::keyexchange::Product::PRODUCT_LIBSPOTIFY_EMBEDDED,
  90. platform: protocol::keyexchange::Platform::PLATFORM_LINUX_X86,
  91. version: 0x10800000000,
  92. },
  93. /*
  94. fingerprints_supported => [
  95. protocol::keyexchange::Fingerprint::FINGERPRINT_GRAIN
  96. ],
  97. */
  98. cryptosuites_supported => [
  99. protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON,
  100. //protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_RC4_SHA1_HMAC
  101. ],
  102. /*
  103. powschemes_supported => [
  104. protocol::keyexchange::Powscheme::POW_HASH_CASH
  105. ],
  106. */
  107. login_crypto_hello.diffie_hellman => {
  108. gc: local_keys.public_key(),
  109. server_keys_known: 1,
  110. },
  111. client_nonce: util::rand_vec(&mut thread_rng(), 0x10),
  112. padding: vec![0x1e],
  113. feature_set => {
  114. autoupdate2: true,
  115. }
  116. });
  117. let init_client_packet = connection.send_packet_prefix(&[0, 4],
  118. &request.write_to_bytes().unwrap())
  119. .unwrap();
  120. let init_server_packet = connection.recv_packet().unwrap();
  121. let response: protocol::keyexchange::APResponseMessage =
  122. protobuf::parse_from_bytes(&init_server_packet[4..]).unwrap();
  123. let remote_key = response.get_challenge()
  124. .get_login_crypto_challenge()
  125. .get_diffie_hellman()
  126. .get_gs();
  127. let shared_secret = local_keys.shared_secret(remote_key);
  128. let (challenge, send_key, recv_key) = {
  129. let mut data = Vec::with_capacity(0x64);
  130. let mut mac = Hmac::new(Sha1::new(), &shared_secret);
  131. for i in 1..6 {
  132. mac.input(&init_client_packet);
  133. mac.input(&init_server_packet);
  134. mac.input(&[i]);
  135. data.write(&mac.result().code()).unwrap();
  136. mac.reset();
  137. }
  138. mac = Hmac::new(Sha1::new(), &data[..0x14]);
  139. mac.input(&init_client_packet);
  140. mac.input(&init_server_packet);
  141. (mac.result().code().to_vec(),
  142. data[0x14..0x34].to_vec(),
  143. data[0x34..0x54].to_vec())
  144. };
  145. let packet = protobuf_init!(protocol::keyexchange::ClientResponsePlaintext::new(), {
  146. login_crypto_response.diffie_hellman => {
  147. hmac: challenge
  148. },
  149. pow_response => {},
  150. crypto_response => {},
  151. });
  152. connection.send_packet(&packet.write_to_bytes().unwrap()).unwrap();
  153. CipherConnection::new(connection.into_stream(),
  154. &send_key,
  155. &recv_key)
  156. }
  157. pub fn login(&self, credentials: Credentials) -> Result<Credentials, ()> {
  158. let packet = protobuf_init!(protocol::authentication::ClientResponseEncrypted::new(), {
  159. login_credentials => {
  160. username: credentials.username,
  161. typ: credentials.auth_type,
  162. auth_data: credentials.auth_data,
  163. },
  164. system_info => {
  165. cpu_family: protocol::authentication::CpuFamily::CPU_UNKNOWN,
  166. os: protocol::authentication::Os::OS_UNKNOWN,
  167. system_information_string: "librespot".to_owned(),
  168. device_id: self.device_id().to_owned(),
  169. },
  170. version_string: version::version_string(),
  171. appkey => {
  172. version: self.config().application_key[0] as u32,
  173. devkey: self.config().application_key[0x1..0x81].to_vec(),
  174. signature: self.config().application_key[0x81..0x141].to_vec(),
  175. useragent: self.config().user_agent.clone(),
  176. callback_hash: vec![0; 20],
  177. }
  178. });
  179. let mut connection = self.connect();
  180. connection.send_packet(0xab, &packet.write_to_bytes().unwrap()).unwrap();
  181. let (cmd, data) = connection.recv_packet().unwrap();
  182. match cmd {
  183. 0xac => {
  184. let welcome_data: protocol::authentication::APWelcome =
  185. protobuf::parse_from_bytes(&data).unwrap();
  186. let username = welcome_data.get_canonical_username().to_owned();
  187. self.0.data.write().unwrap().canonical_username = username.clone();
  188. *self.0.rx_connection.lock().unwrap() = Some(connection.clone());
  189. *self.0.tx_connection.lock().unwrap() = Some(connection);
  190. info!("Authenticated !");
  191. let reusable_credentials = Credentials {
  192. username: username,
  193. auth_type: welcome_data.get_reusable_auth_credentials_type(),
  194. auth_data: welcome_data.get_reusable_auth_credentials().to_owned(),
  195. };
  196. self.0.cache.put_credentials(&reusable_credentials);
  197. Ok(reusable_credentials)
  198. }
  199. 0xad => {
  200. let msg: protocol::keyexchange::APLoginFailed =
  201. protobuf::parse_from_bytes(&data).unwrap();
  202. error!("Authentication failed, {:?}", msg);
  203. Err(())
  204. }
  205. _ => {
  206. error!("Unexpected message {:x}", cmd);
  207. Err(())
  208. }
  209. }
  210. }
  211. pub fn poll(&self) {
  212. let (cmd, data) = self.recv();
  213. match cmd {
  214. 0x4 => self.send_packet(0x49, &data).unwrap(),
  215. 0x4a => (),
  216. 0x9 | 0xa => self.0.stream.lock().unwrap().handle(cmd, data, self),
  217. 0xd | 0xe => self.0.audio_key.lock().unwrap().handle(cmd, data, self),
  218. 0x1b => {
  219. self.0.data.write().unwrap().country = String::from_utf8(data).unwrap();
  220. }
  221. 0xb2...0xb6 => self.0.mercury.lock().unwrap().handle(cmd, data, self),
  222. _ => (),
  223. }
  224. }
  225. pub fn recv(&self) -> (u8, Vec<u8>) {
  226. self.0.rx_connection.lock().unwrap().as_mut().unwrap().recv_packet().unwrap()
  227. }
  228. pub fn send_packet(&self, cmd: u8, data: &[u8]) -> connection::Result<()> {
  229. self.0.tx_connection.lock().unwrap().as_mut().unwrap().send_packet(cmd, data)
  230. }
  231. pub fn audio_key(&self, track: SpotifyId, file_id: FileId) -> Future<AudioKey, AudioKeyError> {
  232. self.0.cache
  233. .get_audio_key(track, file_id)
  234. .map(Future::of)
  235. .unwrap_or_else(|| {
  236. let self_ = self.clone();
  237. self.0.audio_key.lock().unwrap()
  238. .request(self, track, file_id)
  239. .map(move |key| {
  240. self_.0.cache.put_audio_key(track, file_id, key);
  241. key
  242. })
  243. })
  244. }
  245. pub fn audio_file(&self, file_id: FileId) -> Box<ReadSeek> {
  246. self.0.cache
  247. .get_file(file_id)
  248. .unwrap_or_else(|| {
  249. let (audio_file, complete_rx) = AudioFile::new(self, file_id);
  250. let self_ = self.clone();
  251. complete_rx.map(move |mut complete_file| {
  252. self_.0.cache.put_file(file_id, &mut complete_file)
  253. }).fire();
  254. Box::new(audio_file.await().unwrap())
  255. })
  256. }
  257. pub fn album_cover(&self, file_id: FileId) -> eventual::Future<Vec<u8>, ()> {
  258. self.0.cache
  259. .get_file(file_id)
  260. .map(|mut f| {
  261. let mut data = Vec::new();
  262. f.read_to_end(&mut data).unwrap();
  263. Future::of(data)
  264. })
  265. .unwrap_or_else(|| {
  266. let self_ = self.clone();
  267. AlbumCover::get(file_id, self)
  268. .map(move |data| {
  269. self_.0.cache.put_file(file_id, &mut Cursor::new(&data));
  270. data
  271. })
  272. })
  273. }
  274. pub fn stream(&self, handler: Box<stream::Handler>) {
  275. self.0.stream.lock().unwrap().create(handler, self)
  276. }
  277. pub fn metadata<T: MetadataTrait>(&self, id: SpotifyId) -> MetadataRef<T> {
  278. self.0.metadata.lock().unwrap().get(self, id)
  279. }
  280. pub fn mercury(&self, req: MercuryRequest) -> Future<MercuryResponse, ()> {
  281. self.0.mercury.lock().unwrap().request(self, req)
  282. }
  283. pub fn mercury_sub(&self, uri: String) -> mpsc::Receiver<MercuryResponse> {
  284. self.0.mercury.lock().unwrap().subscribe(self, uri)
  285. }
  286. pub fn cache(&self) -> &Cache {
  287. self.0.cache.as_ref()
  288. }
  289. pub fn config(&self) -> &Config {
  290. &self.0.config
  291. }
  292. pub fn username(&self) -> String {
  293. self.0.data.read().unwrap().canonical_username.clone()
  294. }
  295. pub fn country(&self) -> String {
  296. self.0.data.read().unwrap().country.clone()
  297. }
  298. pub fn device_id(&self) -> &str {
  299. &self.0.device_id
  300. }
  301. }
  302. pub trait PacketHandler {
  303. fn handle(&mut self, cmd: u8, data: Vec<u8>, session: &Session);
  304. }