aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/app.js
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/app.js')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/app.js33
1 files changed, 31 insertions, 2 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js
index a48535a..abb3374 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/app.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js
@@ -6,10 +6,15 @@ import { t, getLocale, setLocale, initLocale, LOCALES } from './i18n.js';
import { ZipStream, entriesUnder } from './zipstream.js';
import { transfers, formatSpeed } from './transfers.js';
import * as downloads from './downloads.js';
+import * as platform from './platform.js';
// ── Constants ────────────────────────────────────────────────────────────────
-const HUB = '';
+// Where the hub is. Empty in a browser — it served this page, so a relative
+// path cannot be pointed at the wrong place. In the installed app the page
+// comes from disk and has no origin of its own, so the base is configured.
+// See platform.js.
+const HUB = platform.hubBase();
const AUTH_KEY = 'mb_auth';
// Renew an access token with this much life left rather than waiting for it to
// fail. Generous against a one-hour token: a film is watched without the hub
@@ -1323,7 +1328,9 @@ function GroupPage({ groupId, group, token, username, userId, onRefreshAuth,
// connection at all. Renewals are shared, so if one is already in
// flight this waits for it instead of starting a second.
const live = (await ensureFreshToken()) || token;
- const transport = new window.MeshBayTransport('', live);
+ // The same base the API calls use: signaling is a hub endpoint like
+ // any other, and two sources for one address is how they drift.
+ const transport = new window.MeshBayTransport(HUB, live);
transportRef.current = transport;
const ack = await transport.connect(
@@ -3941,6 +3948,15 @@ function SettingsPage({ user, theme, onThemeChange, groups }) {
// Read from the hub rather than written here: the two constants that used to
// sit in this markup said 0.1.0 and MNP 0.1 long after both had moved on.
const [hubInfo, setHubInfo] = useState(null);
+ // On a desktop build, whether the OS is really holding the keys. Electron's
+ // safeStorage falls back to a fixed key when no keyring is running — a
+ // headless session, a minimal desktop — and does it silently. Somebody who
+ // believes the OS is protecting their keys deserves to be told when it is not.
+ const [keyBackend, setKeyBackend] = useState('');
+ useEffect(() => {
+ if (!platform.secrets.available) return;
+ platform.secrets.backend().then(setKeyBackend).catch(() => {});
+ }, []);
useEffect(() => {
hubFetch('/v1/hub/version').then(setHubInfo).catch(() => {});
@@ -4043,6 +4059,19 @@ function SettingsPage({ user, theme, onThemeChange, groups }) {
</div>
`}
+ ${keyBackend && html`
+ <div class="settings-section">
+ <h3 class="settings-heading">${t('settings.keys_heading')}</h3>
+ <div class="settings-row">
+ <span class="settings-label">${t('settings.keys_where')}</span>
+ <span class="settings-value">${keyBackend}</span>
+ </div>
+ ${keyBackend === 'unprotected_fallback' && html`
+ <p class="error-msg">${t('settings.keys_unprotected')}</p>
+ `}
+ </div>
+ `}
+
<div class="settings-section">
<h3 class="settings-heading">${t('settings.about')}</h3>
<div class="settings-row">