您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A mod that handles monke bot's chats with a cool typing animation.
// ==UserScript== // @name Monkey Chat Handler (Typing Style) // @namespace http://tampermonkey.net/ // @version 3.0002 // @license MIT // @description A mod that handles monke bot's chats with a cool typing animation. // @author You & AI Assistant // @match https://bonk.io/gameframe-release.html // @icon https://www.google.com/s2/favicons?sz=64&domain=bonk.io // @grant GM_addStyle // ==/UserScript== let Currentvursion =3.0002 GM_addStyle(` .cool-chat-message { border-left: 3px solid #4CAF50; padding: 5px 8px; margin: 4px 0; word-wrap: break-word; } .cool-chat-message a { color: #87CEEB; text-decoration: none; font-weight: bold; transition: color 0.2s ease, text-decoration 0.2s ease; } .cool-chat-message a:hover { color: #98FB98; text-decoration: underline; } `); let autoCanv = function() { Object.defineProperty(this, 'chatBox1', { get: function() { return document.getElementById('newbonklobby_chat_content'); } }); Object.defineProperty(this, 'chatBox2', { get: function() { return document.getElementById('ingamechatcontent'); } }); }; let canv = new autoCanv(); function linkify(text) { const urlRegex = /(https?:\/\/[^\s]+)/g; return text.replace(urlRegex, url => `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`); } async function displayInChat(msg, color = '#228B22', inner = true, size) { const TYPING_SPEED_MS = 30; const chatBox1 = canv.chatBox1; const chatBox2 = canv.chatBox2; if (!chatBox1 && !chatBox2) { console.error("No chatbox elements found!"); return; } const scrollToBottom = () => { if (chatBox1) chatBox1.scrollTop = chatBox1.scrollHeight; if (chatBox2) chatBox2.scrollTop = chatBox2.scrollHeight; }; const finalHtml = inner ? linkify(msg) : linkify(msg.replace(/</g, "<").replace(/>/g, ">")); const tempDiv = document.createElement('div'); tempDiv.innerHTML = finalHtml; const plainText = tempDiv.textContent || ""; const createMessageElements = () => { const messageContainer = document.createElement('div'); messageContainer.className = 'cool-chat-message'; const typingSpan = document.createElement('span'); typingSpan.style.color = color; if (size) { typingSpan.style.fontSize = size + 'px'; } messageContainer.appendChild(typingSpan); return { messageContainer, typingSpan }; }; const elements1 = chatBox1 ? createMessageElements() : null; const elements2 = chatBox2 ? createMessageElements() : null; if (elements1) chatBox1.appendChild(elements1.messageContainer); if (elements2) chatBox2.appendChild(elements2.messageContainer); scrollToBottom(); for (let i = 0; i < plainText.length; i++) { const char = plainText[i]; if (elements1) elements1.typingSpan.textContent += char; if (elements2) elements2.typingSpan.textContent += char; scrollToBottom(); await new Promise(resolve => setTimeout(resolve, TYPING_SPEED_MS)); } if (elements1) elements1.typingSpan.innerHTML = finalHtml; if (elements2) elements2.typingSpan.innerHTML = finalHtml; } let autoName = function() { Object.defineProperty(this, 'name', { get: function() { return document.getElementById("pretty_top_name")?.textContent; } }); }; let name = new autoName(); let monkTypes = { handleJoining: { run: function(data) { if (data[0].to == name.name && data[0].version==Currentvursion) { pack(`4,{"initiator":"monke","type":"returnMessage","confirmed":"yes","from":"${name.name}"}`); } }, variables: ['data'], }, chatMessage: { run: function(data) { if (data[0].to == name.name) { const message = Mycipher.decrypt(data[0].message); displayInChat(message); } }, variables: ['data'], }, }; let monkVariableTypes = { data: { description: 'returns the data from the monk command', returned: function(data) { return data; } } }; function handleMonk(data) { let runner = monkTypes[data.type]; if (!runner) return; runner.run(runner.variables.map(variable => monkVariableTypes[variable].returned(data))); } let Mycipher; let oldsend = WebSocket.prototype.send; let code = function(xx) { if (xx == "5") { window.bonkws = this; let old_onmsg = this.onmessage; this.onmessage = function(yy) { if (yy.data.startsWith("42[")) { try { let data = JSON.parse(yy.data.slice(2)); if (data[0] == 21) { if(data[1].wl.startsWith('monke:')){ //expected monke:encryption key:rounds let fullstring=data[1].wl; let parts = data[1].wl.split(':'); Mycipher = new EduCipher(parts[1]); pack(`4,{"initiator":"monke","type":"returnMessage","key":"${Mycipher.encrypt(parts[1])}","from":"${name.name}"}`); let newString=yy.data.replace('"'+fullstring+'"',parts[2]); old_onmsg.call(this,{data:newString}); return }} if (data[0] == 7 && data[2].initiator == 'monke') { handleMonk(data[2]); } } catch (e) {} } return old_onmsg.call(this, yy); }; } return oldsend.call(this, xx); }; function fixOverwriteBitch() { WebSocket.prototype.send = code; } fixOverwriteBitch(); async function pack(input) { if (window.bonkws && window.bonkws.readyState === 1) { await window.bonkws.send("42[" + input + "]"); } else { console.error("Bonk WebSocket not ready to send message."); } } class EduCipher { constructor(masterKey) { this.BLOCK_SIZE = 16; this.NUM_ROUNDS = 8; const { substitutionTable, reverseSubstitutionTable } = this._createSubstitutionTables(masterKey); this.substitutionTable = substitutionTable; this.reverseSubstitutionTable = reverseSubstitutionTable; this.roundKeys = this._expandKeyToRoundKeys(masterKey); } _createSubstitutionTables(key) { const substitutionTable = new Uint8Array(256); const reverseSubstitutionTable = new Uint8Array(256); for (let i = 0; i < 256; i++) { substitutionTable[i] = i; } let shuffleIndex = 0; for (let i = 0; i < 256; i++) { const keyByte = key.charCodeAt(i % key.length); shuffleIndex = (shuffleIndex + substitutionTable[i] + keyByte) % 256; [substitutionTable[i], substitutionTable[shuffleIndex]] = [substitutionTable[shuffleIndex], substitutionTable[i]]; } for (let i = 0; i < 256; i++) { reverseSubstitutionTable[substitutionTable[i]] = i; } return { substitutionTable, reverseSubstitutionTable }; } _expandKeyToRoundKeys(masterKey) { const expandedKeys = []; let currentKey = new Uint8Array(this.BLOCK_SIZE); for (let i = 0; i < this.BLOCK_SIZE; i++) { currentKey[i] = masterKey.charCodeAt(i % masterKey.length) || 0; } for (let round = 0; round < this.NUM_ROUNDS + 1; round++) { expandedKeys.push(new Uint8Array(currentKey)); currentKey[0] = this.substitutionTable[currentKey[0]] ^ (round + 1); for (let i = 1; i < this.BLOCK_SIZE; i++) { currentKey[i] = this.substitutionTable[currentKey[i]] ^ currentKey[i - 1]; } } return expandedKeys; } encrypt(message) { const messageAsBytes = new TextEncoder().encode(message); const paddedMessage = this._addPadding(messageAsBytes); const encryptedBlocks = new Uint8Array(paddedMessage.length); const iv = this._getInsecureRandomBytes(this.BLOCK_SIZE); let previousCipherBlock = iv; for (let i = 0; i < paddedMessage.length; i += this.BLOCK_SIZE) { let blockToEncrypt = paddedMessage.slice(i, i + this.BLOCK_SIZE); for (let j = 0; j < this.BLOCK_SIZE; j++) { blockToEncrypt[j] ^= previousCipherBlock[j]; } const encryptedBlock = this._encryptBlock(blockToEncrypt); encryptedBlocks.set(encryptedBlock, i); previousCipherBlock = encryptedBlock; } const finalPayload = new Uint8Array(iv.length + encryptedBlocks.length); finalPayload.set(iv); finalPayload.set(encryptedBlocks, iv.length); return btoa(String.fromCharCode(...finalPayload)); } decrypt(encryptedBase64) { const combinedBytes = Uint8Array.from(atob(encryptedBase64), c => c.charCodeAt(0)); const iv = combinedBytes.slice(0, this.BLOCK_SIZE); const encryptedMessage = combinedBytes.slice(this.BLOCK_SIZE); const decryptedBlocks = new Uint8Array(encryptedMessage.length); let previousCipherBlock = iv; for (let i = 0; i < encryptedMessage.length; i += this.BLOCK_SIZE) { const blockToDecrypt = encryptedMessage.slice(i, i + this.BLOCK_SIZE); const decryptedBlock = this._decryptBlock(blockToDecrypt); for (let j = 0; j < this.BLOCK_SIZE; j++) { decryptedBlock[j] ^= previousCipherBlock[j]; } decryptedBlocks.set(decryptedBlock, i); previousCipherBlock = blockToDecrypt; } const unpaddedBytes = this._removePadding(decryptedBlocks); return new TextDecoder().decode(unpaddedBytes); } _encryptBlock(block) { let state = new Uint8Array(block); this._mixWithRoundKey(state, this.roundKeys[0]); for (let round = 1; round < this.NUM_ROUNDS; round++) { this._substituteBytes(state, this.substitutionTable); this._shiftBytes(state); this._mixWithRoundKey(state, this.roundKeys[round]); } this._substituteBytes(state, this.substitutionTable); this._mixWithRoundKey(state, this.roundKeys[this.NUM_ROUNDS]); return state; } _decryptBlock(block) { let state = new Uint8Array(block); this._mixWithRoundKey(state, this.roundKeys[this.NUM_ROUNDS]); this._substituteBytes(state, this.reverseSubstitutionTable); for (let round = this.NUM_ROUNDS - 1; round >= 1; round--) { this._mixWithRoundKey(state, this.roundKeys[round]); this._reverseShiftBytes(state); this._substituteBytes(state, this.reverseSubstitutionTable); } this._mixWithRoundKey(state, this.roundKeys[0]); return state; } _substituteBytes(state, table) { for (let i = 0; i < state.length; i++) state[i] = table[state[i]]; } _shiftBytes(state) { const firstByte = state[0]; state.copyWithin(0, 1); state[state.length - 1] = firstByte; } _reverseShiftBytes(state) { const lastByte = state[state.length - 1]; state.copyWithin(1, 0); state[0] = lastByte; } _mixWithRoundKey(state, roundKey) { for (let i = 0; i < state.length; i++) state[i] ^= roundKey[i]; } _addPadding(data) { const padLength = this.BLOCK_SIZE - (data.length % this.BLOCK_SIZE); const padding = new Uint8Array(padLength).fill(padLength); const result = new Uint8Array(data.length + padLength); result.set(data); result.set(padding, data.length); return result; } _removePadding(data) { const padLength = data[data.length - 1]; if (padLength === 0 || padLength > data.length) { throw new Error("Invalid padding detected. Decryption failed."); } return data.slice(0, data.length - padLength); } _getInsecureRandomBytes(length) { const randomBytes = new Uint8Array(length); for (let i = 0; i < length; i++) { randomBytes[i] = Math.floor(Math.random() * 256); } return randomBytes; } }