mirror of
https://github.com/FluxaMedia/fluxa-core.git
synced 2026-08-17 04:34:49 +00:00
fix(core): rewrite GitHub blob avatar URLs to raw.githubusercontent.com
Pack authors often paste the browsable github.com/.../blob/... URL instead of the raw one. That endpoint only serves the image after a two-hop redirect and is subject to GitHub's anti-abuse rate limiting, so some avatars in a pack would intermittently fail to load on-device even though the same URL worked fine in a browser or curl. Normalize these to the direct raw.githubusercontent.com URL during pack parsing so platforms never depend on the redirect. Also restore the rquickjs "bindgen" feature, needed to cross-compile for aarch64-linux-android since rquickjs-sys doesn't ship prebuilt bindings for that target (host builds don't need it).
This commit is contained in:
parent
02e50bc92e
commit
6c1e6fa4e8
3 changed files with 186 additions and 5 deletions
133
Cargo.lock
generated
133
Cargo.lock
generated
|
|
@ -367,6 +367,26 @@ dependencies = [
|
|||
"virtue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.72.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.10.5",
|
||||
"log",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex 1.3.0",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.11.1"
|
||||
|
|
@ -521,7 +541,7 @@ dependencies = [
|
|||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
"shlex 2.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -530,6 +550,15 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
|
|
@ -614,6 +643,17 @@ dependencies = [
|
|||
"inout 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.60"
|
||||
|
|
@ -725,6 +765,15 @@ dependencies = [
|
|||
"typewit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.10.1"
|
||||
|
|
@ -1317,6 +1366,12 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.5"
|
||||
|
|
@ -2158,6 +2213,16 @@ version = "0.2.186"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.16"
|
||||
|
|
@ -2914,6 +2979,15 @@ dependencies = [
|
|||
"wnaf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f"
|
||||
dependencies = [
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
|
|
@ -3317,6 +3391,7 @@ dependencies = [
|
|||
"either",
|
||||
"indexmap 2.14.0",
|
||||
"rquickjs-core",
|
||||
"rquickjs-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3335,12 +3410,30 @@ dependencies = [
|
|||
"rquickjs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rquickjs-macro"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7204086521740ca03f33036579801871aa5b714a0e7f68b4c2e98d68b0380bfb"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"indexmap 2.14.0",
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rquickjs-core",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rquickjs-sys"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eef73520804cf5aa4876097ac5733058d628c769eba9678e0f4dba5a4ef79703"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
]
|
||||
|
||||
|
|
@ -3789,6 +3882,12 @@ dependencies = [
|
|||
"digest 0.11.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
|
|
@ -4230,7 +4329,7 @@ dependencies = [
|
|||
"indexmap 2.14.0",
|
||||
"serde_core",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_datetime 0.7.5+spec-1.1.0",
|
||||
"toml_parser",
|
||||
"toml_writer",
|
||||
"winnow 0.7.15",
|
||||
|
|
@ -4245,6 +4344,27 @@ dependencies = [
|
|||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "1.1.1+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.25.13+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b"
|
||||
dependencies = [
|
||||
"indexmap 2.14.0",
|
||||
"toml_datetime 1.1.1+spec-1.1.0",
|
||||
"toml_parser",
|
||||
"winnow 1.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.1.2+spec-1.1.0"
|
||||
|
|
@ -4368,6 +4488,12 @@ version = "1.0.24"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.2"
|
||||
|
|
@ -5107,6 +5233,9 @@ name = "winnow"
|
|||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ p256 = { version = "0.14.0", optional = true }
|
|||
pbkdf2 = { version = "0.13.0", optional = true }
|
||||
rand = { version = "0.10.2", optional = true }
|
||||
regex = "1"
|
||||
rquickjs = { version = "0.12.1", default-features = false, features = ["std", "chrono", "loader", "dyn-load", "either", "indexmap", "futures"], optional = true }
|
||||
rquickjs = { version = "0.12.1", default-features = false, features = ["std", "chrono", "loader", "dyn-load", "either", "indexmap", "futures", "bindgen"], optional = true }
|
||||
rsa = { version = "0.9.10", features = ["sha2"], optional = true }
|
||||
scraper = { version = "0.27.0", optional = true }
|
||||
sha1 = { version = "0.11.0", optional = true }
|
||||
|
|
|
|||
|
|
@ -150,10 +150,14 @@ pub(crate) fn profile_avatar_pack_json(request_json: &str) -> Option<String> {
|
|||
let mut avatars = Vec::new();
|
||||
let mut seen_urls = HashSet::new();
|
||||
for image in images {
|
||||
let Some(url) = image.get("url").and_then(Value::as_str).map(str::trim) else {
|
||||
let Some(raw_url) = image.get("url").and_then(Value::as_str).map(str::trim) else {
|
||||
continue;
|
||||
};
|
||||
if !is_https_url(url) || !seen_urls.insert(url.to_string()) {
|
||||
if !is_https_url(raw_url) {
|
||||
continue;
|
||||
}
|
||||
let url = normalize_avatar_url(raw_url);
|
||||
if !seen_urls.insert(url.clone()) {
|
||||
continue;
|
||||
}
|
||||
let name = image
|
||||
|
|
@ -246,6 +250,34 @@ fn percent_encode(value: &str) -> String {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn normalize_avatar_url(url: &str) -> String {
|
||||
let Some(rest) = url.strip_prefix("https://github.com/") else {
|
||||
return url.to_string();
|
||||
};
|
||||
let mut blob_segments = rest.splitn(2, "/blob/");
|
||||
let Some(owner_repo) = blob_segments.next() else {
|
||||
return url.to_string();
|
||||
};
|
||||
let Some(ref_and_path) = blob_segments.next() else {
|
||||
return url.to_string();
|
||||
};
|
||||
let mut owner_repo_parts = owner_repo.splitn(2, '/');
|
||||
let (Some(owner), Some(repo)) = (owner_repo_parts.next(), owner_repo_parts.next()) else {
|
||||
return url.to_string();
|
||||
};
|
||||
if owner.is_empty() || repo.is_empty() {
|
||||
return url.to_string();
|
||||
}
|
||||
let ref_and_path = ref_and_path.split('?').next().unwrap_or(ref_and_path);
|
||||
let Some((reference, path)) = ref_and_path.split_once('/') else {
|
||||
return url.to_string();
|
||||
};
|
||||
if reference.is_empty() || path.is_empty() {
|
||||
return url.to_string();
|
||||
}
|
||||
format!("https://raw.githubusercontent.com/{owner}/{repo}/{reference}/{path}")
|
||||
}
|
||||
|
||||
fn is_https_url(value: &str) -> bool {
|
||||
let value = value.trim();
|
||||
let Some(rest) = value.strip_prefix("https://") else {
|
||||
|
|
@ -320,4 +352,24 @@ mod tests {
|
|||
assert_eq!(output["avatars"].as_array().unwrap().len(), 1);
|
||||
assert_eq!(output["avatars"][0]["name"], "A");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pack_parser_rewrites_github_blob_urls_to_raw() {
|
||||
let output: Value = serde_json::from_str(
|
||||
&profile_avatar_pack_json(
|
||||
r#"{
|
||||
"manifestUrl":"https://example.com/pack.json",
|
||||
"pack":{"title":"Hell's Paradise","images":[
|
||||
{"name":"Choubei","url":"https://github.com/eueueue292/Fusion-Profile-Avatars/blob/main/Hells%20Paradise/Choubei.PNG?raw=true&v=3"}
|
||||
]}
|
||||
}"#,
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
output["avatars"][0]["url"],
|
||||
"https://raw.githubusercontent.com/eueueue292/Fusion-Profile-Avatars/main/Hells%20Paradise/Choubei.PNG"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue