Tries to detect and un-break Session IDs posted on 4chan
当前为
// ==UserScript==
// @name 4chan Session ID Unbreaker
// @license GPLv3
// @namespace https://boards.4chan.org/
// @version 1.8
// @description Tries to detect and un-break Session IDs posted on 4chan
// @author ceodoe
// @match https://boards.4chan.org/*/thread/*
// @match https://boards.4chan.org/*/res/*
// @match https://archived.moe/*/thread/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=4chan.org
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
// DEBUG
//GM_setValue("mechanism", "smart");
function parsePosts() {
let posts = document.querySelectorAll("blockquote.postMessage");
if(location.href.startsWith("https://archived.moe/")) {
posts = document.querySelectorAll("article > div.text, div.post_wrapper > div.text");
}
for(let i = 0; i < posts.length; i++) {
if(posts[i].getAttribute("data-4sidu-parsed") !== "1") {
posts[i].setAttribute("data-4sidu-parsed", "1");
// Strip all backlinks as they are likely to contain the magic number 05 that all Session IDs start with
let postText = posts[i].innerText.replace(/\>\>\b[0-9]+\b/g, "");
let idStartIndex = postText.indexOf("05");
if(idStartIndex > -1) {
let id = "";
//if(mechanism == "bruteforce") {
// Mechanism: Bruteforce - Remove all non-hex chars, grab the next 66 chars
//id = postText.substring(idStartIndex).replace(/[^A-Fa-f0-9]/g, "").substring(0, 66);
//} else if(mechanism == "smart") {
// Mechanism: "Smart" - Split input on whitespace...
let words = postText.substring(idStartIndex).split(/\s/);
for(let j = 0; j < words.length; j++) {
// ...keep iterating until we have more than 66 chars...
if(id.length < 66) {
// ...remove all non-alphanumeric chars
let word = words[j].replace(/[^A-Za-z0-9]/g, "");
// ...finally, ignore words that have any non-hex chars, add the word to the ID if it doesn't
if(!word.match(/[^A-Fa-f0-9]/g)) {
id += word;
}
} else {
break;
}
}
//}
if(id.length == 66) { // All Session IDs are 66 characters long; if we didn't get exactly that many characters, the ID is invalid
let opPost = "";
if(posts[i].parentNode.classList.contains("op")) {
opPost = "overflow: auto;";
}
let archivePost = "border-top: 1px solid; width: fit-content;";
if(posts[i].parentNode.tagName.toLowerCase() == "article") {
archivePost = "";
}
let html = `
<div style="margin-top: 1em; padding: 0.5em; ${archivePost} ${opPost}">
<span style="color: #66cc33; font-weight: bold;">Session ID:</span> ${id}
<input type="button" class="4sidu-copy-btn" id="4sidu-copy-btn-${i}" data-4sidu-session-id="${id}" style="margin-left: 0.5em;" value="Copy">
</div>
`;
posts[i].insertAdjacentHTML("beforeend", html);
document.getElementById(`4sidu-copy-btn-${i}`).addEventListener("click", async function() {
let tempInput = document.createElement("input");
tempInput.value = this.getAttribute("data-4sidu-session-id");
tempInput.select();
tempInput.setSelectionRange(0,66);
try {
await navigator.clipboard.writeText(tempInput.value);
this.value = "✓";
window.setTimeout(function() {
document.getElementById(`4sidu-copy-btn-${i}`).value = "Copy";
}, 3000)
} catch (err) {
alert("Failed to copy to clipboard: " + err);
}
});
}
}
}
}
}
//let mechanism = GM_getValue("mechanism", "bruteforce");
new MutationObserver(function(event) { parsePosts(); }).observe(document.querySelector("div.thread"), {childList: true});
parsePosts();