mirror of
https://git.ethanthesleepy.one/ethanaobrien/ew
synced 2026-07-12 00:32:20 +08:00
Add client side header check for if client supports custom songs
This commit is contained in:
@@ -230,8 +230,29 @@ async fn get_clearrate_json() -> JsonValue {
|
||||
rv
|
||||
}
|
||||
|
||||
fn strip_custom_clear_rates(mut data: JsonValue) -> JsonValue {
|
||||
let ids = data["master_music_ids"].clone();
|
||||
let rates = data["all_user_clear_rate"].clone();
|
||||
let mut kept_ids = array![];
|
||||
let mut kept_rates = array![];
|
||||
for (i, id) in ids.members().enumerate() {
|
||||
if id.as_i64().unwrap_or(0) >= crate::database::custom_song::FIRST_MUSIC_ID {
|
||||
continue;
|
||||
}
|
||||
kept_ids.push(id.clone()).unwrap();
|
||||
kept_rates.push(rates[i].clone()).unwrap();
|
||||
}
|
||||
data["master_music_ids"] = kept_ids;
|
||||
data["all_user_clear_rate"] = kept_rates;
|
||||
data
|
||||
}
|
||||
|
||||
pub async fn clearrate(req: HttpRequest) -> impl Responder {
|
||||
global::api(&req, Some(get_clearrate_json().await))
|
||||
let mut data = get_clearrate_json().await;
|
||||
if !crate::router::custom_song::client_supports_custom_songs(&req) {
|
||||
data = strip_custom_clear_rates(data);
|
||||
}
|
||||
global::api(&req, Some(data))
|
||||
}
|
||||
|
||||
pub async fn ranking(req: HttpRequest, body: String) -> impl Responder {
|
||||
|
||||
@@ -80,6 +80,19 @@ pub fn disabled() -> bool {
|
||||
args.hidden || !args.enable_custom_songs
|
||||
}
|
||||
|
||||
// A client that understands custom songs advertises it with this exact header
|
||||
// on its API requests. Old / official clients don't send it, so we must NOT
|
||||
// inject custom-song data (custom master_music_ids) into the shared /api/user
|
||||
// response for them - the unresolvable ids would break the account
|
||||
const SUPPORT_HEADER: &str = "X-Custom-Songs";
|
||||
|
||||
pub fn client_supports_custom_songs(req: &HttpRequest) -> bool {
|
||||
req.headers()
|
||||
.get(SUPPORT_HEADER)
|
||||
.and_then(|v| v.to_str().ok())
|
||||
== Some("1")
|
||||
}
|
||||
|
||||
// The catalog is filtered per requesting user: private songs only show for
|
||||
// their owner, shared songs for the owner plus their shared-user list
|
||||
async fn list(req: HttpRequest, body: String) -> impl Responder {
|
||||
@@ -1247,4 +1260,43 @@ mod tests {
|
||||
});
|
||||
jzon::parse(&String::from_utf8_lossy(&body)).unwrap()
|
||||
}
|
||||
|
||||
// With the feature enabled, custom unlock ids are appended to /api/user ONLY
|
||||
// for clients that send X-Custom-Songs: 1. An old/official client (no
|
||||
// header, or a different value) gets its official unlock list untouched.
|
||||
#[test]
|
||||
fn unlock_ids_gated_on_support_header() {
|
||||
use actix_web::test::TestRequest;
|
||||
let _lock = crate::runtime::lock_test_data_path();
|
||||
|
||||
let owner = 4242;
|
||||
let music_id = database::next_music_id();
|
||||
database::insert_song(music_id, owner, &object!{music_id: music_id}, "public", &array![], false);
|
||||
// Sanity: the feature is on, so the id is visible to get_music_ids
|
||||
assert!(get_music_ids(owner).contains(music_id));
|
||||
|
||||
// Exactly what the /api/user handler appends to master_music_ids
|
||||
let appended = |req: &HttpRequest| -> JsonValue {
|
||||
if client_supports_custom_songs(req) {
|
||||
get_music_ids(owner)
|
||||
} else {
|
||||
array![]
|
||||
}
|
||||
};
|
||||
|
||||
// No header -> unsupported -> nothing appended
|
||||
let without = TestRequest::default().to_http_request();
|
||||
assert!(!client_supports_custom_songs(&without));
|
||||
assert!(appended(&without).is_empty());
|
||||
|
||||
// Correct header -> supported -> custom id appended
|
||||
let with = TestRequest::default().insert_header(("X-Custom-Songs", "1")).to_http_request();
|
||||
assert!(client_supports_custom_songs(&with));
|
||||
assert!(appended(&with).contains(music_id));
|
||||
|
||||
// Any other value is treated as an unsupporting client
|
||||
let wrong = TestRequest::default().insert_header(("X-Custom-Songs", "true")).to_http_request();
|
||||
assert!(!client_supports_custom_songs(&wrong));
|
||||
assert!(appended(&wrong).is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,10 +65,11 @@ async fn user(req: HttpRequest) -> impl Responder {
|
||||
|
||||
user["lottery_list"] = array![];
|
||||
|
||||
// Custom songs visible to this user are unlocked
|
||||
if crate::router::custom_song::client_supports_custom_songs(&req) {
|
||||
for id in crate::router::custom_song::get_music_ids(user["user"]["id"].as_i64().unwrap()).members() {
|
||||
user["master_music_ids"].push(id.as_i64().unwrap()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
global::api(&req, Some(user))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user