diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 758025a1..e64e35a5 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -108,7 +108,7 @@ fn initial_state() -> State { fn initial_device_state(config: ConnectConfig) -> DeviceState { { let mut msg = DeviceState::new(); - msg.set_sw_version(version::VERSION_STRING.to_string()); + msg.set_sw_version(version::SEMVER.to_string()); msg.set_is_active(false); msg.set_can_play(true); msg.set_volume(0); diff --git a/core/src/connection/handshake.rs b/core/src/connection/handshake.rs index 7194f0f4..3659ab82 100644 --- a/core/src/connection/handshake.rs +++ b/core/src/connection/handshake.rs @@ -3,6 +3,7 @@ use hmac::{Hmac, Mac, NewMac}; use protobuf::{self, Message}; use rand::{thread_rng, RngCore}; use sha1::Sha1; +use std::env::consts::ARCH; use std::io; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use tokio_util::codec::{Decoder, Framed}; @@ -10,7 +11,9 @@ use tokio_util::codec::{Decoder, Framed}; use super::codec::ApCodec; use crate::diffie_hellman::DhLocalKeys; use crate::protocol; -use crate::protocol::keyexchange::{APResponseMessage, ClientHello, ClientResponsePlaintext}; +use crate::protocol::keyexchange::{ + APResponseMessage, ClientHello, ClientResponsePlaintext, Platform, ProductFlags, +}; pub async fn handshake( mut connection: T, @@ -42,13 +45,51 @@ where let mut client_nonce = vec![0; 0x10]; thread_rng().fill_bytes(&mut client_nonce); + let platform = match std::env::consts::OS { + "android" => Platform::PLATFORM_ANDROID_ARM, + "freebsd" | "netbsd" | "openbsd" => match ARCH { + "x86_64" => Platform::PLATFORM_FREEBSD_X86_64, + _ => Platform::PLATFORM_FREEBSD_X86, + }, + "ios" => match ARCH { + "arm64" => Platform::PLATFORM_IPHONE_ARM64, + _ => Platform::PLATFORM_IPHONE_ARM, + }, + "linux" => match ARCH { + "arm" | "arm64" => Platform::PLATFORM_LINUX_ARM, + "blackfin" => Platform::PLATFORM_LINUX_BLACKFIN, + "mips" => Platform::PLATFORM_LINUX_MIPS, + "sh" => Platform::PLATFORM_LINUX_SH, + "x86_64" => Platform::PLATFORM_LINUX_X86_64, + _ => Platform::PLATFORM_LINUX_X86, + }, + "macos" => match ARCH { + "ppc" | "ppc64" => Platform::PLATFORM_OSX_PPC, + "x86_64" => Platform::PLATFORM_OSX_X86_64, + _ => Platform::PLATFORM_OSX_X86, + }, + "windows" => match ARCH { + "arm" => Platform::PLATFORM_WINDOWS_CE_ARM, + "x86_64" => Platform::PLATFORM_WIN32_X86_64, + _ => Platform::PLATFORM_WIN32_X86, + }, + _ => Platform::PLATFORM_LINUX_X86, + }; + + #[cfg(debug_assertions)] + const PRODUCT_FLAGS: ProductFlags = ProductFlags::PRODUCT_FLAG_DEV_BUILD; + #[cfg(not(debug_assertions))] + const PRODUCT_FLAGS: ProductFlags = ProductFlags::PRODUCT_FLAG_NONE; + let mut packet = ClientHello::new(); packet .mut_build_info() - .set_product(protocol::keyexchange::Product::PRODUCT_PARTNER); + .set_product(protocol::keyexchange::Product::PRODUCT_LIBSPOTIFY); packet .mut_build_info() - .set_platform(protocol::keyexchange::Platform::PLATFORM_LINUX_X86); + .mut_product_flags() + .push(PRODUCT_FLAGS); + packet.mut_build_info().set_platform(platform); packet.mut_build_info().set_version(999999999); packet .mut_cryptosuites_supported() diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index 472109e6..29a33296 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -71,6 +71,29 @@ pub async fn authenticate( ) -> Result { use crate::protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os}; + let cpu_family = match std::env::consts::ARCH { + "blackfin" => CpuFamily::CPU_BLACKFIN, + "arm" | "arm64" => CpuFamily::CPU_ARM, + "ia64" => CpuFamily::CPU_IA64, + "mips" => CpuFamily::CPU_MIPS, + "ppc" => CpuFamily::CPU_PPC, + "ppc64" => CpuFamily::CPU_PPC_64, + "sh" => CpuFamily::CPU_SH, + "x86" => CpuFamily::CPU_X86, + "x86_64" => CpuFamily::CPU_X86_64, + _ => CpuFamily::CPU_UNKNOWN, + }; + + let os = match std::env::consts::OS { + "android" => Os::OS_ANDROID, + "freebsd" | "netbsd" | "openbsd" => Os::OS_FREEBSD, + "ios" => Os::OS_IPHONE, + "linux" => Os::OS_LINUX, + "macos" => Os::OS_OSX, + "windows" => Os::OS_WINDOWS, + _ => Os::OS_UNKNOWN, + }; + let mut packet = ClientResponseEncrypted::new(); packet .mut_login_credentials() @@ -81,21 +104,19 @@ pub async fn authenticate( 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_cpu_family(cpu_family); + packet.mut_system_info().set_os(os); packet .mut_system_info() .set_system_information_string(format!( - "librespot_{}_{}", + "librespot-{}-{}", version::SHA_SHORT, version::BUILD_ID )); packet .mut_system_info() .set_device_id(device_id.to_string()); - packet.set_version_string(version::VERSION_STRING.to_string()); + packet.set_version_string(format!("librespot {}", version::SEMVER)); let cmd = PacketType::Login; let data = packet.write_to_bytes().unwrap(); diff --git a/core/src/http_client.rs b/core/src/http_client.rs index 21a6c0a6..157fbaef 100644 --- a/core/src/http_client.rs +++ b/core/src/http_client.rs @@ -5,9 +5,12 @@ use hyper::header::InvalidHeaderValue; use hyper::{Body, Client, Request, Response, StatusCode}; use hyper_proxy::{Intercept, Proxy, ProxyConnector}; use hyper_rustls::HttpsConnector; +use std::env::consts::OS; use thiserror::Error; use url::Url; +use crate::version; + pub struct HttpClient { proxy: Option, } @@ -50,11 +53,29 @@ impl HttpClient { let connector = HttpsConnector::with_native_roots(); + let spotify_version = match OS { + "android" | "ios" => "8.6.84", + _ => "117300517", + }; + + let spotify_platform = match OS { + "android" => "Android/31", + "ios" => "iOS/15.1.1", + "macos" => "OSX/0", + "windows" => "Win32/0", + _ => "Linux/0", + }; + let headers_mut = req.headers_mut(); headers_mut.insert( "User-Agent", // Some features like lyrics are version-gated and require an official version string. - HeaderValue::from_str("Spotify/8.6.80 iOS/13.5 (iPhone11,2)")?, + HeaderValue::from_str(&format!( + "Spotify/{} {} ({})", + spotify_version, + spotify_platform, + version::VERSION_STRING + ))?, ); let response = if let Some(url) = &self.proxy { diff --git a/discovery/src/server.rs b/discovery/src/server.rs index 57f5bf46..a82f90c0 100644 --- a/discovery/src/server.rs +++ b/discovery/src/server.rs @@ -57,7 +57,7 @@ impl RequestHandler { "status": 101, "statusString": "ERROR-OK", "spotifyError": 0, - "version": "2.7.1", + "version": crate::core::version::SEMVER, "deviceID": (self.config.device_id), "remoteName": (self.config.name), "activeUser": "",