session.rs 11 KB

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