// DO NOT INSTALL THIS IN YOUR common.js!
const DEFAULT_SETTINGS = {
skin : "vector",
nologin : true
};
const CONFIG_SRC = "https://en.wikipedia.org/w/index.php?title=User:Suffusion_of_Yellow/AnonSettings/config.js&action=raw&ctype=text/javascript";
function saveSettings(settings) {
return self.caches.open("anonsettings")
.then(cache => cache.put("/anonsettings/data", new Response(JSON.stringify(settings))));
}
function getSettings() {
return self.caches.open("anonsettings")
.then(cache => cache.match("/anonsettings/data"))
.then(settings => settings ? settings.json() : DEFAULT_SETTINGS);
}
function injectSettingsScript(response, settings) {
return response.text()
.then(text => new Response(text.replace(
/<\/body>\s*<\/html>\s*$/,
`<script>const ANON_SETTINGS=${JSON.stringify(settings)};</script><script src="${CONFIG_SRC}"></script>$&`), {
headers : response.headers
}));
}
function getResponse(event, url, settings) {
// Unregister if attempting to log in
if (settings.nologin && url.pathname == "/w/index.php" && url.searchParams.get("title") == "Special:UserLogin") {
return self.registration.unregister()
.then(() => fetch(event.request));
}
if (settings.skin && !url.searchParams.get("useskin"))
url.searchParams.set("useskin", settings.skin);
if (settings.lang && !url.searchParams.get("uselang"))
url.searchParams.set("uselang", settings.lang);
if (settings.gadget && !url.searchParams.get("withgadget"))
url.searchParams.set("withgadget", settings.gadget);
let options = {};
for (let option of ["method", "headers", "credentials", "cache", "redirect", "referrer", "referrerPolicy", "integrity"])
if (option in event.request)
options[option] = event.request[option];
if (url.pathname == "/wiki/User:Suffusion_of_Yellow/AnonSettings/Setup") {
return fetch(new Request(url, options))
.then(response => injectSettingsScript(response, settings))
.catch(e => getErrorResponse(e));
}
if (event.request.method == "GET" || event.request.method == "HEAD")
return fetch(new Request(url, options)).catch(e => getErrorResponse(e));
return event.request.blob()
.then(body => {
options.body = body;
return fetch(new Request(url, options)).catch(e => getErrorResponse(e));
});
}
function getErrorResponse(err) {
if (!self.navigator.userAgent.includes("Firefox"))
return null; // Trigger network error in client
// Apparently Firefox will "helpfully" remove the ServiceWorker after
// too many network errors. So send a fake 503 response instead.
return new Response(`AnonSettings: ${err}`, {
status: 503
});
}
// Flush out any buggy old versions, at least while still in development
self.addEventListener('install', event => {
self.skipWaiting();
});
self.addEventListener('activate', event => {
event.waitUntil(self.clients.claim());
});
self.addEventListener('message', event => {
if (event.data && event.data.settings)
event.waitUntil(saveSettings(event.data.settings));
});
self.addEventListener('fetch', event => {
let url = new URL(event.request.url);
if (url.origin !== self.location.origin)
return;
// Safe mode means "no user scripts", which I guess should include this one
if (url.searchParams.get("safemode"))
return;
// Hack to detect an already logged-in session. This is the only
// non-"navigate" request we look at and we don't modify it
if (url.pathname == "/w/load.php" && url.searchParams.get("modules") && url.searchParams.get("modules").split("|").includes("user")) {
event.waitUntil(getSettings().then(settings => {
if (settings.nologin)
self.registration.unregister();
}));
return;
}
// Ignore JS, CSS, etc.
if (event.request.mode !== "navigate")
return;
// Don't add irritating warnings to every API help page...
if (!url.pathname.match(/^\/w\/index.php$|^\/$|^\/wiki/))
return;
// Fallback uninstallation link, in case the settings page fails to load
if (url.pathname == "/wiki/User:Suffusion_of_Yellow/AnonSettings/Uninstall" ) {
event.respondWith(self.registration.unregister()
.then(() => Response.redirect("/")));
return;
}
// Default response if offline
if (!self.navigator.onLine)
return;
event.respondWith(getSettings().then(settings => getResponse(event, url, settings)));
});
// DO NOT INSTALL THIS IN YOUR common.js!