const internals = { kStyleSheet: "/security/style.css", kClientSettingsURL: "/auth/client-settings.json", kOpenLockSVG: '', kLockSVG: '', kKeySVG: '', settings: {}, makeLinkWithIcon(href, id, classes, title, icon) { const link = document.createElement("a"); link.href = href; link.id = id; link.title = title; link.classList.add(...classes); link.innerHTML = icon; return link; }, }; const oidcSecurity = { async setup() { const hasStyleSheet = [...document.styleSheets].some((styleSheet) => styleSheet?.href?.endsWith(internals.kStyleSheet), ); if (!hasStyleSheet) { console.log("Adding security stylesheet."); const link = document.createElement("link"); link.rel = "stylesheet"; link.href = internals.kStyleSheet; link.type = "text/css"; document.getElementsByTagName("head")[0].appendChild(link); } const response = await fetch(internals.kClientSettingsURL, { cache: "no-cache", mode: "same-origin", }); if (response.ok) { const clientSettings = await response.json(); window.isOwner = clientSettings.isOwner; internals.settings = clientSettings; let dialogHost = window.location.hostname; if (internals.settings.wikiHost) { dialogHost = clientSettings.wikiHost; } internals.settings.cookieDomain = dialogHost; if (window.location.port) { dialogHost = `${dialogHost}:${window.location.port}`; } let dialogProtocol = window.location.protocol; if (internals.settings.useHttps) { dialogProtocol = "https:"; } const dialogOrigin = `${dialogProtocol}//${dialogHost}`; internals.settings.dialogOrigin = dialogOrigin; internals.settings.dialogURL = `${dialogOrigin}${internals.settings.loginURL}`; oidcSecurity.updateFooter(window.ownerName, window.isAuthenticated); // Subscription to the dialog messages. window.addEventListener("message", async (event) => { if (event.origin !== internals.settings.dialogOrigin) { return; } if (event.data?.event === "loginDone") { if ( internals.settings.claimOnFirstLogin && !window.isClaimed ) { await oidcSecurity.claimWiki(); } window.location.reload(); } }); } else { console.log("Unable to fetch client settings: ", response); } }, async claimWiki() { if (!window.isClaimed) { const response = await fetch(internals.settings.claimURL, { cache: "no-cache", mode: "same-origin", credentials: "same-origin", }); if (response.ok) { const json = await response.json(); if (wiki.lineup.bestTitle() === "Login Required") { location.reload(); } else { const { owner } = json; window.isClaimed = true; window.isOwner = true; oidcSecurity.updateFooter(owner, true); } } else { console.log("Attempt to claim site failed", response); } } }, updateFooter(ownerName, isAuthenticated) { if (ownerName) { document.querySelector("footer > #site-owner").innerHTML = `Site Owned by: ${ownerName}`; } document.querySelector("footer > #security").innerHTML = ""; if (isAuthenticated) { let logoutTitle = "Not Owner : Sign-out"; let logoutIcon = internals.kLockSVG; let logoutClass = ["footer-item", "notOwner"]; if (window.isOwner) { logoutTitle = "Sign-out"; logoutIcon = internals.kOpenLockSVG; logoutClass = ["footer-item"]; } const logoutLink = internals.makeLinkWithIcon( internals.settings.logoutURL, "logout", logoutClass, logoutTitle, logoutIcon, ); document.querySelector("footer > #security").append(logoutLink); logoutLink.addEventListener("click", async (event) => { event.preventDefault(); const response = await fetch(internals.settings.logoutURL, { cache: "no-cache", mode: "same-origin", credentials: "same-origin", }); if (response.ok) { window.isAuthenticated = false; window.user = ""; document.cookie = `state=loggedOut;domain=.${internals.settings.cookieDomain}; path=/; max-age=60; sameSite=Strict;`; oidcSecurity.updateFooter(ownerName, false); } else { console.log("Logout failed: ", response); } }); if (!window.isClaimed) { const claimLink = internals.makeLinkWithIcon( internals.settings.claimURL, "claim", ["footer-item", "claim"], "Claim this Wiki", internals.kKeySVG, ); document.querySelector("footer > #security").append(claimLink); claimLink.addEventListener("click", (event) => { event.preventDefault(); oidcSecurity.claimWiki(); }); } } else { let signOnTitle = "Claim this wiki"; if (window.isClaimed) { signOnTitle = "Wiki Owner Sign-on"; } const securityLink = internals.makeLinkWithIcon( internals.settings.dialogURL, "show-security-dialog", ["footer-item"], signOnTitle, internals.kLockSVG, ); document.querySelector("footer > #security").append(securityLink); securityLink.addEventListener("click", (event) => { event.preventDefault(); document.cookie = `wikiName=${window.location.host};domain=.${internals.settings.cookieDomain}; path=/; max-age=300; sameSite=Strict;`; // This dialog will emit a loginDone event when done. // We listen to it to refresh. window.open( internals.settings.dialogURL, "oidc", "popup,height=600,width=375", ); }); } }, }; window.plugins.security = oidcSecurity;