Skip to content

Commit

Permalink
Merge pull request #1230 from dsheets/cargo-replace-hex-with-data-enc…
Browse files Browse the repository at this point in the history
…oding

Cargo replace hex with data-encoding
  • Loading branch information
roderickvd authored Dec 15, 2023
2 parents f7ffa9a + 0fbd19b commit a245a3c
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 28 deletions.
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ path = "protocol"
version = "0.5.0-dev"

[dependencies]
data-encoding = "2.5"
env_logger = { version = "0.10", default-features = false, features = ["color", "humantime", "auto-color"] }
futures-util = { version = "0.3", default_features = false }
getopts = "0.2"
hex = "0.4"
log = "0.4"
rpassword = "7.0"
sha1 = "0.10"
Expand Down
2 changes: 1 addition & 1 deletion core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ form_urlencoded = "1.0"
futures-core = "0.3"
futures-util = { version = "0.3", features = ["alloc", "bilock", "sink", "unstable"] }
governor = { version = "0.6", default-features = false, features = ["std", "jitter"] }
hex = "0.4"
hmac = "0.12"
httparse = "1.7"
http = "0.2"
Expand Down Expand Up @@ -57,6 +56,7 @@ tokio-tungstenite = { version = "*", default-features = false, features = ["rust
tokio-util = { version = "0.7", features = ["codec"] }
url = "2"
uuid = { version = "1", default-features = false, features = ["fast-rng", "v4"] }
data-encoding = "2.5"

[build-dependencies]
rand = "0.8"
Expand Down
14 changes: 10 additions & 4 deletions core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ pub struct SessionConfig {
pub autoplay: Option<bool>,
}

impl Default for SessionConfig {
fn default() -> SessionConfig {
impl SessionConfig {
pub(crate) fn default_for_os(os: &str) -> Self {
let device_id = uuid::Uuid::new_v4().as_hyphenated().to_string();
let client_id = match std::env::consts::OS {
let client_id = match os {
"android" => ANDROID_CLIENT_ID,
"ios" => IOS_CLIENT_ID,
_ => KEYMASTER_CLIENT_ID,
}
.to_owned();

SessionConfig {
Self {
client_id,
device_id,
proxy: None,
Expand All @@ -37,6 +37,12 @@ impl Default for SessionConfig {
}
}

impl Default for SessionConfig {
fn default() -> Self {
Self::default_for_os(std::env::consts::OS)
}
}

#[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub enum DeviceType {
Unknown = 0,
Expand Down
44 changes: 27 additions & 17 deletions core/src/spclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{

use byteorder::{BigEndian, ByteOrder};
use bytes::Bytes;
use data_encoding::HEXUPPER_PERMISSIVE;
use futures_util::future::IntoStream;
use http::header::HeaderValue;
use hyper::{
Expand Down Expand Up @@ -189,9 +190,10 @@ impl SpClient {
// on macOS and Windows. On Android and iOS we can send a platform-specific client ID and are
// then presented with a hash cash challenge. On Linux, we have to pass the old keymaster ID.
// We delegate most of this logic to `SessionConfig`.
let client_id = match OS {
let os = OS;
let client_id = match os {
"macos" | "windows" => self.session().client_id(),
_ => SessionConfig::default().client_id,
os => SessionConfig::default_for_os(os).client_id,
};
client_data.client_id = client_id;

Expand All @@ -206,7 +208,7 @@ impl SpClient {
let os_version = sys.os_version().unwrap_or_else(|| String::from("0"));
let kernel_version = sys.kernel_version().unwrap_or_else(|| String::from("0"));

match OS {
match os {
"windows" => {
let os_version = os_version.parse::<f32>().unwrap_or(10.) as i32;
let kernel_version = kernel_version.parse::<i32>().unwrap_or(21370);
Expand Down Expand Up @@ -269,7 +271,10 @@ impl SpClient {
match ClientTokenResponseType::from_i32(message.response_type.value()) {
// depending on the platform, you're either given a token immediately
// or are presented a hash cash challenge to solve first
Some(ClientTokenResponseType::RESPONSE_GRANTED_TOKEN_RESPONSE) => break message,
Some(ClientTokenResponseType::RESPONSE_GRANTED_TOKEN_RESPONSE) => {
debug!("Received a granted token");
break message;
}
Some(ClientTokenResponseType::RESPONSE_CHALLENGES_RESPONSE) => {
debug!("Received a hash cash challenge, solving...");

Expand All @@ -279,20 +284,22 @@ impl SpClient {
let hash_cash_challenge = challenge.evaluate_hashcash_parameters();

let ctx = vec![];
let prefix = hex::decode(&hash_cash_challenge.prefix).map_err(|e| {
Error::failed_precondition(format!(
"Unable to decode hash cash challenge: {e}"
))
})?;
let prefix = HEXUPPER_PERMISSIVE
.decode(hash_cash_challenge.prefix.as_bytes())
.map_err(|e| {
Error::failed_precondition(format!(
"Unable to decode hash cash challenge: {e}"
))
})?;
let length = hash_cash_challenge.length;

let mut suffix = vec![0; 0x10];
let mut suffix = [0u8; 0x10];
let answer = Self::solve_hash_cash(&ctx, &prefix, length, &mut suffix);

match answer {
Ok(_) => {
// the suffix must be in uppercase
let suffix = hex::encode(suffix).to_uppercase();
let suffix = HEXUPPER_PERMISSIVE.encode(&suffix);

let mut answer_message = ClientTokenRequest::new();
answer_message.request_type =
Expand All @@ -302,7 +309,7 @@ impl SpClient {
let challenge_answers = answer_message.mut_challenge_answers();

let mut challenge_answer = ChallengeAnswer::new();
challenge_answer.mut_hash_cash().suffix = suffix.to_string();
challenge_answer.mut_hash_cash().suffix = suffix;
challenge_answer.ChallengeType =
ChallengeType::CHALLENGE_HASH_CASH.into();

Expand Down Expand Up @@ -477,11 +484,14 @@ impl SpClient {
HeaderValue::from_str(&format!("{} {}", token.token_type, token.access_token,))?,
);

if let Ok(client_token) = self.client_token().await {
headers_mut.insert(CLIENT_TOKEN, HeaderValue::from_str(&client_token)?);
} else {
// currently these endpoints seem to work fine without it
warn!("Unable to get client token. Trying to continue without...");
match self.client_token().await {
Ok(client_token) => {
let _ = headers_mut.insert(CLIENT_TOKEN, HeaderValue::from_str(&client_token)?);
}
Err(e) => {
// currently these endpoints seem to work fine without it
warn!("Unable to get client token: {e} Trying to continue without...")
}
}

last_response = self.session().http_client().request_body(request).await;
Expand Down
3 changes: 2 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use data_encoding::HEXLOWER;
use futures_util::StreamExt;
use log::{debug, error, info, trace, warn};
use sha1::{Digest, Sha1};
Expand Down Expand Up @@ -39,7 +40,7 @@ mod player_event_handler;
use player_event_handler::{run_program_on_sink_events, EventHandler};

fn device_id(name: &str) -> String {
hex::encode(Sha1::digest(name.as_bytes()))
HEXLOWER.encode(&Sha1::digest(name.as_bytes()))
}

fn usage(program: &str, opts: &getopts::Options) -> String {
Expand Down

0 comments on commit a245a3c

Please sign in to comment.