// ==UserScript==
// @name bonk.io Account Switcher
// @namespace http://tampermonkey.net/
// @version 1.5
// @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 search = document.createElement("input")
search.style.position = "absolute"
search.style.left = "6px"
search.style.top = "6px"
search.style.bottom = "6px"
search.style.width = "160px"
search.className = "fieldShadow"
search.style.borderColor = "transparent"
search.style.backgroundColor = "var(--bonk_theme_secondary_background, #fdfdfd)"
search.style.color = "var(--bonk_theme_primary_text, #4e4e4e)"
search.oninput = () => {
const usernameList = Object.keys(accList).sort()
const value = search.value.toLowerCase()
for (let i = 0; i < usernameList.length; i++){
if (usernameList[i].toLowerCase().startsWith(value)){
buttonContainer.scrollTop = buttonContainer.children[i].offsetTop
break
}
}
}
search.style.display = "none"
mainHeader.append(search)
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).sort()){
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"
search.style.display = ""
}
const knownUsernames = Object.keys(accList)
}
window.kitaes.accSwitcher()