Content deleted Content added
create script |
move range blocks to separate page, add range links to contributions user tools |
||
Line 1:
mw.loader.using(['mediawiki.api', 'mediawiki.util']).then(function() {
if (mw.config.get('
const userToolsBDI = document.querySelector('.mw-contributions-user-tools bdi');
const userName = userToolsBDI ? userToolsBDI.textContent.trim() : '';
const ip = extractIP(userName);
if (ip) {
addContributionsLinks(ip);
}
} else if (mw.config.get('wgCanonicalSpecialPageName') === 'Blankpage') {
const pageName = mw.config.get('wgPageName') || '';
const match = pageName.match(/^Special:BlankPage\/RangeBlocks\/(.+)$/);
if (match) {
const ip = extractIP(match[1]);
if (ip) {
addRangeBlocks(ip);
}
}
} else if (mw.config.get('wgPageName') === 'Special:Log/block') {
const pageParam = mw.util.getParamValue('page');
if (pageParam) {
const match = pageParam.match(/^User:(.+)$/);
if (match) {
const ip = extractIP(match[1]);
if (ip) {
mw.util.addPortletLink('p-tb', `/wiki/Special:BlankPage/RangeBlocks/${ip.ip}`, "Find range blocks");
}
}
}
}
return;
//
function addContributionsLinks(ip) {
const userToolsContainer = document.querySelector('.mw-contributions-user-tools .mw-changeslist-links');
if (!userToolsContainer) return;
const spans = userToolsContainer.querySelectorAll('span');
let insertBefore = null;
for (const span of spans) {
if (span.textContent.toLowerCase().includes('global')) {
insertBefore = span;
break;
}
if (!insertBefore) return;
let floor = 16, ceiling = 24, steps = 8;
if (ip.version === 6) {
floor = 32;
ceiling = 64;
if (ip.mask >= 64)
steps = 16;
}
let links = [];
const rangeBlockLink = document.createElement('a');
rangeBlockLink.href = `/wiki/Special:BlankPage/RangeBlocks/${ip.ip}`;
rangeBlockLink.textContent = 'range block log';
rangeBlockLink.className = 'mw-link-range-blocks';
links.push(rangeBlockLink);
for (let mask = floor; mask <= ceiling && mask < ip.mask; mask += steps) {
const contribsLink = document.createElement('a');
contribsLink.href = `/wiki/Special:Contributions/${ip.ip}/${mask}`;
contribsLink.textContent = `/${mask}`;
contribsLink.className = 'mw-contributions-link-range-suggestion';
links.push(contribsLink)
}
links.forEach(link => {
const span = document.createElement('span');
span.appendChild(link);
userToolsContainer.insertBefore(span, insertBefore);
});
}
// find range blocks
async function
document.title = `Range blocks for ${ip.ip}`;
const heading = document.querySelector('#firstHeading');
if (heading) {
heading.innerHTML = `Range blocks for <a href="/wiki/Special:Contributions/${ip.ip}">${ip.ip}</a>`;
}
const contentContainer = document.querySelector('#mw-content-text');
if (!contentContainer) return;
contentContainer.innerHTML = '';
let masks;
if (ip.version === 6) {
masks = Array.from({ length: 46 }, (_, i) => 64 - i);
} else {
}
const api = new mw.Api();
const statusMessage = document.createElement('p');
statusMessage.textContent = 'Querying logs for relevant IP range blocks...';
const resultsList = document.createElement('ul');
mw.hook('wikipage.content').fire($(contentContainer));
let foundBlocks = false;
for (const mask of masks) {
const range = ip.version === 6 ? maskedIPv6(ip.ip, mask) : maskedIPv4(ip.ip, mask);
const blocks = await getBlockLogs(api, range);
if (Object.keys(blocks).length > 0) {
foundBlocks = true;
Object.assign(allBlocks, blocks);
resultsList.innerHTML = '';
const sortedBlocks = Object.values(allBlocks).sort((a, b) => b.timestamp > a.timestamp ? 1 : -1);
for (const block of sortedBlocks) {
const li = document.createElement('li');
li.innerHTML = `<a href="${block.url}">${block.timestamp}</a> <a href="/wiki/User:${encodeURIComponent(block.user)}">${block.user}</a> blocked <a href="/wiki/Special:Contributions/${encodeURIComponent(block.range)}">${block.range}</a> (${block.expiry})`;
resultsList.appendChild(li);
}
}
mw.hook('wikipage.content').fire($(resultsList));
}
statusMessage.textContent = foundBlocks ? 'Range blocks:' : 'No blocks found.';
mw.hook('wikipage.content').fire($(contentContainer));
}
Line 72 ⟶ 124:
format: 'json'
});
const blocksObj = {};
response.query.logevents.forEach(event => {
user: event.user,
expiry: event.params.duration || 'indefinite',
url: mw.util.getUrl('Special:Log', { logid: event.logid }),
range: range,
};
});
return blocksObj;
}
// extract IP address
function extractIP(userName) {
const IPV4REGEX = /^((?:1?\d\d?|2[0-2]\d)\b(?:\.(?:1?\d\d?|2[0-4]\d|25[0-5])){3})(?:\/(1[6-9]|2\d|3[0-2]))?$/;
const IPV6REGEX = /^((?:[\dA-Fa-f]{1,4}:){2,7}(?:[\dA-Fa-f]{1,4}|:)?)(?:\/(19|[2-9]\d|1[01]\d|12[0-8]))?$/;
let match;
if ((match = IPV4REGEX.exec(userName) || IPV6REGEX.exec(userName))) {
const version = match[1].includes(':') ? 6 : 4;
const ip = match[1];
const mask = parseInt(match[2] || (version == 6 ? '128' : '32'), 10);
return { version, ip, mask };
}
return null;
}
|