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.
(async function( $, mw ) {
	'use strict';
	if ((mw.config.get('wgNamespaceNumber') === mw.config.get('wgNamespaceIds').user && mw.config.get('wgTitle') === 'GeneralNotability/SpurLookup') &&
		mw.config.get('wgAction') === 'view') {
		await mw.loader.load(['mediawiki.util', 'mediawiki.user']);
		const contentdiv = document.getElementById('spur-content');
		contentdiv.textContent = '';  // clear children
		const noScriptDiv = document.getElementById('spur-noscript');
		noScriptDiv.textContent = '';  // nuke the "you don't have the script" warning

		const ip = mw.util.getParamValue('address');
		
		if (!ip) {
			contentdiv.innerText = 'Address parameter was not specified in the URL';
			return;
		}
		if (!mw.util.isIPAddress(ip)) {
			contentdiv.innerText = `${ip} is not a valid IP address`;
			return;
		}
		
		mw.config.set("wgRelevantUserName", ip);
	
		let apiKey = mw.user.options.get('userjs-spurkey');
		if (!apiKey) {
			const mwapi = new mw.Api();
			apiKey = prompt('Please enter your Spur API key');
			if (!apiKey) {
				contentdiv.innerText = 'An API key is required to use this tool';
				return;
			}
			mw.user.options.set('userjs-spurkey', apiKey);
			await mwapi.saveOption('userjs-spurkey', apiKey);
		}
		
		// Actually send the query
		const apiUrl = `https://api.spur.us/v1/context/${ip}`;
		
		let apiResponse;
		try {
			apiResponse = $.ajax({
				async: false,
				url: apiUrl,
				headers: {'Token': apiKey},
				dataType: 'json'
			});
		} catch (err) {
			contentdiv.innerText = `Failed to query the Spur API: ${err}`;
			return;
		}
		
		console.log(apiResponse);
		const responseJson = apiResponse.responseJSON;
		let newHtml = '';
		newHtml += `This search took ${apiResponse.getResponseHeader('x-query-cost')} queries.<p/>`;
		newHtml += `You have ${apiResponse.getResponseHeader('x-balance-remaining')} queries left this month.<p/>`;
		newHtml += `
<ul>
  <li>IP: <a href="${mw.config.get('wgServer')}${mw.config.get('wgArticlePath').replace('$1', 'Special:Contributions/')}${responseJson.ip}">${responseJson.ip}</a></li>
  <li>Suspected VPN/proxy: ${responseJson.anonymous}</li>
  <li><a href="https://isprangefinder.toolforge.org/hint.php?type=asn&range=${responseJson.as.number}">AS${responseJson.as.number}</a>, belongs to ${responseJson.as.organization}</li>
`;
		if (responseJson.assignment.exists) {
			newHtml += `  <li>Assignment: ${responseJson.assignment}</li>\n`;
		}
		if (responseJson.infrastructure) {
			newHtml += `  <li>Infrastructure: ${responseJson.infrastructure}</li>\n`;
		}
		if (responseJson.devices && responseJson.devices.estimate) {
			newHtml += `  <li># devices on IP (estimated): ${responseJson.devices.estimate}</li>\n`;
		}
		if (responseJson.vpnOperators.exists) {
			newHtml += '  <li>VPN operators:\n';
			newHtml += '    <ul>';
			for (const oper of responseJson.vpnOperators.operators) {
				newHtml += `    <li>${oper.name}</li>\n`;
			}
			newHtml += '    </ul>\n  </li>\n';		
		}
		if (responseJson.geolite) {
			newHtml += `  <li>GeoLite data: ${JSON.stringify(responseJson.geolite)}</li>\n`;
		}
		if (responseJson.deviceBehaviors.exists) {
			newHtml += '  <li>Device behaviors:\n';
			newHtml += '    <ul>';
			for (const behavior of responseJson.deviceBehaviors.behaviors) {
				newHtml += `    <li>${JSON.stringify(behavior.name)}</li>\n`;
			}
			newHtml += '    </ul>\n  </li>\n';
		}
		if (responseJson.proxiedTraffic.exists) {
			newHtml += '  <li>Proxy services:\n';
			newHtml += '    <ul>';
			for (const proxy of responseJson.proxiedTraffic.proxies) {
				newHtml += `    <li>${JSON.stringify(proxy)}</li>\n`;
			}
			newHtml += '    </ul>\n  </li>\n';
		}
		if (responseJson.geoPrecision.exists) {
			newHtml += `  <li>Estimated user location: ${JSON.stringify(responseJson.geoPrecision)}</li>\n`;
		}
		if (responseJson.similarIPs.exists) {
			newHtml += '  <li>Similar IPs:\n';
			newHtml += '    <ul>';
			for (const ip of responseJson.similarIPs.ips) {
				newHtml += `    <li><a href="${mw.config.get('wgServer')}${mw.config.get('wgArticlePath').replace('$1', 'Special:Contributions/')}${ip}">${ip}</a> (<a href="https://en.wikipedia.org/wiki/User:GeneralNotability/SpurLookup?address=${ip}">query</a>)</li>\n`;
			}
			newHtml += '    </ul>\n  </li>\n';		
		}
		if (responseJson.wifi.exists) {
			newHtml += '  <li>Associated SSIDs:\n';
			newHtml += '    <ul>';
			for (const wifi of responseJson.wifi.ssids) {
				newHtml += `    <li>${wifi}</li>\n`;
			}
			newHtml += '    </ul>\n  </li>\n';
		}
		newHtml += '</ul>';
		contentdiv.innerHTML = newHtml;
	}
}) (jQuery, mediaWiki );