From 0df423a84f8f32e34fb5301d0eea2fabbffadbba Mon Sep 17 00:00:00 2001 From: archipelago Date: Thu, 8 Oct 2026 12:00:17 -0400 Subject: [PATCH 1/3] fix(ui): support secure UUIDs on LAN HTTP Avoid eager consent component crashes and registration approval failures where crypto.randomUUID is unavailable. Share the companion audio CSPRNG fallback, preserve UUIDv4/session semantics and fail closed without secure randomness. Validation: 24 focused UUID, consent mount, registration recovery and companion audio tests passed. Independent review passed; full UI typecheck/build qualification remains in progress. --- .../components/MediaRegistrationConsent.vue | 3 ++- .../MediaRegistrationConsentHttp.test.ts | 19 +++++++++++++ .../useMediaRegistrationBridge.test.ts | 13 +++++++++ neode-ui/src/composables/useCompanionAudio.ts | 12 ++------- .../composables/useMediaRegistrationBridge.ts | 5 ++-- .../src/utils/__tests__/secureUuid.test.ts | 27 +++++++++++++++++++ neode-ui/src/utils/secureUuid.ts | 13 +++++++++ 7 files changed, 79 insertions(+), 13 deletions(-) create mode 100644 neode-ui/src/components/__tests__/MediaRegistrationConsentHttp.test.ts create mode 100644 neode-ui/src/utils/__tests__/secureUuid.test.ts create mode 100644 neode-ui/src/utils/secureUuid.ts diff --git a/neode-ui/src/components/MediaRegistrationConsent.vue b/neode-ui/src/components/MediaRegistrationConsent.vue index 4f634c16..70e13b8e 100644 --- a/neode-ui/src/components/MediaRegistrationConsent.vue +++ b/neode-ui/src/components/MediaRegistrationConsent.vue @@ -41,6 +41,7 @@ #' /usr/share/nginx/html/index.html; fi"] - exec: ["sed", "-i", "s#tab-signer-v2#tab-signer-v4#g; s#tab-signer-v3#tab-signer-v4#g", "/etc/nginx/conf.d/default.conf", "/usr/share/nginx/html/index.html"] - exec: ["sed", "-i", "s#src=\"/nostr-provider.js\"#src=\"/nostr-provider.js?v=tab-signer-v4\"#g", "/etc/nginx/conf.d/default.conf", "/usr/share/nginx/html/index.html"] + # Compose the outer app-proxy prefix for NIP-98 signed URL verification. + - exec: ["sed", "-i", "s|proxy_set_header X-Forwarded-Prefix /api;|proxy_set_header X-Forwarded-Prefix $http_x_forwarded_prefix/api;|", "/etc/nginx/conf.d/default.conf"] - exec: ["nginx", "-s", "reload"] # TCP liveness on the nginx port, NOT an http GET of /. nginx binds 7777 at diff --git a/scripts/tests/test_indeehub_prefix_hook.py b/scripts/tests/test_indeehub_prefix_hook.py new file mode 100644 index 00000000..501bda94 --- /dev/null +++ b/scripts/tests/test_indeehub_prefix_hook.py @@ -0,0 +1,43 @@ +"""Offline behavior checks for the native post-install proxy prefix hook.""" +import pathlib +import subprocess +import tempfile +import unittest +import yaml + +ROOT = pathlib.Path(__file__).resolve().parents[2] + + +def prefix_hook(): + hooks = yaml.safe_load((ROOT / "apps/indeedhub/manifest.yml").read_text())["app"]["hooks"]["post_install"] + matches = [index for index, hook in enumerate(hooks) if "X-Forwarded-Prefix" in " ".join(hook.get("exec", []))] + assert len(matches) == 1 + index = matches[0] + assert hooks[index + 1] == {"exec": ["nginx", "-s", "reload"]} + return hooks[index]["exec"] + + +class IndeeHubPrefixHook(unittest.TestCase): + def test_composes_prefix_before_reload_and_is_idempotent(self): + original = "server {\n proxy_set_header Host $http_host;\n proxy_set_header X-Forwarded-Prefix /api;\n}\n" + expected = original.replace("X-Forwarded-Prefix /api;", "X-Forwarded-Prefix $http_x_forwarded_prefix/api;") + with tempfile.TemporaryDirectory() as directory: + config = pathlib.Path(directory) / "default.conf" + config.write_text(original) + args = prefix_hook() + self.assertEqual(args[-1], "/etc/nginx/conf.d/default.conf") + for _ in range(2): + subprocess.run([*args[:-1], str(config)], check=True) + self.assertEqual(config.read_text(), expected) + + def test_existing_composed_prefix_is_preserved(self): + original = "proxy_set_header X-Forwarded-Prefix $http_x_forwarded_prefix/api;\n" + with tempfile.TemporaryDirectory() as directory: + config = pathlib.Path(directory) / "default.conf" + config.write_text(original) + subprocess.run([*prefix_hook()[:-1], str(config)], check=True) + self.assertEqual(config.read_text(), original) + + +if __name__ == "__main__": + unittest.main()