fix: buzzheavier through the browser with its file server captured

This commit is contained in:
MyLuxy committed 2026-10-17 00:31:32 +02:00
1 parent 0ec08fa08b
commit c146420192
7 files changed
+42 -15

No files matched your search

+1 -1
View File
@@ -40,7 +40,7 @@ import { FocusScope, Text, View, useIsFocused } from '@ps5-react/core';
} catch {
}
if (kind === "vikingfile") notes.push({ tone: "info", icon: "globe", key: "browserViking" });
else if (kind === "browser" || kind === "datanodes") notes.push({ tone: "info", icon: "globe", key: "browserOther" });
else if (kind === "browser" || kind === "datanodes" || kind === "buzzheavier") notes.push({ tone: "info", icon: "globe", key: "browserOther" });
const need = requiredFirmware(release);
if (need !== null && !isDlc(release)) notes.push({ tone: "info", icon: "cpu", key: "firmware", values: { need: `${need}.xx` } });
return notes;
+2
View File
@@ -26,6 +26,8 @@ import { webURL } from './download-sources.js';
// browser_url.c holds the same rules.
function opaqueFileRoute(host, path) {
if (/^a-[a-z0-9-]+\.1fichier\.com$/.test(host)) return /^\/[A-Za-z0-9]{10,256}$/.test(path);
// Buzzheavier's file server, as its Download button's hx-redirect names it.
if (/^[a-z0-9-]+\.buzzheavier\.com$/.test(host) && !host.startsWith("www.")) return /^\/d\/[A-Za-z0-9]{8,32}\?v=[A-Za-z0-9_-]{32,1024}$/.test(path);
if (/^tunnel\d+\.dlproxy\.uk$/.test(host)) return /^\/[^/?]{8}\/[^/?]{32,1024}\?sig=[^&]+$/.test(path) && /^[!-~]+$/.test(path) && !path.includes("\\");
return false;
}
+1 -1
View File
@@ -207,7 +207,7 @@ import { VIKING_PAGE_PREFIX, VIKING_PREFIX, describeVikingCapture, linkPageMetad
} : formats.artifact(release, root2);
function reresolve(job2) {
const source2 = job2.parts ? job2.currentSource : job2.release;
if ((job2.reresolved || 0) >= 2 || ["direct", "browser", "datanodes", "manifest", "unavailable"].includes(sourceKind(source2))) return false;
if ((job2.reresolved || 0) >= 2 || ["direct", "browser", "datanodes", "buzzheavier", "manifest", "unavailable"].includes(sourceKind(source2))) return false;
job2.reresolved = (job2.reresolved || 0) + 1;
delete job2.options;
if (job2.parts) delete job2.parts[job2.partIndex].options;
+3 -13
View File
@@ -127,7 +127,9 @@
if (kind === "unavailable") throw new Error("Source unavailable: no download URL.");
if (kind === "direct") return { url: webURL(url).url, rejectHtml: true };
if (kind === "manifest") throw new Error("Split manifests must be resolved by the queue.");
if (kind === "browser" || kind === "datanodes") throw new BrowserRequired(url);
// Buzzheavier's pages sit behind a Cloudflare check only a browser passes (403 to the app,
// 2026-10-17): its file link is captured from the console's browser, as Datanodes' is.
if (kind === "browser" || kind === "datanodes" || kind === "buzzheavier") throw new BrowserRequired(url);
if (kind === "filekeeper") return fileKeeper(url, signal);
const response = await request(url, { signal });
const base = response.url || url;
@@ -136,18 +138,6 @@
let candidate;
if (kind === "mediafire") candidate = anchor(html, "downloadButton");
if (kind === "vikingfile") candidate = anchor(html, "download-link");
if (kind === "buzzheavier") {
const button = (html.match(/<[a-z]+\b[^>]*>/gi) || []).find((tag) => attribute(tag, "hx-get")?.includes("/download"));
const route = button && attribute(button, "hx-get");
if (route) {
const next = await request(absolute(route, base), {
signal,
followRedirects: false,
headers: { "HX-Request": "true", "HX-Current-URL": base }
});
candidate = next.headers?.["hx-redirect"] || next.headers?.location;
}
}
if (!candidate) throw new BrowserRequired(url);
return direct(absolute(candidate, base), signal);
}
+6
View File
@@ -1,5 +1,11 @@
# Changelog
## Unreleased — Buzzheavier's file server
- Anchor mode accepts Buzzheavier's file server, `<server>.buzzheavier.com/d/<id>?v=<signed token>`,
which its Download button's `hx-redirect` answer names and which carries no file name (observed
2026-10-17; the file's name comes in its Content-Disposition). Its pages stay on the bare domain.
## Unreleased — links up to 2047 bytes
- A captured link may be up to 2047 bytes (was 543, Orbit Store's limit): FileKeeper hands its file
@@ -113,6 +113,19 @@ static bool opaque_file_route(const char *host, size_t length, const char *path)
if (!token((unsigned char)*at)) return false;
return size >= 10 && size <= 256;
}
/* Buzzheavier's Download button gets an hx-redirect to its file server, ts.buzzheavier.com/d/<id>
* ?v=<signed token>, which names no file: the answer's Content-Disposition does (observed
* 2026-10-17). Its page sits on buzzheavier.com itself, so a subdomain is required. */
if (host_under(host, length, "buzzheavier.com") && !host_equals(host, length, "buzzheavier.com") && !strncmp(path, "/d/", 3)) {
const char *at = path + 3;
size_t id = 0;
while (token((unsigned char)at[id])) id++;
if (id < 8 || id > 32 || strncmp(at + id, "?v=", 3)) return false;
size_t size = 0;
for (at += id + 3; *at; at++, size++)
if (!token((unsigned char)*at) && *at != '-' && *at != '_') return false;
return size >= 32 && size <= 1024;
}
if (host_under(host, length, "dlproxy.uk") && length > 17 && host_equals(host, 6, "tunnel")) {
for (size_t i = 6; i < length - 11; i++)
if (host[i] < '0' || host[i] > '9') return false;
@@ -197,6 +197,22 @@ int main(void) {
assert(!strcmp(longest.url, filekeeper));
}
}
// Buzzheavier's file server, as its Download button's hx-redirect answer names it (2026-10-17).
{
const char *buzz = "https://ts.buzzheavier.com/d/vsym6i66c6st?v=mqq2UM8yPmme6XOi01QgF6Qe7xJrqwGMtD34EAS3xFREvk1vXD7bxiLAv94SHzs6D1BV7Ai4tb_mZxkOnBw_Di69Bb2_Wv1KDh0Ns6LgpVFRX0kfPfwrwApCJRYOarUI-OVgeGHpPuBrCdZUhlzldTPZmE-hV9cBy8ALIdmNIodrM648z07x8tS-";
assert(browser_capture_anchor_url("PPSA16901", buzz) == BROWSER_CAPTURE_UNBOUND);
assert(!browser_capture_anchor_url("PPSA16901", "https://buzzheavier.com/d/vsym6i66c6st?v=mqq2UM8yPmme6XOi01QgF6Qe7xJrqwGMtD34"));
assert(!browser_capture_anchor_url("PPSA16901", "https://buzzheavier.com/vsym6i66c6st"));
assert(!browser_capture_anchor_url("PPSA16901", "https://ts.buzzheavier.com/d/vsym6i66c6st"));
assert(!browser_capture_anchor_url("PPSA16901", "https://ts.buzzheavier.com/d/vsym6i66c6st?v=short"));
assert(!browser_capture_anchor_url("PPSA16901", "https://ts.buzzheavier.com/d/vsym6i66c6st?v=mqq2UM8yPmme6XOi01QgF6Qe7xJrqwGMtD34EAS&x=1"));
assert(!browser_capture_anchor_url("PPSA16901", "https://ts.buzzheavier.com.evil.test/d/vsym6i66c6st?v=mqq2UM8yPmme6XOi01QgF6Qe7xJrqwGMtD34"));
char header[400];
snprintf(header, sizeof header, "HTTP/1.1 204 No Content\r\nhx-redirect: %s\r\n\r\n", buzz);
BrowserMatch heard = {.prefix = "https://", .filename = "PPSA16901", .anchor = true};
assert(browser_match(&heard, (const unsigned char *)header, strlen(header)));
assert(!strcmp(heard.url, buzz));
}
// Page mode: the Vikingfile file page a LinkVault vault opens, and nothing else.
assert(browser_capture_page_url("https://vikingfile.com/f/jjeEUkyPki"));
assert(browser_capture_page_url("https://vik1ngfile.site/f/jjeEUkyPki"));