您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Шифрование сообщений и комментариев
// ==UserScript== // @name Safe Chat // @namespace http://tampermonkey.net/ // @version 0.3.2 // @description Шифрование сообщений и комментариев // @author v666ad // @match *://shikimori.one/* // @icon https://www.google.com/s2/favicons?sz=64&domain=shikimori.one // @grant none // @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js // ==/UserScript== (function() { 'use strict'; let isCryptMenuShow = false; const keyLength = 32; function stripHtmlTags(html) { const tempDiv = document.createElement("div"); tempDiv.innerHTML = html; return tempDiv.textContent || tempDiv.innerText || ""; } function decryptEntities(entities, key) { entities.forEach(entity => { const entityBody = entity.querySelector('.body'); if (entityBody.innerHTML.endsWith('=') && entityBody.innerHTML.startsWith('U2F')) { try { const decrypted = CryptoJS.AES.decrypt(entityBody.innerHTML, key); entityBody.innerHTML = stripHtmlTags(decrypted.toString(CryptoJS.enc.Utf8)); entity.classList.add('_decrypt-successful'); entity.querySelector('span.time').innerHTML += ' ✅'; } catch (err) { console.error(entity, err); entity.classList.add('_decrypt-failed'); entity.querySelector('span.time').innerHTML += ' ❌'; } } else { entity.classList.add('_not-encrypted'); } }); } function decrypt() { const secretKey = localStorage.getItem('secret-key')?.padStart(keyLength, '0').slice(0, keyLength) || ''; const comments = document.querySelectorAll('.b-comment:not(._decrypt-failed, ._decrypt-successful, ._not-encrypted)'); decryptEntities(comments, secretKey); const messages = document.querySelectorAll('.b-message:not(._decrypt-failed, ._decrypt-successful, ._not-encrypted)'); decryptEntities(messages, secretKey); } function encryptText() { const secretKey = document.querySelector('.secret-key-input-container input').value.padStart(keyLength, '0').slice(0, keyLength); const textarea = document.querySelector('.editor textarea'); const inputText = textarea.value; const encrypted = CryptoJS.AES.encrypt(inputText, secretKey).toString(); textarea.value = `${encrypted}=`; } function toggleMenu() { document.querySelectorAll('.crypt-menu').forEach(menu => { menu.style.display = isCryptMenuShow ? 'none' : 'block'; }); isCryptMenuShow = !isCryptMenuShow; } function addButtons() { document.querySelectorAll('.b-shiki_editor').forEach(editor => { const buttons = editor.querySelector('footer'); if (buttons.querySelector('.show-crypt-menu-button')) return; const showCryptMenuButton = document.createElement('div'); showCryptMenuButton.classList.add('b-button', 'show-crypt-menu-button'); showCryptMenuButton.title = 'Меню шифрования'; showCryptMenuButton.innerText = 'SC'; showCryptMenuButton.onclick = toggleMenu; buttons.querySelector('.hide').insertAdjacentElement('afterend', showCryptMenuButton) // buttons.appendChild(showCryptMenuButton); const cryptMenu = document.createElement('div'); cryptMenu.className = 'crypt-menu'; cryptMenu.style.display = 'none'; const secretKeyInputContainer = document.createElement('div'); secretKeyInputContainer.className = 'secret-key-input-container'; const secretKey = localStorage.getItem('secret-key') || ''; const secretKeyInput = document.createElement('input'); secretKeyInput.type = 'text'; secretKeyInput.placeholder = 'Секретный ключ'; secretKeyInput.value = secretKey; secretKeyInput.oninput = (e) => localStorage.setItem('secret-key', e.target.value); secretKeyInputContainer.appendChild(secretKeyInput); cryptMenu.appendChild(secretKeyInputContainer); const doButtons = document.createElement('div'); doButtons.className = 'do-buttons-container'; const cryptButton = document.createElement('span'); cryptButton.className = 'crypt-button b-button'; cryptButton.textContent = 'Зашифровать'; cryptButton.onclick = encryptText; doButtons.appendChild(cryptButton); cryptMenu.appendChild(doButtons); editor.appendChild(cryptMenu); }); } function init() { const style = document.createElement('style'); style.textContent = ` .editor-controls .show-crypt-menu-button:before { content: '🔐'; } .editor-controls .show-crypt-menu-button { margin-left: 15px; cursor: pointer; } .crypt-menu { position: absolute; background: #fff; width: 100%; height: 70px; padding: 5px; border-radius: 3px; box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, .1); } .crypt-menu input { width: 100%; border-radius: 3px; } .crypt-menu .do-buttons-container { margin-top: 10px; text-align: center; } `; document.head.appendChild(style); setInterval(addButtons, 1000); setInterval(decrypt, 1000); } if (document.readyState === "complete" || document.readyState === "interactive") { init(); } else { document.addEventListener("DOMContentLoaded", init); } })();