Merge branch 'trunk' into feat/encryption

This commit is contained in:
beerpsi 2023-11-16 03:37:30 +07:00 committed by GitHub
commit 27d4438e88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 66 additions and 35 deletions

View File

@ -29,8 +29,13 @@ impl Configuration {
pub struct GeneralConfiguration { pub struct GeneralConfiguration {
#[serde(default = "default_true")] #[serde(default = "default_true")]
pub enable: bool, pub enable: bool,
#[serde(default)]
#[serde(default = "default_true")]
pub export_class: bool, pub export_class: bool,
#[serde(default = "default_false")]
pub fail_over_lamp: bool,
#[serde(default = "default_timeout")] #[serde(default = "default_timeout")]
pub timeout: u64, pub timeout: u64,
} }
@ -39,6 +44,10 @@ fn default_true() -> bool {
true true
} }
fn default_false() -> bool {
false
}
fn default_timeout() -> u64 { fn default_timeout() -> u64 {
3000 3000
} }

0
src/crypto.rs Normal file
View File

View File

@ -129,7 +129,6 @@ pub fn read_hinternet_url(handle: HINTERNET) -> Result<String> {
Err(anyhow!("Could not get URL from HINTERNET handle: {ec}")) Err(anyhow!("Could not get URL from HINTERNET handle: {ec}"))
} }
/// Read all bytes of a slice into a buffer.
pub fn read_slice(buf: *const u8, len: usize) -> Result<Vec<u8>> { pub fn read_slice(buf: *const u8, len: usize) -> Result<Vec<u8>> {
let mut slice = unsafe { std::slice::from_raw_parts(buf, len) }; let mut slice = unsafe { std::slice::from_raw_parts(buf, len) };
let mut ret = Vec::with_capacity(len); let mut ret = Vec::with_capacity(len);

View File

@ -20,7 +20,7 @@ use crate::{
}, },
types::{ types::{
game::UpsertUserAllRequest, game::UpsertUserAllRequest,
tachi::{ClassEmblem, Import, ImportClasses, ImportScore}, tachi::{ClassEmblem, Difficulty, Import, ImportClasses, ImportScore},
}, },
CONFIGURATION, TACHI_IMPORT_URL, TACHI_STATUS_URL, UPSERT_USER_ALL_API_ENCRYPTED, CONFIGURATION, TACHI_IMPORT_URL, TACHI_STATUS_URL, UPSERT_USER_ALL_API_ENCRYPTED,
}; };
@ -41,6 +41,16 @@ pub fn hook_init() -> Result<()> {
.as_u64() .as_u64()
.ok_or(anyhow::anyhow!("Couldn't parse user from Tachi response"))?; .ok_or(anyhow::anyhow!("Couldn't parse user from Tachi response"))?;
let mut permissions = resp["body"]["permissions"]
.as_array()
.ok_or(anyhow!("Couldn't parse permissions from Tachi response"))?
.into_iter()
.filter_map(|v| v.as_str());
if permissions.all(|v| v != "submit_score") {
return Err(anyhow!("API key has insufficient permission. The permission submit_score must be set."));
}
info!("Logged in to Tachi with userID {user_id}"); info!("Logged in to Tachi with userID {user_id}");
let winhttpwritedata = unsafe { let winhttpwritedata = unsafe {
@ -50,12 +60,13 @@ pub fn hook_init() -> Result<()> {
}; };
unsafe { unsafe {
DetourWriteData.initialize(winhttpwritedata, winhttpwritedata_hook)?; DetourWriteData
.initialize(winhttpwritedata, winhttpwritedata_hook)?
DetourWriteData.enable()?; .enable()?;
}; };
info!("Hook successfully initialized"); info!("Hook successfully initialized");
Ok(()) Ok(())
} }
@ -191,11 +202,13 @@ fn winhttpwritedata_hook(
.user_playlog_list .user_playlog_list
.into_iter() .into_iter()
.filter_map(|playlog| { .filter_map(|playlog| {
if let Ok(score) = ImportScore::try_from(playlog) { let result =
if score.difficulty.as_str() == "WORLD'S END" { ImportScore::try_from_playlog(playlog, CONFIGURATION.general.fail_over_lamp);
return None; if result
} .as_ref()
Some(score) .is_ok_and(|v| v.difficulty != Difficulty::WorldsEnd)
{
result.ok()
} else { } else {
None None
} }

View File

@ -1,4 +1,4 @@
use anyhow::anyhow; use anyhow::Result;
use chrono::{FixedOffset, NaiveDateTime, TimeZone}; use chrono::{FixedOffset, NaiveDateTime, TimeZone};
use num_enum::TryFromPrimitive; use num_enum::TryFromPrimitive;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -68,7 +68,7 @@ pub struct ImportScore {
pub lamp: TachiLamp, pub lamp: TachiLamp,
pub match_type: String, pub match_type: String,
pub identifier: String, pub identifier: String,
pub difficulty: String, pub difficulty: Difficulty,
pub time_achieved: u128, pub time_achieved: u128,
pub judgements: Judgements, pub judgements: Judgements,
pub optional: OptionalMetrics, pub optional: OptionalMetrics,
@ -93,6 +93,28 @@ pub enum TachiLamp {
AllJusticeCritical = 4, AllJusticeCritical = 4,
} }
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, TryFromPrimitive)]
#[repr(u32)]
pub enum Difficulty {
#[serde(rename = "BASIC")]
Basic = 0,
#[serde(rename = "ADVANCED")]
Advanced = 1,
#[serde(rename = "EXPERT")]
Expert = 2,
#[serde(rename = "MASTER")]
Master = 3,
#[serde(rename = "ULTIMA")]
Ultima = 4,
#[serde(rename = "WORLD'S END")]
WorldsEnd = 5,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Judgements { pub struct Judgements {
pub jcrit: u32, pub jcrit: u32,
@ -107,11 +129,11 @@ pub struct OptionalMetrics {
pub max_combo: u32, pub max_combo: u32,
} }
impl TryFrom<UserPlaylog> for ImportScore { impl ImportScore {
type Error = anyhow::Error; pub fn try_from_playlog(p: UserPlaylog, fail_over_lamp: bool) -> Result<ImportScore> {
let lamp = if !p.is_clear && fail_over_lamp {
fn try_from(p: UserPlaylog) -> Result<ImportScore, Self::Error> { TachiLamp::Failed
let lamp = if p.is_all_justice { } else if p.is_all_justice {
if p.judge_justice + p.judge_attack + p.judge_guilty == 0 { if p.judge_justice + p.judge_attack + p.judge_guilty == 0 {
TachiLamp::AllJusticeCritical TachiLamp::AllJusticeCritical
} else { } else {
@ -133,23 +155,11 @@ impl TryFrom<UserPlaylog> for ImportScore {
}; };
let rom_major_version = p.rom_version.split('.').next().unwrap_or("2"); let rom_major_version = p.rom_version.split('.').next().unwrap_or("2");
let difficulty = match p.level { let difficulty = if rom_major_version == "1" && p.level == 4 {
0 => "BASIC", Difficulty::WorldsEnd
1 => "ADVANCED", } else {
2 => "EXPERT", Difficulty::try_from(p.level)?
3 => "MASTER", };
4 => if rom_major_version == "2" {
"ULTIMA"
} else {
"WORLD'S END"
},
5 => if rom_major_version == "2" {
"WORLD'S END"
} else {
return Err(anyhow!("difficulty index '5' should not be possible on rom_version {rom_major_version}."));
},
_ => return Err(anyhow!("unknown difficulty index {level} on major version {rom_major_version}", level=p.level)),
}.to_string();
let datetime = NaiveDateTime::parse_from_str(&p.user_play_date, "%Y-%m-%d %H:%M:%S")?; let datetime = NaiveDateTime::parse_from_str(&p.user_play_date, "%Y-%m-%d %H:%M:%S")?;
let jst_offset = let jst_offset =