Report actual CPU, OS, platform and librespot version

This commit is contained in:
Roderick van Domburg 2021-12-09 19:00:27 +01:00
parent f3bb679ab1
commit 4f51c1e810
No known key found for this signature in database
GPG key ID: A9EF5222A26F0451
5 changed files with 95 additions and 12 deletions

View file

@ -108,7 +108,7 @@ fn initial_state() -> State {
fn initial_device_state(config: ConnectConfig) -> DeviceState { fn initial_device_state(config: ConnectConfig) -> DeviceState {
{ {
let mut msg = DeviceState::new(); 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_is_active(false);
msg.set_can_play(true); msg.set_can_play(true);
msg.set_volume(0); msg.set_volume(0);

View file

@ -3,6 +3,7 @@ use hmac::{Hmac, Mac, NewMac};
use protobuf::{self, Message}; use protobuf::{self, Message};
use rand::{thread_rng, RngCore}; use rand::{thread_rng, RngCore};
use sha1::Sha1; use sha1::Sha1;
use std::env::consts::ARCH;
use std::io; use std::io;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio_util::codec::{Decoder, Framed}; use tokio_util::codec::{Decoder, Framed};
@ -10,7 +11,9 @@ use tokio_util::codec::{Decoder, Framed};
use super::codec::ApCodec; use super::codec::ApCodec;
use crate::diffie_hellman::DhLocalKeys; use crate::diffie_hellman::DhLocalKeys;
use crate::protocol; use crate::protocol;
use crate::protocol::keyexchange::{APResponseMessage, ClientHello, ClientResponsePlaintext}; use crate::protocol::keyexchange::{
APResponseMessage, ClientHello, ClientResponsePlaintext, Platform, ProductFlags,
};
pub async fn handshake<T: AsyncRead + AsyncWrite + Unpin>( pub async fn handshake<T: AsyncRead + AsyncWrite + Unpin>(
mut connection: T, mut connection: T,
@ -42,13 +45,51 @@ where
let mut client_nonce = vec![0; 0x10]; let mut client_nonce = vec![0; 0x10];
thread_rng().fill_bytes(&mut client_nonce); 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(); let mut packet = ClientHello::new();
packet packet
.mut_build_info() .mut_build_info()
.set_product(protocol::keyexchange::Product::PRODUCT_PARTNER); .set_product(protocol::keyexchange::Product::PRODUCT_LIBSPOTIFY);
packet packet
.mut_build_info() .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_build_info().set_version(999999999);
packet packet
.mut_cryptosuites_supported() .mut_cryptosuites_supported()

View file

@ -71,6 +71,29 @@ pub async fn authenticate(
) -> Result<Credentials, AuthenticationError> { ) -> Result<Credentials, AuthenticationError> {
use crate::protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os}; 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(); let mut packet = ClientResponseEncrypted::new();
packet packet
.mut_login_credentials() .mut_login_credentials()
@ -81,21 +104,19 @@ pub async fn authenticate(
packet packet
.mut_login_credentials() .mut_login_credentials()
.set_auth_data(credentials.auth_data); .set_auth_data(credentials.auth_data);
packet packet.mut_system_info().set_cpu_family(cpu_family);
.mut_system_info() packet.mut_system_info().set_os(os);
.set_cpu_family(CpuFamily::CPU_UNKNOWN);
packet.mut_system_info().set_os(Os::OS_UNKNOWN);
packet packet
.mut_system_info() .mut_system_info()
.set_system_information_string(format!( .set_system_information_string(format!(
"librespot_{}_{}", "librespot-{}-{}",
version::SHA_SHORT, version::SHA_SHORT,
version::BUILD_ID version::BUILD_ID
)); ));
packet packet
.mut_system_info() .mut_system_info()
.set_device_id(device_id.to_string()); .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 cmd = PacketType::Login;
let data = packet.write_to_bytes().unwrap(); let data = packet.write_to_bytes().unwrap();

View file

@ -5,9 +5,12 @@ use hyper::header::InvalidHeaderValue;
use hyper::{Body, Client, Request, Response, StatusCode}; use hyper::{Body, Client, Request, Response, StatusCode};
use hyper_proxy::{Intercept, Proxy, ProxyConnector}; use hyper_proxy::{Intercept, Proxy, ProxyConnector};
use hyper_rustls::HttpsConnector; use hyper_rustls::HttpsConnector;
use std::env::consts::OS;
use thiserror::Error; use thiserror::Error;
use url::Url; use url::Url;
use crate::version;
pub struct HttpClient { pub struct HttpClient {
proxy: Option<Url>, proxy: Option<Url>,
} }
@ -50,11 +53,29 @@ impl HttpClient {
let connector = HttpsConnector::with_native_roots(); 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(); let headers_mut = req.headers_mut();
headers_mut.insert( headers_mut.insert(
"User-Agent", "User-Agent",
// Some features like lyrics are version-gated and require an official version string. // 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 { let response = if let Some(url) = &self.proxy {

View file

@ -57,7 +57,7 @@ impl RequestHandler {
"status": 101, "status": 101,
"statusString": "ERROR-OK", "statusString": "ERROR-OK",
"spotifyError": 0, "spotifyError": 0,
"version": "2.7.1", "version": crate::core::version::SEMVER,
"deviceID": (self.config.device_id), "deviceID": (self.config.device_id),
"remoteName": (self.config.name), "remoteName": (self.config.name),
"activeUser": "", "activeUser": "",