Initial commit.

This commit is contained in:
Paul Liétar 2015-04-25 21:32:07 +01:00
commit a993b60ffa
17 changed files with 872 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
target
Cargo.lock
.cargo

107
Cargo.lock generated Normal file
View file

@ -0,0 +1,107 @@
[root]
name = "librespot"
version = "0.1.0"
dependencies = [
"byteorder 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"mod_path 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"protobuf 0.0.9 (git+https://github.com/plietar/rust-protobuf.git)",
"protobuf_macros 0.1.0 (git+https://github.com/plietar/rust-protobuf-macros.git)",
"rand 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-gmp 0.2.0 (git+https://github.com/plietar/rust-gmp.git)",
]
[[package]]
name = "byteorder"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gcc"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mod_path"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "protobuf"
version = "0.0.9"
source = "git+https://github.com/plietar/rust-protobuf.git#f26efc36c09602109a01885449e16d15a8494cb8"
[[package]]
name = "protobuf_macros"
version = "0.1.0"
source = "git+https://github.com/plietar/rust-protobuf-macros.git#3631dbaac78e955b36fdb71bb79c9b3cdc4bd4d9"
[[package]]
name = "rand"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rust-crypto"
version = "0.2.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rust-gmp"
version = "0.2.0"
source = "git+https://github.com/plietar/rust-gmp.git#150cb69f787d413e95860dc7268a6399163f468f"
[[package]]
name = "rustc-serialize"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "time"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]

28
Cargo.toml Normal file
View file

@ -0,0 +1,28 @@
[package]
name = "librespot"
version = "0.1.0"
authors = ["Paul Liétar <paul@lietar.net>"]
build = "build.rs"
links = "gmp"
#[[bin]]
#name = "librespot"
#path = "src/main.rs"
[dependencies]
mod_path = "*"
byteorder = "*"
num = "*"
rand = "*"
lazy_static = "0.1.*"
rust-crypto = "*"
[dependencies.protobuf]
git = "https://github.com/plietar/rust-protobuf.git"
[dependencies.protobuf_macros]
git = "https://github.com/plietar/rust-protobuf-macros.git"
[dependencies.rust-gmp]
git = "https://github.com/plietar/rust-gmp.git"

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Paul Lietar
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

43
build.rs Normal file
View file

@ -0,0 +1,43 @@
use std::env;
use std::process::{Command, Stdio};
use std::path::Path;
#[derive(Debug)]
enum ProtobufError {
IoError(::std::io::Error),
Other
}
impl std::convert::From<::std::io::Error> for ProtobufError {
fn from(e: ::std::io::Error) -> ProtobufError {
ProtobufError::IoError(e)
}
}
fn compile(prefix : &Path, files : &[&Path]) -> Result<(),ProtobufError>{
let mut c = Command::new("protoc");
c.arg("--rust_out").arg(env::var("OUT_DIR").unwrap())
.arg("--proto_path").arg(prefix.to_str().unwrap());
for f in files.iter() {
c.arg(f.to_str().unwrap());
}
//c.stdout(Stdio::inherit());
c.stderr(Stdio::inherit());
let mut p = try!(c.spawn());
let r = try!(p.wait());
return match r.success() {
true => Ok(()),
false => Err(ProtobufError::Other),
};
}
fn main() {
let prefix = Path::new("protocol");
compile(&prefix, &[
&prefix.join("keyexchange.proto"),
&prefix.join("authentication.proto")
]).unwrap();
}

View file

@ -0,0 +1,51 @@
message AuthRequest {
enum LoginMethod {
PASSWORD = 0x0;
TOKEN = 0x3;
}
message Credentials {
optional string username = 0x0a;
required LoginMethod method = 0x14;
required bytes password = 0x1e;
}
required Credentials credentials = 0x0a;
message Data1 {
required uint32 data0 = 0x0a;
required uint32 data1 = 0x3c;
required string partner = 0x5a; // "Partner %s %s;%s" % ("lenbrook_bluesound", brand, model)
required string deviceid = 0x64; // sha1(os_device_id).hexdigest()
}
required Data1 data1 = 0x32;
required string version = 0x46;
message Data3 {
required uint32 data0 = 0x01;
required bytes appkey1 = 0x02;
required bytes appkey2 = 0x03;
required string data3 = 0x04;
required bytes data4 = 0x05;
}
required Data3 data3 = 0x50;
}
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 AuthFailure {
required uint32 code = 0x0a;
required Data1 data1 = 0x32;
message Data1 {
required string data0 = 0x01;
}
}

View file

@ -0,0 +1,61 @@
message Request {
message Data0 {
required uint32 data0 = 0x0a; // 05
required uint32 data1 = 0x1e; // 02
required uint64 data2 = 0x28; // 10800000000
}
message Data2 {
message Data0 {
required bytes data0 = 0x0a; // 60
required uint32 data1 = 0x14; // 01
}
required Data0 data0 = 0x0a; // 65
}
required Data0 data0 = 0x0a; // 0d
required uint32 data1 = 0x1e; // 00
required Data2 data2 = 0x32; // 67
required bytes random = 0x3c; // 10
required bytes data4 = 0x46; // 01
required bytes data5 = 0x50; // 02
}
message Response {
message Data {
message Data0 {
message Data0 {
required bytes data0 = 0x0a; // 60
required uint32 data1 = 0x14;
required bytes data2 = 0x1e; // 100
}
required Data0 data0 = 0x0a;
}
message Data3 {
required bytes data0 = 0x0a;
}
required Data0 data0 = 0x0a;
required bytes data1 = 0x14;
required bytes data2 = 0x1e;
required Data3 data3 = 0x28;
required bytes data4 = 0x32;
required bytes data5 = 0x3c;
}
required Data data = 0x0a;
}
message ChallengePacket {
message Data0 {
message Data0 {
required bytes data0 = 0x0a;
}
required Data0 data0 = 0x0a;
}
required Data0 data0 = 0x0a;
required bytes data1 = 0x14;
required bytes data2 = 0x1e;
}

49
protocol/mercury.proto Normal file
View file

@ -0,0 +1,49 @@
message MercuryRequest {
required string url = 0x01;
optional string mime = 0x02;
required string method = 0x03;
}
message MercuryReply {
required string url = 0x01;
required string mime = 0x02;
required sint32 code = 0x04;
repeated Header header = 0x06;
message Header {
required string key = 0x01;
required bytes value = 0x02;
}
}
message MercuryGetRequest {
required string url = 0x01;
optional string method = 0x03;
}
message MercuryMultiGetRequest {
repeated MercuryGetRequest request = 0x01;
}
message MercuryGetReply {
enum CachePolicy {
CACHE_NO = 1;
CACHE_PRIVATE = 2;
CACHE_PUBLIC = 3;
}
optional sint32 code = 0x01;
optional CachePolicy cache_policy = 0x03;
optional uint32 ttl = 0x04;
optional bytes etag = 0x05;
optional string mime = 0x06;
optional bytes body = 0x07;
}
message MercuryMultiGetReply {
repeated MercuryGetReply reply = 0x1;
}
message MercurySubscribed {
required string url = 0x1;
}

154
protocol/metadata.proto Normal file
View file

@ -0,0 +1,154 @@
message TopTracks {
optional string country = 1;
repeated Track track = 2;
}
message ActivityPeriod {
optional sint32 start_year = 1;
optional sint32 end_year = 2;
optional sint32 decade = 3;
}
message Artist {
optional bytes gid = 1;
optional string name = 2;
optional sint32 popularity = 3;
repeated TopTracks top_track = 4;
repeated AlbumGroup album_group = 5;
repeated AlbumGroup single_group = 6;
repeated AlbumGroup compilation_group = 7;
repeated AlbumGroup appears_on_group = 8;
repeated string genre = 9;
repeated ExternalId external_id = 10;
repeated Image portrait = 11;
repeated Biography biography = 12;
repeated ActivityPeriod activity_period = 13;
repeated Restriction restriction = 14;
repeated Artist related = 15;
optional bool is_portrait_album_cover = 16;
optional ImageGroup portrait_group = 17;
}
message AlbumGroup {
repeated Album album = 1;
}
message Date {
optional sint32 year = 1;
optional sint32 month = 2;
optional sint32 day = 3;
}
message Album {
enum Type {
ALBUM = 1;
SINGLE = 2;
COMPILATION = 3;
}
optional bytes gid = 1;
optional string name = 2;
repeated Artist artist = 3;
optional Type type = 4;
optional string label = 5;
optional Date date = 6;
optional sint32 popularity = 7;
repeated string genre = 8;
repeated Image cover = 9;
repeated ExternalId external_id = 10;
repeated Disc disc = 11;
repeated string review = 12;
repeated Copyright copyright = 13;
repeated Restriction restriction = 14;
repeated Album related = 15;
repeated SalePeriod sale_period = 16;
optional ImageGroup cover_group = 17;
}
message Track {
optional bytes gid = 1;
optional string name = 2;
optional Album album = 3;
repeated Artist artist = 4;
optional sint32 number = 5;
optional sint32 disc_number = 6;
optional sint32 duration = 7;
optional sint32 popularity = 8;
optional bool explicit = 9;
repeated ExternalId external_id = 10;
repeated Restriction restriction = 11;
repeated AudioFile file = 12;
repeated Track alternative = 13;
repeated SalePeriod sale_period = 14;
repeated AudioFile preview = 15;
}
message Image {
enum Size {
DEFAULT = 0;
SMALL = 1;
LARGE = 2;
XLARGE = 3;
}
optional bytes file_id = 1;
optional Size size = 2;
optional sint32 width = 3;
optional sint32 height = 4;
}
message ImageGroup {
repeated Image image = 1;
}
message Biography {
optional string text = 1;
repeated Image portrait = 2;
repeated ImageGroup portrait_group = 3;
}
message Disc {
optional sint32 number = 1;
optional string name = 2;
repeated Track track = 3;
}
message Copyright {
enum Type {
P = 0;
C = 1;
}
optional Type type = 1;
optional string text = 2;
}
message Restriction {
enum Catalogue {
FREE = 0;
PREMIUM = 1;
SHUFFLE = 3;
COMMERCIAL = 4;
}
enum Type {
STREAMING = 0;
}
repeated Catalogue catalogue = 1;
optional string countries_allowed = 2;
optional string countries_forbidden = 3;
optional Type type = 4;
repeated string usage = 5;
}
message SalePeriod {
repeated Restriction restriction = 1;
optional Date start = 2;
optional Date end = 3;
}
message ExternalId {
optional string type = 1;
optional string id = 2;
}
message AudioFile {
enum Format {
OGG_VORBIS_96 = 0;
OGG_VORBIS_160 = 1;
OGG_VORBIS_320 = 2;
MP3_256 = 3;
MP3_320 = 4;
MP3_160 = 5;
MP3_96 = 6;
OTHER1 = 7; // TODO
OTHER2 = 8; // TODO
}
optional bytes gid = 1;
optional Format format = 2;
}

92
protocol/spirc.proto Normal file
View file

@ -0,0 +1,92 @@
enum MessageType {
kMessageTypeHello = 1;
kMessageTypeGoodbye = 2;
kMessageTypeNotify = 10;
kMessageTypeLoad = 20;
kMessageTypePlay = 21;
kMessageTypePause = 22;
// kMessageTypePlayPause = 23;
kMessageTypeSeek = 24;
kMessageTypePrev = 25;
kMessageTypeNext = 26;
kMessageTypeVolume = 27;
kMessageTypeShuffle = 28;
kMessageTypeRepeat = 29;
kMessageTypeQueue = 30;
kMessageTypeVolumeDown = 31;
kMessageTypeVolumeUp = 32;
kMessageTypeAddToQueue = 33;
}
enum PlayStatus {
kPlayStatusStop = 0;
kPlayStatusPlay = 1;
kPlayStatusPause = 2;
kPlayStatusLoading = 3;
kPlayStatusError = 4;
}
message Goodbye {
required string reason = 1;
}
message State {
optional string contextURI = 0x2;
optional uint32 index = 0x3;
optional uint32 position = 0x4;
optional PlayStatus status = 0x5;
optional uint64 timestamp = 0x7;
optional string context_name = 0x8;
optional uint32 duration = 0x9;
optional uint32 data9 = 0xa;
repeated uint64 data10 = 0xb;
optional bool shuffle = 0xd;
optional bool repeat = 0xe;
optional string data12 = 0x14;
optional uint32 data13 = 0x15;
optional uint32 data14 = 0x18;
optional uint32 data15 = 0x19;
optional uint32 data16 = 0x1a;
repeated QueuedTrack queued = 0x1b;
message QueuedTrack {
optional bytes gid = 0x1;
optional string local_uri = 0x2;
optional uint32 data1 = 0x3;
}
}
message Frame {
required uint32 version = 1;
required string source = 2;
required string version_string = 3;
required uint32 msgid = 4;
required uint32 type = 5;
required DeviceInfo device = 0x7;
//required Goodbye goodbye = 0xb;
optional State state = 0xc;
optional uint32 position = 0xd;
optional uint32 volume = 0xe;
optional uint64 timestamp = 0x11;
optional string destination = 0x12;
message DeviceInfo {
optional string version = 0x1;
required bool active = 0xa;
required bool foreground = 0xb;
required uint32 volume = 0xc;
required string name = 0xd;
optional uint32 data15 = 0xe;
required uint64 activeTime = 0xf;
repeated Data17 data17 = 0x11;
message Data17 {
required uint32 data0 = 0x1;
optional uint32 data1 = 0x2;
repeated string data2 = 0x3;
}
}
}

0
protocol/spotify.proto Normal file
View file

43
src/connection.rs Normal file
View file

@ -0,0 +1,43 @@
use util;
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
use std::io::{Write,Read};
use std::net::TcpStream;
pub struct Connection {
stream: TcpStream,
}
impl Connection {
pub fn connect() -> Connection {
Connection {
stream: TcpStream::connect("lon3-accesspoint-a26.ap.spotify.com:4070").unwrap(),
}
}
pub fn send_packet(&mut self, data: &[u8]) -> Vec<u8> {
self.send_packet_prefix(&[], data)
}
pub fn send_packet_prefix(&mut self, prefix: &[u8], data: &[u8]) -> Vec<u8> {
let size = prefix.len() + 4 + data.len();
let mut buf = Vec::with_capacity(size);
buf.write(prefix).unwrap();
buf.write_u32::<BigEndian>(size as u32).unwrap();
buf.write(data).unwrap();
self.stream.write(&buf).unwrap();
buf
}
pub fn recv_packet(&mut self) -> Vec<u8> {
let size : usize = self.stream.read_u32::<BigEndian>().unwrap() as usize;
let mut buffer = util::alloc_buffer(size - 4);
self.stream.read(&mut buffer).unwrap();
buffer
}
}

91
src/cryptoutil.rs Normal file
View file

@ -0,0 +1,91 @@
use rand;
use gmp::Mpz;
use std::num::FromPrimitive;
use crypto;
use crypto::mac::Mac;
use std::io::Write;
use util;
lazy_static! {
static ref DH_GENERATOR: Mpz = Mpz::from_u64(0x2).unwrap();
static ref DH_PRIME: Mpz = Mpz::from_bytes_be(&[
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc9,
0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, 0xc4, 0xc6,
0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, 0x29, 0x02, 0x4e,
0x08, 0x8a, 0x67, 0xcc, 0x74, 0x02, 0x0b, 0xbe, 0xa6,
0x3b, 0x13, 0x9b, 0x22, 0x51, 0x4a, 0x08, 0x79, 0x8e,
0x34, 0x04, 0xdd, 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a,
0x43, 0x1b, 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14,
0x37, 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45,
0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, 0xf4,
0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff ]);
}
pub struct Crypto {
private_key: Mpz,
public_key: Mpz,
shared: Option<SharedKeys>,
}
pub struct SharedKeys {
pub challenge: Vec<u8>,
pub send_key: Vec<u8>,
pub recv_key: Vec<u8>
}
impl Crypto {
pub fn new() -> Crypto {
let key_data = util::rand_vec(&mut rand::thread_rng(), 95);
Self::new_with_key(&key_data)
}
pub fn new_with_key(key_data: &[u8]) -> Crypto {
let private_key = Mpz::from_bytes_be(key_data);
let public_key = DH_GENERATOR.powm(&private_key, &DH_PRIME);
Crypto {
private_key: private_key,
public_key: public_key,
shared: None,
}
}
pub fn setup(&mut self, remote_key: &[u8], client_packet: &[u8], server_packet: &[u8]) {
let shared_key = Mpz::from_bytes_be(remote_key).powm(&self.private_key, &DH_PRIME);
let mut data = Vec::with_capacity(0x54);
let mut h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &shared_key.to_bytes_be());
for i in 1..6 {
h.input(client_packet);
h.input(server_packet);
h.input(&[i]);
data.write(&h.result().code()).unwrap();
h.reset();
}
h = crypto::hmac::Hmac::new(crypto::sha1::Sha1::new(), &data[..0x14]);
h.input(client_packet);
h.input(server_packet);
self.shared = Some(SharedKeys{
challenge: h.result().code().to_vec(),
send_key: data[0x14..0x34].to_vec(),
recv_key: data[0x34..0x54].to_vec()
});
}
pub fn public_key(&self) -> Vec<u8> {
return self.public_key.to_bytes_be();
}
pub fn shared(&self) -> &SharedKeys {
match self.shared {
Some(ref shared) => shared,
None => panic!("ABC")
}
}
}

28
src/main.rs Normal file
View file

@ -0,0 +1,28 @@
#![crate_name = "librespot"]
#![feature(plugin,core)]
#![plugin(mod_path)]
#![plugin(protobuf_macros)]
#[macro_use] extern crate lazy_static;
extern crate byteorder;
extern crate crypto;
extern crate gmp;
extern crate num;
extern crate protobuf;
extern crate rand;
mod connection;
mod cryptoutil;
mod protocol;
mod session;
mod util;
use session::Session;
fn main() {
let mut s = Session::new();
s.login();
}

3
src/protocol.rs Normal file
View file

@ -0,0 +1,3 @@
mod_path! keyexchange (concat!(env!("OUT_DIR"), "/keyexchange.rs"));
mod_path! authentication (concat!(env!("OUT_DIR"), "/authentication.rs"));

78
src/session.rs Normal file
View file

@ -0,0 +1,78 @@
use connection::Connection;
use cryptoutil::Crypto;
use protocol;
use util;
use std::iter::{FromIterator,repeat};
use protobuf::*;
use rand::thread_rng;
pub struct Session {
connection: Connection,
crypto: Crypto,
}
impl Session {
pub fn new() -> Session {
Session {
connection: Connection::connect(),
crypto: Crypto::new(),
}
}
pub fn login(&mut self) {
let request = protobuf_init!(protocol::keyexchange::Request::new(), {
data0 => {
data0: 0x05,
data1: 0x01,
data2: 0x10800000000,
},
data1: 0,
data2.data0 => {
data0: self.crypto.public_key(),
data1: 1,
},
random: util::rand_vec(&mut thread_rng(), 0x10),
data4: vec![0x1e],
data5: vec![0x08, 0x01]
});
let init_client_packet =
self.connection.send_packet_prefix(&[0,4], &request.write_to_bytes().unwrap());
let init_server_packet =
self.connection.recv_packet();
let response : protocol::keyexchange::Response =
parse_from_bytes(&init_server_packet).unwrap();
protobuf_bind!(response, { data.data0.data0.data0: remote_key });
self.crypto.setup(&remote_key, &init_client_packet, &init_server_packet);
return;
let appkey = vec![];
let request = protobuf_init!(protocol::authentication::AuthRequest::new(), {
credentials => {
username: "USERNAME".to_string(),
method: protocol::authentication::AuthRequest_LoginMethod::PASSWORD,
password: b"PASSWORD".to_vec(),
},
data1 => {
data0: 0,
data1: 0,
partner: "Partner blabla".to_string(),
deviceid: "abc".to_string()
},
version: "master-v1.8.0-gad9e5b46".to_string(),
data3 => {
data0: 1,
appkey1: appkey[0x1..0x81].to_vec(),
appkey2: appkey[0x81..0x141].to_vec(),
data3: "".to_string(),
data4: Vec::from_iter(repeat(0).take(20))
}
});
//println!("{:?}", response);
}
}

20
src/util.rs Normal file
View file

@ -0,0 +1,20 @@
use rand::{Rng,Rand};
pub fn rand_vec<G: Rng, R: Rand>(rng: &mut G, size: usize) -> Vec<R> {
let mut vec = Vec::with_capacity(size);
for _ in 0..size {
vec.push(R::rand(rng));
}
return vec
}
pub fn alloc_buffer(size: usize) -> Vec<u8> {
let mut vec = Vec::with_capacity(size);
unsafe {
vec.set_len(size);
}
vec
}