diff --git a/core/src/authentication.rs b/core/src/authentication.rs index 9109c7fb..b2b4f544 100644 --- a/core/src/authentication.rs +++ b/core/src/authentication.rs @@ -7,6 +7,7 @@ use sha1::{Digest, Sha1}; use std::io::{self, Read}; use crate::protocol::authentication::AuthenticationType; +use crate::protocol::keyexchange::{APLoginFailed, ErrorCode}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Credentials { @@ -164,3 +165,37 @@ pub fn get_credentials String>( (None, _, None) => None, } } + +error_chain! { + types { + AuthenticationError, AuthenticationErrorKind, AuthenticationResultExt, AuthenticationResult; + } + + foreign_links { + Io(::std::io::Error); + } + + errors { + BadCredentials { + description("Bad credentials") + display("Authentication failed with error: Bad credentials") + } + PremiumAccountRequired { + description("Premium account required") + display("Authentication failed with error: Premium account required") + } + } +} + +impl From for AuthenticationError { + fn from(login_failure: APLoginFailed) -> Self { + let error_code = login_failure.get_error_code(); + match error_code { + ErrorCode::BadCredentials => Self::from_kind(AuthenticationErrorKind::BadCredentials), + ErrorCode::PremiumAccountRequired => { + Self::from_kind(AuthenticationErrorKind::PremiumAccountRequired) + } + _ => format!("Authentication failed with error: {:?}", error_code).into(), + } + } +} diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index 72497795..ffc6d0f4 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -13,7 +13,7 @@ use tokio_core::net::TcpStream; use tokio_core::reactor::Handle; use url::Url; -use crate::authentication::Credentials; +use crate::authentication::{AuthenticationError, Credentials}; use crate::version; use crate::proxytunnel; @@ -66,7 +66,7 @@ pub fn authenticate( transport: Transport, credentials: Credentials, device_id: String, -) -> Box> { +) -> Box> { use crate::protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os}; use crate::protocol::keyexchange::APLoginFailed; @@ -101,6 +101,7 @@ pub fn authenticate( transport .send((cmd, data)) .and_then(|transport| transport.into_future().map_err(|(err, _stream)| err)) + .map_err(|io_err| io_err.into()) .and_then(|(packet, transport)| match packet { Some((0xac, data)) => { let welcome_data: APWelcome = @@ -118,10 +119,7 @@ pub fn authenticate( 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() - ) + Err(error_data.into()) } Some((cmd, _)) => panic!("Unexpected packet {:?}", cmd), diff --git a/core/src/session.rs b/core/src/session.rs index 4d86a02b..3754a000 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -19,6 +19,8 @@ use crate::config::SessionConfig; use crate::connection; use crate::mercury::MercuryManager; +pub use crate::authentication::{AuthenticationError, AuthenticationErrorKind}; + struct SessionData { country: String, time_delta: i64, @@ -53,16 +55,18 @@ impl Session { credentials: Credentials, cache: Option, handle: Handle, - ) -> Box> { + ) -> Box> { let access_point = apresolve_or_fallback::(&handle, &config.proxy, &config.ap_port); let handle_ = handle.clone(); let proxy = config.proxy.clone(); - let connection = access_point.and_then(move |addr| { - info!("Connecting to AP \"{}\"", addr); - connection::connect(addr, &handle_, &proxy) - }); + let connection = access_point + .and_then(move |addr| { + info!("Connecting to AP \"{}\"", addr); + connection::connect(addr, &handle_, &proxy) + }) + .map_err(|io_err| io_err.into()); let device_id = config.device_id.clone(); let authentication = connection.and_then(move |connection| { diff --git a/src/main.rs b/src/main.rs index 8444803e..4c57808f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,7 +3,7 @@ use futures::{Async, Future, Poll, Stream}; use log::{error, info, trace, warn}; use sha1::{Digest, Sha1}; use std::env; -use std::io::{self, stderr, Write}; +use std::io::{stderr, Write}; use std::mem; use std::path::Path; use std::process::exit; @@ -16,7 +16,7 @@ use url::Url; use librespot::core::authentication::{get_credentials, Credentials}; use librespot::core::cache::Cache; use librespot::core::config::{ConnectConfig, DeviceType, SessionConfig, VolumeCtrl}; -use librespot::core::session::Session; +use librespot::core::session::{AuthenticationError, Session}; use librespot::core::version; use librespot::connect::discovery::{discovery, DiscoveryStream}; @@ -436,7 +436,7 @@ struct Main { spirc: Option, spirc_task: Option, - connect: Box>, + connect: Box>, shutdown: bool, last_credentials: Option,