mod.rs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. mod codec;
  2. mod handshake;
  3. pub use self::codec::APCodec;
  4. pub use self::handshake::handshake;
  5. use futures::{Future, Sink, Stream};
  6. use protobuf::{self, Message};
  7. use std::io;
  8. use std::net::ToSocketAddrs;
  9. use tokio_codec::Framed;
  10. use tokio_core::net::TcpStream;
  11. use tokio_core::reactor::Handle;
  12. use url::Url;
  13. use crate::authentication::Credentials;
  14. use crate::version;
  15. use crate::proxytunnel;
  16. pub type Transport = Framed<TcpStream, APCodec>;
  17. pub fn connect(
  18. addr: String,
  19. handle: &Handle,
  20. proxy: &Option<Url>,
  21. ) -> Box<dyn Future<Item = Transport, Error = io::Error>> {
  22. let (addr, connect_url) = match *proxy {
  23. Some(ref url) => {
  24. info!("Using proxy \"{}\"", url);
  25. (url.to_socket_addrs().unwrap().next().unwrap(), Some(addr))
  26. }
  27. None => (addr.to_socket_addrs().unwrap().next().unwrap(), None),
  28. };
  29. let socket = TcpStream::connect(&addr, handle);
  30. if let Some(connect_url) = connect_url {
  31. let connection = socket
  32. .and_then(move |socket| proxytunnel::connect(socket, &connect_url).and_then(handshake));
  33. Box::new(connection)
  34. } else {
  35. let connection = socket.and_then(handshake);
  36. Box::new(connection)
  37. }
  38. }
  39. pub fn authenticate(
  40. transport: Transport,
  41. credentials: Credentials,
  42. device_id: String,
  43. ) -> Box<dyn Future<Item = (Transport, Credentials), Error = io::Error>> {
  44. use crate::protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os};
  45. use crate::protocol::keyexchange::APLoginFailed;
  46. let mut packet = ClientResponseEncrypted::new();
  47. packet
  48. .mut_login_credentials()
  49. .set_username(credentials.username);
  50. packet
  51. .mut_login_credentials()
  52. .set_typ(credentials.auth_type);
  53. packet
  54. .mut_login_credentials()
  55. .set_auth_data(credentials.auth_data);
  56. packet
  57. .mut_system_info()
  58. .set_cpu_family(CpuFamily::CPU_UNKNOWN);
  59. packet.mut_system_info().set_os(Os::OS_UNKNOWN);
  60. packet
  61. .mut_system_info()
  62. .set_system_information_string(format!(
  63. "librespot_{}_{}",
  64. version::short_sha(),
  65. version::build_id()
  66. ));
  67. packet.mut_system_info().set_device_id(device_id);
  68. packet.set_version_string(version::version_string());
  69. let cmd = 0xab;
  70. let data = packet.write_to_bytes().unwrap();
  71. Box::new(
  72. transport
  73. .send((cmd, data))
  74. .and_then(|transport| transport.into_future().map_err(|(err, _stream)| err))
  75. .and_then(|(packet, transport)| match packet {
  76. Some((0xac, data)) => {
  77. let welcome_data: APWelcome =
  78. protobuf::parse_from_bytes(data.as_ref()).unwrap();
  79. let reusable_credentials = Credentials {
  80. username: welcome_data.get_canonical_username().to_owned(),
  81. auth_type: welcome_data.get_reusable_auth_credentials_type(),
  82. auth_data: welcome_data.get_reusable_auth_credentials().to_owned(),
  83. };
  84. Ok((transport, reusable_credentials))
  85. }
  86. Some((0xad, data)) => {
  87. let error_data: APLoginFailed =
  88. protobuf::parse_from_bytes(data.as_ref()).unwrap();
  89. panic!(
  90. "Authentication failed with reason: {:?}",
  91. error_data.get_error_code()
  92. )
  93. }
  94. Some((cmd, _)) => panic!("Unexpected packet {:?}", cmd),
  95. None => panic!("EOF"),
  96. }),
  97. )
  98. }