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;