Jump to content

User:Suffusion of Yellow/AnonSettings/sw.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// 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!