bonk.io Account Switcher

Use this script in order to easily switch between your accounts!

// ==UserScript==
// @name         bonk.io Account Switcher
// @namespace    http://tampermonkey.net/
// @version      1.4.4
// @description  Use this script in order to easily switch between your accounts!
// @author       kitaesq
// @match        https://bonk.io/gameframe-release.html
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bonk.io
// @grant        none
// ==/UserScript==
console.log("Loading account switcher...")
if (!window.kitaes) window.kitaes = {}
window.kitaes.accSwitcher = () => {
    document.body.style.setProperty("--kitaes-accswitcher-a", "column")
    document.body.style.setProperty("--kitaes-accswitcher-bh", "40px")
    document.body.style.setProperty("--kitaes-accswitcher-bm", "10px")
    document.body.style.setProperty("--kitaes-accswitcher-btm", "-20px")
    const accContainer = document.getElementById("guestOrAccountContainer")
    if (!accContainer) {
        setTimeout(window.kitaes.accSwitcher, 100)
        console.log("trying again")
        return
    }
    const send = XMLHttpRequest.prototype.send
    accContainer.children[0].style.margin = "0"
    accContainer.children[1].style.margin = "0"
    accContainer.style.height = "425px"
    const main = document.createElement("div")
    const mainStyle = {
        position: "absolute",
        left: "0",
        right: "0",
        bottom: "0",
        height: "200px",
        borderRadius: "7px",
        backgroundColor: "var(--greyWindowBGColor)"
    }
    main.className = "windowShadow accountContainer"
    Object.assign(main.style, mainStyle)
    const buttonList = []
    const buttonSound = new Audio(GameResources.soundStrings.classicButtonClick)
    buttonSound.volume = 0.6
    let isLoggingIn = false
    const errorMessages = {"username_fail": "No account with that username", "password": "Password incorrect"}
    XMLHttpRequest.prototype.send = function(body){
        this.addEventListener("load", () => {
            if (this.responseURL !== "https://bonk2.io/scripts/login_legacy.php") return
            for (const a of buttonList){
                a.text.style.display = ""
                a.loader.style.display = ""
            }
            const response = JSON.parse(this.responseText)
            if (response.r !== "success") {
                if (isLoggingIn) errorText.innerText = errorMessages[response.e] ? errorMessages[response.e] : response.e
                return
            }
            isLoggingIn = false
            guestOrAccountContainer.style.visibility = "hidden"
            const credentials = body.split("&")
            const username = credentials[0].split("=")[1]
            const password = credentials[1].split("=")[1]
            if (accList[username] && accList[username] === password) return
            accList[username] = password
            localStorage.kitaes_accSwitcher = JSON.stringify(accList)
            if (knownUsernames.indexOf(username) === -1){
                addButton(username)
                knownUsernames.push(username)
            }
        })
        return send.apply(this, [body]);
    };
    const errorText = document.createElement("div")
    errorText.style.color = "red"
    errorText.style.position = "absolute"
    errorText.style.left = "0"
    errorText.style.right = "0"
    errorText.style.top = "-25px"
    errorText.style.fontFamily = "futurept_book_fixed"
    errorText.style.textAlign = "center"
    main.append(errorText)
    const mainHeader = document.createElement("div")
    mainHeader.className = "windowTopBar windowTopBar_classic"
    mainHeader.innerText = "Account Switcher"
    mainHeader.style.position = "relative"
    const headerButtons = document.createElement("div")
    headerButtons.style.display = "flex"
    headerButtons.style.position = "absolute"
    headerButtons.style.right = "0px"
    headerButtons.style.top = "0px"
    headerButtons.style.height = "100%"
    headerButtons.style.alignItems = "center"
    const headerButtonStyle = {
        height: "calc(100% - 10px)",
        lineHeight: "20px",
        margin: "0 5px",
        padding: "0 10px"
    }
    function createHeaderButton(text, onclick){
        const button = document.createElement("div")
        button.className = "brownButton brownButton_classic buttonShadow"
        button.innerText = text
        Object.assign(button.style, headerButtonStyle)
        button.onclick = onclick
        button.onpointerdown = () => buttonSound.play()
        headerButtons.append(button)
    }
    createHeaderButton("Export", () => {
        const data = []
        for (const [username, password] of Object.entries(accList)){
            data.push({username, password})
        }
        const blob = new Blob([JSON.stringify(data)])
        const url = URL.createObjectURL(blob)
        const link = document.createElement("a")
        link.href = url
        link.download = "passwords.json"
        link.click()
        setTimeout(() => URL.revokeObjectURL(url), 10000)
    })
    createHeaderButton("Import", () => {
        const fileDialog = document.createElement("input")
        fileDialog.type = "file"
        fileDialog.oninput = async () => {
            const data = JSON.parse(await (fileDialog.files[0]).text())
            for (const a of data){
                if (!accList[a.username]) addButton(a.username)
                accList[a.username] = a.password
                localStorage.kitaes_accSwitcher = JSON.stringify(accList)
            }
        }
        fileDialog.accept = "application/json"
        fileDialog.click()
    })
    mainHeader.append(headerButtons)
    main.append(mainHeader)
    const labelBox = document.createElement("div")
    labelBox.className = "guestOrAccountContainerLabelBox guestOrAccountContainerLabelSingleLine"
    labelBox.innerText = "Select an account to play with. New accounts will be added automatically"
    labelBox.style.width = "670px"
    main.append(labelBox)
    const buttonContainer = document.createElement("div")
    const buttonStyle = {
        height: "var(--kitaes-accswitcher-bh)",
        lineHeight: "var(--kitaes-accswitcher-bh)",
        fontSize: "18px",
        margin: "var(--kitaes-accswitcher-bm) 12px",
        flexGrow: "1",
        overflow: "hidden",
        textOverflow: "ellipsis"
    }
    function addButton(username){
        const optionWrapper = document.createElement("div")
        optionWrapper.style.flexGrow = "1"
        optionWrapper.style.display = "flex"
        optionWrapper.style.alignItems = "center"
        optionWrapper.style.flexDirection = "var(--kitaes-accswitcher-a)"
        optionWrapper.style.marginBottom = "5px"
        const button = document.createElement("div")
        button.className = "brownButton brownButton_classic buttonShadow thickerText"
        button.style.position = "relative"
        Object.assign(button.style, buttonStyle)
        const text = document.createElement("span")
        text.innerText = username
        button.append(text)
        const loader = document.createElement("div")
        loader.className = "loader"
        button.append(loader)
        button.onpointerdown = () => buttonSound.play()
        button.onclick = () => {
            isLoggingIn = true
            errorText.innerText = ""
            text.style.display = "none"
            loader.style.display = "block"
            login(username, accList[username])
        }
        button.style.width = "calc(100% - 20px)"
        optionWrapper.append(button)
        const deleteButton = document.createElement("div")
        deleteButton.className = "brownButton brownButton_classic buttonShadow mapeditor_leftbox_bottombutton"
        deleteButton.style.backgroundImage = "url(../graphics/delete.png)"
        deleteButton.style.margin = "0 12px"
        deleteButton.onpointerdown = () => buttonSound.play()
        deleteButton.onclick = () => {
            deleteButton.classList.add("mapeditor_leftbox_deletebuttonconfirm")
            deleteButton.onclick = () => {
                knownUsernames.splice(knownUsernames.indexOf(username), 1)
                optionWrapper.remove()
                delete accList[username]
                localStorage.kitaes_accSwitcher = JSON.stringify(accList)
            }
        }
        optionWrapper.append(deleteButton)
        buttonContainer.append(optionWrapper)
        buttonList.push({text, loader})
        if (buttonList.length > 4) listToTable() // jarvis, we're running out of free space. Deploy scrollbar!
    }
    const buttonContStyle = {
        position: "absolute",
        left: "0",
        right: "0",
        bottom: "var(--kitaes-accswitcher-btm)",
        display: "flex",
        maxHeight: "166px",
        overflowY: "auto",
    }
    Object.assign(buttonContainer.style, buttonContStyle)
    buttonContainer.style.justifyContent = "space-between"
    main.append(buttonContainer)
    try{
        var accList = JSON.parse(localStorage.kitaes_accSwitcher)
    }
    catch(e){
        var accList = {}
        localStorage.kitaes_accSwitcher = "{}"
    }
    function login(username,password){
        loginwindow_username.value = username
        loginwindow_password.value = password
        loginwindow_submitbutton.click()
    }
    for (const a of Object.keys(accList)){
        addButton(a, accList[a])
    }
    accContainer.append(main)
    function listToTable(){
        buttonContainer.style.flexDirection = "column"
        document.body.style.setProperty("--kitaes-accswitcher-a", "row")
        document.body.style.setProperty("--kitaes-accswitcher-bh", "30px")
        document.body.style.setProperty("--kitaes-accswitcher-bm", "0")
        document.body.style.setProperty("--kitaes-accswitcher-btm", "0")
        labelBox.style.display = "none"
    }
    const knownUsernames = Object.keys(accList)
}
window.kitaes.accSwitcher()