mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
fix(desktop): use IPv4 loopback for media proxy URLs (#1245)
Signed-off-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co> Co-authored-by: npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta <d8473ee32b973aa31a21a65adddcc4b69cc2a8a4dee8121ecd51926e0cddbc02@sprout-oss.stage.blox.sqprod.co>
This commit is contained in:
co-authored by
npub1mprnacetjua2xx3p5eddmhxyk6wv929ymm5py8kd2xfxurxahspqqlgyta
parent
856815994c
commit
cee2c5f263
@@ -0,0 +1,13 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
|
||||
import { mediaProxyUrl } from "./mediaUrl.ts";
|
||||
|
||||
const HASH = "a".repeat(64);
|
||||
|
||||
test("mediaProxyUrl: uses the IPv4 loopback literal for the localhost proxy", () => {
|
||||
assert.equal(
|
||||
mediaProxyUrl(54321, `${HASH}.png`),
|
||||
`http://127.0.0.1:54321/media/${HASH}.png`,
|
||||
);
|
||||
});
|
||||
@@ -80,9 +80,18 @@ export function resetMediaCaches(): void {
|
||||
cachedRelayOrigin = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the local proxy URL with an IPv4 literal. The Rust proxy binds
|
||||
* `127.0.0.1:0`, not `::1`, and some WebViews resolve `localhost` to IPv6
|
||||
* first. Matching the bind address avoids machine-dependent image failures.
|
||||
*/
|
||||
export function mediaProxyUrl(port: number, mediaPath: string): string {
|
||||
return `http://127.0.0.1:${port}/media/${mediaPath}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* If `url` is a Blossom media URL hosted on the Buzz relay, rewrite it
|
||||
* to go through the localhost streaming proxy. External Blossom URLs and
|
||||
* to go through the local streaming proxy. External Blossom URLs and
|
||||
* non-Blossom URLs are returned unchanged.
|
||||
*
|
||||
* Falls back to buzz-media:// if the proxy port isn't available yet.
|
||||
@@ -100,7 +109,7 @@ export function rewriteRelayUrl(url: string): string {
|
||||
}
|
||||
|
||||
if (cachedPort && cachedPort > 0) {
|
||||
return `http://localhost:${cachedPort}/media/${m[1]}`;
|
||||
return mediaProxyUrl(cachedPort, m[1]);
|
||||
}
|
||||
|
||||
// Kick off fetch if we haven't yet.
|
||||
|
||||
@@ -674,7 +674,7 @@ const KIND_REACTION = 7; // NIP-25 reaction
|
||||
const KIND_DELETION = 5; // NIP-09 deletion
|
||||
|
||||
// Fake media-proxy port the mock answers for `get_media_proxy_port`, so
|
||||
// `rewriteRelayUrl()` produces a real `http://localhost:<port>/media/...` src
|
||||
// `rewriteRelayUrl()` produces a real `http://127.0.0.1:<port>/media/...` src
|
||||
// in e2e (instead of the `buzz-media://` fallback). The reaction guard
|
||||
// asserts against this exact port.
|
||||
const MOCK_MEDIA_PROXY_PORT = 54321;
|
||||
|
||||
@@ -141,14 +141,14 @@ test("native emoji-only messages leave space below the author metadata", async (
|
||||
//
|
||||
// This drives the real interactive react flow (hover -> Open reactions ->
|
||||
// emoji-mart custom category) so it exercises the add_reaction Tauri command,
|
||||
// then asserts the rendered reaction <img> src points at the localhost media
|
||||
// then asserts the rendered reaction <img> src points at the loopback media
|
||||
// proxy. On the pre-fix code the src would be the raw relay URL, so this test
|
||||
// fails there — exactly the assertion that would have caught the bug.
|
||||
//
|
||||
// `:react:` is a relay-hosted fixture emoji (URL on the relay origin matching
|
||||
// rewriteRelayUrl()'s /media/{64-hex}.{ext} pattern), and the mock bridge
|
||||
// answers get_media_proxy_port with port 54321 so the rewrite resolves to a
|
||||
// real localhost URL rather than the buzz-media:// fallback.
|
||||
// real 127.0.0.1 URL rather than the buzz-media:// fallback.
|
||||
|
||||
const REACTION_SHORTCODE = "react";
|
||||
const MOCK_MEDIA_PROXY_PORT = 54321;
|
||||
@@ -214,7 +214,7 @@ test("message quick reaction tray stays neutral after selecting a tray emoji", a
|
||||
);
|
||||
});
|
||||
|
||||
test("reacting with a custom emoji renders via the localhost media proxy", async ({
|
||||
test("reacting with a custom emoji renders via the loopback media proxy", async ({
|
||||
page,
|
||||
}) => {
|
||||
await openGeneral(page);
|
||||
@@ -236,7 +236,7 @@ test("reacting with a custom emoji renders via the localhost media proxy", async
|
||||
.click();
|
||||
|
||||
// The reaction pill renders the custom emoji as an <img alt=":react:">. Its
|
||||
// src must be the localhost proxy URL — proving rewriteRelayUrl() ran. A raw
|
||||
// src must be the loopback proxy URL — proving rewriteRelayUrl() ran. A raw
|
||||
// relay URL here is the bug.
|
||||
const reactionPill = row.getByLabel(
|
||||
`Toggle :${REACTION_SHORTCODE}: reaction`,
|
||||
@@ -248,7 +248,7 @@ test("reacting with a custom emoji renders via the localhost media proxy", async
|
||||
await expect(reactionImg).toHaveAttribute(
|
||||
"src",
|
||||
new RegExp(
|
||||
`^http://localhost:${MOCK_MEDIA_PROXY_PORT}/media/[\\da-f]{64}\\.png$`,
|
||||
`^http://127\\.0\\.0\\.1:${MOCK_MEDIA_PROXY_PORT}/media/[\\da-f]{64}\\.png$`,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user