123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- mod codec;
- mod handshake;
- pub use self::codec::APCodec;
- pub use self::handshake::handshake;
- use futures::{Future, Sink, Stream};
- use protobuf::{self, Message};
- use std::io;
- use std::net::ToSocketAddrs;
- use tokio_codec::Framed;
- use tokio_core::net::TcpStream;
- use tokio_core::reactor::Handle;
- use url::Url;
- use crate::authentication::Credentials;
- use crate::version;
- use crate::proxytunnel;
- pub type Transport = Framed<TcpStream, APCodec>;
- pub fn connect(
- addr: String,
- handle: &Handle,
- proxy: &Option<Url>,
- ) -> Box<dyn Future<Item = Transport, Error = io::Error>> {
- let (addr, connect_url) = match *proxy {
- Some(ref url) => {
- info!("Using proxy \"{}\"", url);
- match url.to_socket_addrs().and_then(|mut iter| {
- iter.next().ok_or(io::Error::new(
- io::ErrorKind::NotFound,
- "Can't resolve proxy server address",
- ))
- }) {
- Ok(socket_addr) => (socket_addr, Some(addr)),
- Err(error) => return Box::new(futures::future::err(error)),
- }
- }
- None => {
- match addr.to_socket_addrs().and_then(|mut iter| {
- iter.next().ok_or(io::Error::new(
- io::ErrorKind::NotFound,
- "Can't resolve server address",
- ))
- }) {
- Ok(socket_addr) => (socket_addr, None),
- Err(error) => return Box::new(futures::future::err(error)),
- }
- }
- };
- let socket = TcpStream::connect(&addr, handle);
- if let Some(connect_url) = connect_url {
- let connection = socket
- .and_then(move |socket| proxytunnel::connect(socket, &connect_url).and_then(handshake));
- Box::new(connection)
- } else {
- let connection = socket.and_then(handshake);
- Box::new(connection)
- }
- }
- pub fn authenticate(
- transport: Transport,
- credentials: Credentials,
- device_id: String,
- ) -> Box<dyn Future<Item = (Transport, Credentials), Error = io::Error>> {
- use crate::protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os};
- use crate::protocol::keyexchange::APLoginFailed;
- let mut packet = ClientResponseEncrypted::new();
- packet
- .mut_login_credentials()
- .set_username(credentials.username);
- packet
- .mut_login_credentials()
- .set_typ(credentials.auth_type);
- packet
- .mut_login_credentials()
- .set_auth_data(credentials.auth_data);
- packet
- .mut_system_info()
- .set_cpu_family(CpuFamily::CPU_UNKNOWN);
- packet.mut_system_info().set_os(Os::OS_UNKNOWN);
- packet
- .mut_system_info()
- .set_system_information_string(format!(
- "librespot_{}_{}",
- version::short_sha(),
- version::build_id()
- ));
- packet.mut_system_info().set_device_id(device_id);
- packet.set_version_string(version::version_string());
- let cmd = 0xab;
- let data = packet.write_to_bytes().unwrap();
- Box::new(
- transport
- .send((cmd, data))
- .and_then(|transport| transport.into_future().map_err(|(err, _stream)| err))
- .and_then(|(packet, transport)| match packet {
- Some((0xac, data)) => {
- let welcome_data: APWelcome =
- protobuf::parse_from_bytes(data.as_ref()).unwrap();
- let reusable_credentials = Credentials {
- username: welcome_data.get_canonical_username().to_owned(),
- auth_type: welcome_data.get_reusable_auth_credentials_type(),
- auth_data: welcome_data.get_reusable_auth_credentials().to_owned(),
- };
- Ok((transport, reusable_credentials))
- }
- Some((0xad, data)) => {
- let error_data: APLoginFailed =
- protobuf::parse_from_bytes(data.as_ref()).unwrap();
- panic!(
- "Authentication failed with reason: {:?}",
- error_data.get_error_code()
- )
- }
- Some((cmd, _)) => panic!("Unexpected packet {:?}", cmd),
- None => panic!("EOF"),
- }),
- )
- }
|