spirc: Don’t hardcode stuff

This commit is contained in:
Paul Lietar 2015-07-02 01:27:19 +02:00
parent 45491925de
commit df11960946
4 changed files with 118 additions and 115 deletions

View file

@ -13,11 +13,11 @@ message ClientResponseEncrypted {
message LoginCredentials { message LoginCredentials {
optional string username = 0xa; optional string username = 0xa;
required Type typ = 0x14; required AuthenticationType typ = 0x14;
optional bytes auth_data = 0x1e; optional bytes auth_data = 0x1e;
} }
enum Type { enum AuthenticationType {
AUTHENTICATION_USER_PASS = 0x0; AUTHENTICATION_USER_PASS = 0x0;
AUTHENTICATION_STORED_SPOTIFY_CREDENTIALS = 0x1; AUTHENTICATION_STORED_SPOTIFY_CREDENTIALS = 0x1;
AUTHENTICATION_STORED_FACEBOOK_CREDENTIALS = 0x2; AUTHENTICATION_STORED_FACEBOOK_CREDENTIALS = 0x2;
@ -134,21 +134,31 @@ message ClientInfoFacebook {
optional string machine_id = 0x1; optional string machine_id = 0x1;
} }
message AuthSuccess { message APWelcome {
required string username = 0x0a; required string canonical_username = 0xa;
required uint32 data1 = 0x14; required AccountType account_type_logged_in = 0x14;
required uint32 data2 = 0x19; required AccountType credentials_type_logged_in = 0x19;
required uint32 data3 = 0x1e; required AuthenticationType reusable_auth_credentials_type = 0x1e;
required bytes data4 = 0x28; required bytes reusable_auth_credentials = 0x28;
required bytes data5 = 0x32; optional bytes lfs_secret = 0x32;
optional AccountInfo account_info = 0x3c;
optional AccountInfoFacebook fb = 0x46;
} }
message AuthFailure { enum AccountType {
required uint32 code = 0x0a; Spotify = 0x0;
required Data1 data1 = 0x32; Facebook = 0x1;
message Data1 {
required string data0 = 0x01;
}
} }
message AccountInfo {
optional AccountInfoSpotify spotify = 0x1;
optional AccountInfoFacebook facebook = 0x2;
}
message AccountInfoSpotify {
}
message AccountInfoFacebook {
optional string access_token = 0x1;
optional string machine_id = 0x2;
}

View file

@ -1,21 +1,21 @@
// size=80
message ClientHello { message ClientHello {
required BuildInfo build_info = 0xa; // idx=0 offset=c required BuildInfo build_info = 0xa;
repeated Fingerprint fingerprints_supported = 0x14; // idx=ffff offset=10 repeated Fingerprint fingerprints_supported = 0x14;
repeated Cryptosuite cryptosuites_supported = 0x1e; // idx=ffff offset=2c repeated Cryptosuite cryptosuites_supported = 0x1e;
repeated Powscheme powschemes_supported = 0x28; // idx=ffff offset=48 repeated Powscheme powschemes_supported = 0x28;
required LoginCryptoHelloUnion login_crypto_hello = 0x32; // idx=1 offset=64 required LoginCryptoHelloUnion login_crypto_hello = 0x32;
required bytes client_nonce = 0x3c; // idx=2 offset=68 size=f required bytes client_nonce = 0x3c;
optional bytes padding = 0x46; // idx=3 offset=78 optional bytes padding = 0x46;
optional FeatureSet feature_set = 0x50; // idx=4 offset=7c optional FeatureSet feature_set = 0x50;
} }
// size=38
message BuildInfo { message BuildInfo {
required Product product = 0xa; // idx=0 offset=c required Product product = 0xa;
repeated ProductFlags product_flags = 0x14; // idx=ffff offset=10 repeated ProductFlags product_flags = 0x14;
required Platform platform = 0x1e; // idx=1 offset=2c required Platform platform = 0x1e;
required uint64 version = 0x28; // idx=2 offset=30 extra=246558 required uint64 version = 0x28;
} }
enum Product { enum Product {
@ -72,108 +72,101 @@ enum Powscheme {
POW_HASH_CASH = 0x0; POW_HASH_CASH = 0x0;
} }
// size=10
message LoginCryptoHelloUnion { message LoginCryptoHelloUnion {
optional LoginCryptoDiffieHellmanHello diffie_hellman = 0xa; // idx=0 offset=c optional LoginCryptoDiffieHellmanHello diffie_hellman = 0xa;
} }
// size=70
message LoginCryptoDiffieHellmanHello { message LoginCryptoDiffieHellmanHello {
required bytes gc = 0xa; // idx=0 offset=c size=5f required bytes gc = 0xa;
required uint32 server_keys_known = 0x14; // idx=1 offset=6c required uint32 server_keys_known = 0x14;
} }
// size=10
message FeatureSet { message FeatureSet {
optional bool autoupdate2 = 0x1; // idx=0 offset=c optional bool autoupdate2 = 0x1;
optional bool current_location = 0x2; // idx=1 offset=d optional bool current_location = 0x2;
} }
// size=18
message APResponseMessage { message APResponseMessage {
optional APChallenge challenge = 0xa; // idx=0 offset=c optional APChallenge challenge = 0xa;
optional UpgradeRequiredMessage upgrade = 0x14; // idx=1 offset=10 optional UpgradeRequiredMessage upgrade = 0x14;
optional APLoginFailed login_failed = 0x1e; // idx=2 offset=14 optional APLoginFailed login_failed = 0x1e;
} }
// size=30
message APChallenge { message APChallenge {
required LoginCryptoChallengeUnion login_crypto_challenge = 0xa; // idx=0 offset=c required LoginCryptoChallengeUnion login_crypto_challenge = 0xa;
required FingerprintChallengeUnion fingerprint_challenge = 0x14; // idx=1 offset=10 required FingerprintChallengeUnion fingerprint_challenge = 0x14;
required PoWChallengeUnion pow_challenge = 0x1e; // idx=2 offset=14 required PoWChallengeUnion pow_challenge = 0x1e;
required CryptoChallengeUnion crypto_challenge = 0x28; // idx=3 offset=18 required CryptoChallengeUnion crypto_challenge = 0x28;
required bytes server_nonce = 0x32; // idx=4 offset=1c size=f required bytes server_nonce = 0x32;
optional bytes padding = 0x3c; // idx=5 offset=2c optional bytes padding = 0x3c;
} }
// size=10
message LoginCryptoChallengeUnion { message LoginCryptoChallengeUnion {
optional LoginCryptoDiffieHellmanChallenge diffie_hellman = 0xa; // idx=0 offset=c optional LoginCryptoDiffieHellmanChallenge diffie_hellman = 0xa;
} }
// size=170
message LoginCryptoDiffieHellmanChallenge { message LoginCryptoDiffieHellmanChallenge {
required bytes gs = 0xa; // idx=0 offset=c size=5f required bytes gs = 0xa;
required int32 server_signature_key = 0x14; // idx=1 offset=6c type=int8 required int32 server_signature_key = 0x14;
required bytes gs_signature = 0x1e; // idx=2 offset=6d size=ff required bytes gs_signature = 0x1e;
} }
// size=14
message FingerprintChallengeUnion { message FingerprintChallengeUnion {
optional FingerprintGrainChallenge grain = 0xa; // idx=0 offset=c optional FingerprintGrainChallenge grain = 0xa;
optional FingerprintHmacRipemdChallenge hmac_ripemd = 0x14; // idx=1 offset=10 optional FingerprintHmacRipemdChallenge hmac_ripemd = 0x14;
} }
// size=1c
message FingerprintGrainChallenge { message FingerprintGrainChallenge {
required bytes kek = 0xa; // idx=0 offset=c size=f required bytes kek = 0xa;
} }
// size=20
message FingerprintHmacRipemdChallenge { message FingerprintHmacRipemdChallenge {
required bytes challenge = 0xa; // idx=0 offset=c size=13 required bytes challenge = 0xa;
} }
// size=10
message PoWChallengeUnion { message PoWChallengeUnion {
optional PoWHashCashChallenge hash_cash = 0xa; // idx=0 offset=c optional PoWHashCashChallenge hash_cash = 0xa;
} }
// size=24
message PoWHashCashChallenge { message PoWHashCashChallenge {
optional bytes prefix = 0xa; // idx=0 offset=c size=f optional bytes prefix = 0xa;
optional int32 length = 0x14; // idx=1 offset=1c type=int8 optional int32 length = 0x14;
optional int32 target = 0x1e; // idx=2 offset=20 optional int32 target = 0x1e;
} }
// size=14
message CryptoChallengeUnion { message CryptoChallengeUnion {
optional CryptoShannonChallenge shannon = 0xa; // idx=0 offset=c optional CryptoShannonChallenge shannon = 0xa;
optional CryptoRc4Sha1HmacChallenge rc4_sha1_hmac = 0x14; // idx=1 offset=10 optional CryptoRc4Sha1HmacChallenge rc4_sha1_hmac = 0x14;
} }
// size=8
message CryptoShannonChallenge { message CryptoShannonChallenge {
} }
// size=8
message CryptoRc4Sha1HmacChallenge { message CryptoRc4Sha1HmacChallenge {
} }
// size=18
message UpgradeRequiredMessage { message UpgradeRequiredMessage {
required bytes upgrade_signed_part = 0xa; // idx=0 offset=c required bytes upgrade_signed_part = 0xa;
required bytes signature = 0x14; // idx=1 offset=10 required bytes signature = 0x14;
optional string http_suffix = 0x1e; // idx=2 offset=14 optional string http_suffix = 0x1e;
} }
// size=1c
message APLoginFailed { message APLoginFailed {
required ErrorCode error_code = 0xa; // idx=0 offset=c required ErrorCode error_code = 0xa;
optional int32 retry_delay = 0x14; // idx=1 offset=10 optional int32 retry_delay = 0x14;
optional int32 expiry = 0x1e; // idx=2 offset=14 optional int32 expiry = 0x1e;
optional string error_description = 0x28; // idx=3 offset=18 optional string error_description = 0x28;
} }
enum ErrorCode { enum ErrorCode {
@ -190,50 +183,45 @@ enum ErrorCode {
ApplicationBanned = 0x11; ApplicationBanned = 0x11;
} }
// size=18
message ClientResponsePlaintext { message ClientResponsePlaintext {
required LoginCryptoResponseUnion login_crypto_response = 0xa; // idx=0 offset=c required LoginCryptoResponseUnion login_crypto_response = 0xa;
required PoWResponseUnion pow_response = 0x14; // idx=1 offset=10 required PoWResponseUnion pow_response = 0x14;
required CryptoResponseUnion crypto_response = 0x1e; // idx=2 offset=14 required CryptoResponseUnion crypto_response = 0x1e;
} }
// size=10
message LoginCryptoResponseUnion { message LoginCryptoResponseUnion {
optional LoginCryptoDiffieHellmanResponse diffie_hellman = 0xa; // idx=0 offset=c optional LoginCryptoDiffieHellmanResponse diffie_hellman = 0xa;
} }
// size=20
message LoginCryptoDiffieHellmanResponse { message LoginCryptoDiffieHellmanResponse {
required bytes hmac = 0xa; // idx=0 offset=c size=13 required bytes hmac = 0xa;
} }
// size=10
message PoWResponseUnion { message PoWResponseUnion {
optional PoWHashCashResponse hash_cash = 0xa; // idx=0 offset=c optional PoWHashCashResponse hash_cash = 0xa;
} }
// size=1c
message PoWHashCashResponse { message PoWHashCashResponse {
required bytes hash_suffix = 0xa; // idx=0 offset=c size=f required bytes hash_suffix = 0xa;
} }
// size=14
message CryptoResponseUnion { message CryptoResponseUnion {
optional CryptoShannonResponse shannon = 0xa; // idx=0 offset=c optional CryptoShannonResponse shannon = 0xa;
optional CryptoRc4Sha1HmacResponse rc4_sha1_hmac = 0x14; // idx=1 offset=10 optional CryptoRc4Sha1HmacResponse rc4_sha1_hmac = 0x14;
} }
// size=10
message CryptoShannonResponse { message CryptoShannonResponse {
optional int32 dummy = 0x1; // idx=0 offset=c type=uint8 optional int32 dummy = 0x1;
} }
// size=10
message CryptoRc4Sha1HmacResponse { message CryptoRc4Sha1HmacResponse {
optional int32 dummy = 0x1; // idx=0 offset=c type=uint8 optional int32 dummy = 0x1;
} }

View file

@ -44,6 +44,7 @@ use protobuf::core::Message;
use metadata::{MetadataCache, AlbumRef, ArtistRef, TrackRef}; use metadata::{MetadataCache, AlbumRef, ArtistRef, TrackRef};
use session::{Config, Session}; use session::{Config, Session};
use util::SpotifyId; use util::SpotifyId;
use util::version::version_string;
use player::Player; use player::Player;
use mercury::{MercuryRequest, MercuryMethod}; use mercury::{MercuryRequest, MercuryMethod};
use librespot_protocol as protocol; use librespot_protocol as protocol;
@ -53,28 +54,31 @@ fn main() {
let mut appkey_file = File::open(Path::new(&args.next().unwrap())).unwrap(); let mut appkey_file = File::open(Path::new(&args.next().unwrap())).unwrap();
let username = args.next().unwrap(); let username = args.next().unwrap();
let password = args.next().unwrap(); let password = args.next().unwrap();
let name = args.next().unwrap();
let mut appkey = Vec::new(); let mut appkey = Vec::new();
appkey_file.read_to_end(&mut appkey).unwrap(); appkey_file.read_to_end(&mut appkey).unwrap();
let config = Config { let config = Config {
application_key: appkey, application_key: appkey,
user_agent: "ABC".to_string(), user_agent: version_string(),
device_id: "ABC".to_string() device_id: name.to_string()
}; };
let session = Session::new(config); let session = Session::new(config);
session.login(username, password); session.login(username.clone(), password);
session.poll(); session.poll();
let ident = session.config.device_id.clone(); let ident = session.config.device_id.clone();
SpircManager{ SpircManager{
session: session, session: session,
username: username.clone(),
name: name.clone(),
ident: ident,
device_type: 5,
state_update_id: 0, state_update_id: 0,
seq_nr: 0, seq_nr: 0,
name: "BlaBla".to_string(),
ident: ident,
device_type: 5,
volume: 0x8000, volume: 0x8000,
can_play: true, can_play: true,
is_active: false, is_active: false,
@ -116,6 +120,7 @@ fn print_track(cache: &mut MetadataCache, track_id: SpotifyId) {
struct SpircManager { struct SpircManager {
session: Session, session: Session,
username: String,
state_update_id: i64, state_update_id: i64,
seq_nr: u32, seq_nr: u32,
@ -135,7 +140,7 @@ impl SpircManager {
self.session.mercury.send(MercuryRequest{ self.session.mercury.send(MercuryRequest{
method: MercuryMethod::SUB, method: MercuryMethod::SUB,
uri: "hm://remote/user/lietar/v23".to_string(), uri: format!("hm://remote/user/{}/v23", self.username).to_string(),
content_type: None, content_type: None,
callback: Some(tx), callback: Some(tx),
payload: Vec::new() payload: Vec::new()
@ -185,7 +190,7 @@ impl SpircManager {
let device_state = self.device_state(); let device_state = self.device_state();
self.session.mercury.send(MercuryRequest{ self.session.mercury.send(MercuryRequest{
method: MercuryMethod::SEND, method: MercuryMethod::SEND,
uri: "hm://remote/user/lietar".to_string(), uri: format!("hm://remote/user/{}", self.username).to_string(),
content_type: None, content_type: None,
callback: None, callback: None,
payload: vec![ payload: vec![
@ -206,7 +211,7 @@ impl SpircManager {
fn device_state(&mut self) -> protocol::spirc::DeviceState { fn device_state(&mut self) -> protocol::spirc::DeviceState {
protobuf_init!(protocol::spirc::DeviceState::new(), { protobuf_init!(protocol::spirc::DeviceState::new(), {
sw_version: "librespot-0.1.0".to_string(), sw_version: version_string(),
is_active: self.is_active, is_active: self.is_active,
can_play: self.can_play, can_play: self.can_play,
volume: self.volume as u32, volume: self.volume as u32,

View file

@ -147,7 +147,7 @@ impl Session {
let packet = protobuf_init!(protocol::authentication::ClientResponseEncrypted::new(), { let packet = protobuf_init!(protocol::authentication::ClientResponseEncrypted::new(), {
login_credentials => { login_credentials => {
username: username, username: username,
typ: protocol::authentication::Type::AUTHENTICATION_USER_PASS, typ: protocol::authentication::AuthenticationType::AUTHENTICATION_USER_PASS,
auth_data: password.into_bytes(), auth_data: password.into_bytes(),
}, },
system_info => { system_info => {