diff --git a/protocol/proto/authentication.proto b/protocol/proto/authentication.proto index 30e4f6b6..8a15211c 100644 --- a/protocol/proto/authentication.proto +++ b/protocol/proto/authentication.proto @@ -13,11 +13,11 @@ message ClientResponseEncrypted { message LoginCredentials { optional string username = 0xa; - required Type typ = 0x14; + required AuthenticationType typ = 0x14; optional bytes auth_data = 0x1e; } -enum Type { +enum AuthenticationType { AUTHENTICATION_USER_PASS = 0x0; AUTHENTICATION_STORED_SPOTIFY_CREDENTIALS = 0x1; AUTHENTICATION_STORED_FACEBOOK_CREDENTIALS = 0x2; @@ -134,21 +134,31 @@ message ClientInfoFacebook { optional string machine_id = 0x1; } -message AuthSuccess { - required string username = 0x0a; - required uint32 data1 = 0x14; - required uint32 data2 = 0x19; - required uint32 data3 = 0x1e; - required bytes data4 = 0x28; - required bytes data5 = 0x32; +message APWelcome { + required string canonical_username = 0xa; + required AccountType account_type_logged_in = 0x14; + required AccountType credentials_type_logged_in = 0x19; + required AuthenticationType reusable_auth_credentials_type = 0x1e; + required bytes reusable_auth_credentials = 0x28; + optional bytes lfs_secret = 0x32; + optional AccountInfo account_info = 0x3c; + optional AccountInfoFacebook fb = 0x46; } -message AuthFailure { - required uint32 code = 0x0a; - required Data1 data1 = 0x32; - - message Data1 { - required string data0 = 0x01; - } +enum AccountType { + Spotify = 0x0; + Facebook = 0x1; } +message AccountInfo { + optional AccountInfoSpotify spotify = 0x1; + optional AccountInfoFacebook facebook = 0x2; +} + +message AccountInfoSpotify { +} + +message AccountInfoFacebook { + optional string access_token = 0x1; + optional string machine_id = 0x2; +} diff --git a/protocol/proto/keyexchange.proto b/protocol/proto/keyexchange.proto index 464828df..8a5813b3 100644 --- a/protocol/proto/keyexchange.proto +++ b/protocol/proto/keyexchange.proto @@ -1,21 +1,21 @@ -// size=80 + message ClientHello { - required BuildInfo build_info = 0xa; // idx=0 offset=c - repeated Fingerprint fingerprints_supported = 0x14; // idx=ffff offset=10 - repeated Cryptosuite cryptosuites_supported = 0x1e; // idx=ffff offset=2c - repeated Powscheme powschemes_supported = 0x28; // idx=ffff offset=48 - required LoginCryptoHelloUnion login_crypto_hello = 0x32; // idx=1 offset=64 - required bytes client_nonce = 0x3c; // idx=2 offset=68 size=f - optional bytes padding = 0x46; // idx=3 offset=78 - optional FeatureSet feature_set = 0x50; // idx=4 offset=7c + required BuildInfo build_info = 0xa; + repeated Fingerprint fingerprints_supported = 0x14; + repeated Cryptosuite cryptosuites_supported = 0x1e; + repeated Powscheme powschemes_supported = 0x28; + required LoginCryptoHelloUnion login_crypto_hello = 0x32; + required bytes client_nonce = 0x3c; + optional bytes padding = 0x46; + optional FeatureSet feature_set = 0x50; } -// size=38 + message BuildInfo { - required Product product = 0xa; // idx=0 offset=c - repeated ProductFlags product_flags = 0x14; // idx=ffff offset=10 - required Platform platform = 0x1e; // idx=1 offset=2c - required uint64 version = 0x28; // idx=2 offset=30 extra=246558 + required Product product = 0xa; + repeated ProductFlags product_flags = 0x14; + required Platform platform = 0x1e; + required uint64 version = 0x28; } enum Product { @@ -72,108 +72,101 @@ enum Powscheme { POW_HASH_CASH = 0x0; } -// size=10 + message LoginCryptoHelloUnion { - optional LoginCryptoDiffieHellmanHello diffie_hellman = 0xa; // idx=0 offset=c + optional LoginCryptoDiffieHellmanHello diffie_hellman = 0xa; } -// size=70 + message LoginCryptoDiffieHellmanHello { - required bytes gc = 0xa; // idx=0 offset=c size=5f - required uint32 server_keys_known = 0x14; // idx=1 offset=6c + required bytes gc = 0xa; + required uint32 server_keys_known = 0x14; } -// size=10 + message FeatureSet { - optional bool autoupdate2 = 0x1; // idx=0 offset=c - optional bool current_location = 0x2; // idx=1 offset=d + optional bool autoupdate2 = 0x1; + optional bool current_location = 0x2; } -// size=18 message APResponseMessage { - optional APChallenge challenge = 0xa; // idx=0 offset=c - optional UpgradeRequiredMessage upgrade = 0x14; // idx=1 offset=10 - optional APLoginFailed login_failed = 0x1e; // idx=2 offset=14 + optional APChallenge challenge = 0xa; + optional UpgradeRequiredMessage upgrade = 0x14; + optional APLoginFailed login_failed = 0x1e; } -// size=30 message APChallenge { - required LoginCryptoChallengeUnion login_crypto_challenge = 0xa; // idx=0 offset=c - required FingerprintChallengeUnion fingerprint_challenge = 0x14; // idx=1 offset=10 - required PoWChallengeUnion pow_challenge = 0x1e; // idx=2 offset=14 - required CryptoChallengeUnion crypto_challenge = 0x28; // idx=3 offset=18 - required bytes server_nonce = 0x32; // idx=4 offset=1c size=f - optional bytes padding = 0x3c; // idx=5 offset=2c + required LoginCryptoChallengeUnion login_crypto_challenge = 0xa; + required FingerprintChallengeUnion fingerprint_challenge = 0x14; + required PoWChallengeUnion pow_challenge = 0x1e; + required CryptoChallengeUnion crypto_challenge = 0x28; + required bytes server_nonce = 0x32; + optional bytes padding = 0x3c; } -// size=10 message LoginCryptoChallengeUnion { - optional LoginCryptoDiffieHellmanChallenge diffie_hellman = 0xa; // idx=0 offset=c + optional LoginCryptoDiffieHellmanChallenge diffie_hellman = 0xa; } -// size=170 message LoginCryptoDiffieHellmanChallenge { - required bytes gs = 0xa; // idx=0 offset=c size=5f - required int32 server_signature_key = 0x14; // idx=1 offset=6c type=int8 - required bytes gs_signature = 0x1e; // idx=2 offset=6d size=ff + required bytes gs = 0xa; + required int32 server_signature_key = 0x14; + required bytes gs_signature = 0x1e; } -// size=14 message FingerprintChallengeUnion { - optional FingerprintGrainChallenge grain = 0xa; // idx=0 offset=c - optional FingerprintHmacRipemdChallenge hmac_ripemd = 0x14; // idx=1 offset=10 + optional FingerprintGrainChallenge grain = 0xa; + optional FingerprintHmacRipemdChallenge hmac_ripemd = 0x14; } -// size=1c + message FingerprintGrainChallenge { - required bytes kek = 0xa; // idx=0 offset=c size=f + required bytes kek = 0xa; } -// size=20 + message FingerprintHmacRipemdChallenge { - required bytes challenge = 0xa; // idx=0 offset=c size=13 + required bytes challenge = 0xa; } -// size=10 + message PoWChallengeUnion { - optional PoWHashCashChallenge hash_cash = 0xa; // idx=0 offset=c + optional PoWHashCashChallenge hash_cash = 0xa; } -// size=24 message PoWHashCashChallenge { - optional bytes prefix = 0xa; // idx=0 offset=c size=f - optional int32 length = 0x14; // idx=1 offset=1c type=int8 - optional int32 target = 0x1e; // idx=2 offset=20 + optional bytes prefix = 0xa; + optional int32 length = 0x14; + optional int32 target = 0x1e; } -// size=14 + message CryptoChallengeUnion { - optional CryptoShannonChallenge shannon = 0xa; // idx=0 offset=c - optional CryptoRc4Sha1HmacChallenge rc4_sha1_hmac = 0x14; // idx=1 offset=10 + optional CryptoShannonChallenge shannon = 0xa; + optional CryptoRc4Sha1HmacChallenge rc4_sha1_hmac = 0x14; } -// size=8 + message CryptoShannonChallenge { } -// size=8 + message CryptoRc4Sha1HmacChallenge { } -// size=18 + message UpgradeRequiredMessage { - required bytes upgrade_signed_part = 0xa; // idx=0 offset=c - required bytes signature = 0x14; // idx=1 offset=10 - optional string http_suffix = 0x1e; // idx=2 offset=14 + required bytes upgrade_signed_part = 0xa; + required bytes signature = 0x14; + optional string http_suffix = 0x1e; } -// size=1c message APLoginFailed { - required ErrorCode error_code = 0xa; // idx=0 offset=c - optional int32 retry_delay = 0x14; // idx=1 offset=10 - optional int32 expiry = 0x1e; // idx=2 offset=14 - optional string error_description = 0x28; // idx=3 offset=18 + required ErrorCode error_code = 0xa; + optional int32 retry_delay = 0x14; + optional int32 expiry = 0x1e; + optional string error_description = 0x28; } enum ErrorCode { @@ -190,50 +183,45 @@ enum ErrorCode { ApplicationBanned = 0x11; } - - -// size=18 message ClientResponsePlaintext { - required LoginCryptoResponseUnion login_crypto_response = 0xa; // idx=0 offset=c - required PoWResponseUnion pow_response = 0x14; // idx=1 offset=10 - required CryptoResponseUnion crypto_response = 0x1e; // idx=2 offset=14 + required LoginCryptoResponseUnion login_crypto_response = 0xa; + required PoWResponseUnion pow_response = 0x14; + required CryptoResponseUnion crypto_response = 0x1e; } -// size=10 + message LoginCryptoResponseUnion { - optional LoginCryptoDiffieHellmanResponse diffie_hellman = 0xa; // idx=0 offset=c + optional LoginCryptoDiffieHellmanResponse diffie_hellman = 0xa; } -// size=20 + message LoginCryptoDiffieHellmanResponse { - required bytes hmac = 0xa; // idx=0 offset=c size=13 + required bytes hmac = 0xa; } -// size=10 + message PoWResponseUnion { - optional PoWHashCashResponse hash_cash = 0xa; // idx=0 offset=c + optional PoWHashCashResponse hash_cash = 0xa; } -// size=1c + message PoWHashCashResponse { - required bytes hash_suffix = 0xa; // idx=0 offset=c size=f + required bytes hash_suffix = 0xa; } -// size=14 + message CryptoResponseUnion { - optional CryptoShannonResponse shannon = 0xa; // idx=0 offset=c - optional CryptoRc4Sha1HmacResponse rc4_sha1_hmac = 0x14; // idx=1 offset=10 + optional CryptoShannonResponse shannon = 0xa; + optional CryptoRc4Sha1HmacResponse rc4_sha1_hmac = 0x14; } -// size=10 + message CryptoShannonResponse { - optional int32 dummy = 0x1; // idx=0 offset=c type=uint8 + optional int32 dummy = 0x1; } -// size=10 + message CryptoRc4Sha1HmacResponse { - optional int32 dummy = 0x1; // idx=0 offset=c type=uint8 + optional int32 dummy = 0x1; } - - diff --git a/src/main.rs b/src/main.rs index 90fa5787..774a5597 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,6 +44,7 @@ use protobuf::core::Message; use metadata::{MetadataCache, AlbumRef, ArtistRef, TrackRef}; use session::{Config, Session}; use util::SpotifyId; +use util::version::version_string; use player::Player; use mercury::{MercuryRequest, MercuryMethod}; use librespot_protocol as protocol; @@ -53,28 +54,31 @@ fn main() { let mut appkey_file = File::open(Path::new(&args.next().unwrap())).unwrap(); let username = args.next().unwrap(); let password = args.next().unwrap(); + let name = args.next().unwrap(); let mut appkey = Vec::new(); appkey_file.read_to_end(&mut appkey).unwrap(); let config = Config { application_key: appkey, - user_agent: "ABC".to_string(), - device_id: "ABC".to_string() + user_agent: version_string(), + device_id: name.to_string() }; let session = Session::new(config); - session.login(username, password); + session.login(username.clone(), password); session.poll(); let ident = session.config.device_id.clone(); SpircManager{ session: session, + username: username.clone(), + name: name.clone(), + ident: ident, + device_type: 5, + state_update_id: 0, seq_nr: 0, - name: "BlaBla".to_string(), - ident: ident, - device_type: 5, volume: 0x8000, can_play: true, is_active: false, @@ -116,6 +120,7 @@ fn print_track(cache: &mut MetadataCache, track_id: SpotifyId) { struct SpircManager { session: Session, + username: String, state_update_id: i64, seq_nr: u32, @@ -135,7 +140,7 @@ impl SpircManager { self.session.mercury.send(MercuryRequest{ method: MercuryMethod::SUB, - uri: "hm://remote/user/lietar/v23".to_string(), + uri: format!("hm://remote/user/{}/v23", self.username).to_string(), content_type: None, callback: Some(tx), payload: Vec::new() @@ -185,7 +190,7 @@ impl SpircManager { let device_state = self.device_state(); self.session.mercury.send(MercuryRequest{ method: MercuryMethod::SEND, - uri: "hm://remote/user/lietar".to_string(), + uri: format!("hm://remote/user/{}", self.username).to_string(), content_type: None, callback: None, payload: vec![ @@ -206,7 +211,7 @@ impl SpircManager { fn device_state(&mut self) -> protocol::spirc::DeviceState { protobuf_init!(protocol::spirc::DeviceState::new(), { - sw_version: "librespot-0.1.0".to_string(), + sw_version: version_string(), is_active: self.is_active, can_play: self.can_play, volume: self.volume as u32, diff --git a/src/session.rs b/src/session.rs index ded674b9..b38aa218 100644 --- a/src/session.rs +++ b/src/session.rs @@ -147,7 +147,7 @@ impl Session { let packet = protobuf_init!(protocol::authentication::ClientResponseEncrypted::new(), { login_credentials => { username: username, - typ: protocol::authentication::Type::AUTHENTICATION_USER_PASS, + typ: protocol::authentication::AuthenticationType::AUTHENTICATION_USER_PASS, auth_data: password.into_bytes(), }, system_info => {