T-HUB/infra/occupymedia/edge/hub-sso/chat-sso.html
glass beadian c01d121748 mobile: gateway handoff for Chat and Drive below 1024px; pin Hub theme in the SSO bootstrap
Panel consensus (the branding panel): don't mount full-app iframes on
mobile — nested scrolling, keyboard collapse and double chrome break both
Element and oCIS under the bottom tab bar. Chat and Drive render a gateway
card (same-tab handoff, matrix: deep link, signed-in-as) below 1024px; the
iframe stays on desktop. hub-sso.html pins mx_local_settings.theme to
custom-OccupyHub Dark once (version-flagged) — a device's earlier picker
choice would otherwise beat config.json's default_theme.
2026-10-13 17:41:05 +00:00

78 lines
3.4 KiB
HTML

<!doctype html>
<!--
Hub → Element sign-in bootstrap, served by the edge at
https://chat.occupymedia.cc/hub-sso.html (same origin as Element Web).
Element only completes `/?loginToken=…` when localStorage["mx_sso_hs_url"]
was set on its own origin beforehand (Lifecycle.attemptTokenLogin — normally
Element writes it when IT starts an SSO redirect). The Hub cannot write
another origin's storage, so this page does it, then hands over.
Protocol (window.postMessage, both directions origin-pinned):
page → Hub { type: "tmbh:chat-sso:need-token" }
Hub → page { type: "tmbh:chat-sso:token", loginToken }
The Hub frames this page as /hub-sso.html#expect=<mxid>; when Element
already holds a live session for that MXID no token is requested at all, so
re-opening Chat never replaces the device (and its E2EE keys).
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="referrer" content="no-referrer">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Signing in to chat…</title>
<style>html,body{margin:0;height:100%;background:#000;color:#9a9a9a;font:14px system-ui,sans-serif;display:grid;place-items:center}</style>
</head>
<body>
<p>Signing in to chat…</p>
<script>
(function () {
var HUB_ORIGINS = ["https://app.occupymedia.cc"];
// Element and the homeserver share this host (/_matrix is proxied here).
var HOMESERVER = location.origin;
// Pin the Hub theme before any handover. config.json's default_theme only
// applies to devices that never picked a theme: Element stores the choice
// in mx_local_settings on THIS origin, and this bootstrap page is the one
// place the Hub can set it. Version-flagged so a later choice in Element's
// theme picker is respected.
try {
if (localStorage.getItem("tmbh_theme_pin_v1") !== "1") {
var raw = localStorage.getItem("mx_local_settings");
var settings = raw ? JSON.parse(raw) : {};
settings.theme = "custom-OccupyHub Dark";
localStorage.setItem("mx_local_settings", JSON.stringify(settings));
localStorage.setItem("tmbh_theme_pin_v1", "1");
}
} catch (e) {}
function openElement(query) {
location.replace("/" + query);
}
// Opened directly rather than framed by the Hub: plain Element.
if (window.parent === window) return openElement("");
var expected = new URLSearchParams(location.hash.slice(1)).get("expect");
var signedInAs = localStorage.getItem("mx_user_id");
var live = localStorage.getItem("mx_has_access_token") === "true" && localStorage.getItem("mx_soft_logout") !== "true";
if (expected !== null && expected === signedInAs && live) return openElement("");
var done = false;
window.addEventListener("message", function (event) {
if (done || event.source !== window.parent || HUB_ORIGINS.indexOf(event.origin) === -1) return;
var data = event.data;
if (data === null || typeof data !== "object" || data.type !== "tmbh:chat-sso:token" || typeof data.loginToken !== "string") return;
done = true;
localStorage.setItem("mx_sso_hs_url", HOMESERVER);
localStorage.removeItem("mx_sso_is_url");
openElement("?loginToken=" + encodeURIComponent(data.loginToken));
});
// A non-matching targetOrigin is dropped by the browser, never delivered.
HUB_ORIGINS.forEach(function (origin) {
window.parent.postMessage({ type: "tmbh:chat-sso:need-token" }, origin);
});
})();
</script>
</body>
</html>