您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
通过 PGP 间接在 V2EX 上实现私信功能。
// ==UserScript== // @name V2EX-PGP-MSG // @namespace http://shendaowu.freevar.com/ // @version 0.2 // @description 通过 PGP 间接在 V2EX 上实现私信功能。 // @author shendaowu // @match https://www.v2ex.com/* // @require https://cdnjs.cloudflare.com/ajax/libs/openpgp/4.10.7/openpgp.min.js // @grant none // ==/UserScript== (function() { 'use strict'; let $ = window.jQuery; let openpgp = window.openpgp; const markStr = "Greasy Fork镜像 搜索 V2EX-PGP-MSG,让加密解密更方便。"; let bodyText = $("body")[0].innerText; let re = new RegExp("-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----", "gms"); let encryptedMessages = bodyText.match(re); if(encryptedMessages){ let bodyHTML = $("body")[0].innerHTML; re = new RegExp("(-----BEGIN PGP MESSAGE-----)(.*?-----END PGP MESSAGE-----)"); for(let i = 0; i < encryptedMessages.length; i++){ bodyHTML = bodyHTML.replace(re, '-----TMP MARK-----$2<br><div style="border: 1px solid;white-space: pre-line" id="decrypted_messages_' + i + '"/>如果一直显示此消息表明很可能消息不是用你的公钥加密的。</div>'); } re = new RegExp("-----TMP MARK-----", "gms"); bodyHTML = bodyHTML.replace(re, "-----BEGIN PGP MESSAGE-----"); $("body")[0].innerHTML = bodyHTML; } (async () => { if(!encryptedMessages) return; const privateKeyArmored = JSON.parse(localStorage.getItem("pri_key")); const passphrase = JSON.parse(localStorage.getItem("pgp_password")); const { keys: [privateKey] } = await openpgp.key.readArmored(privateKeyArmored); await privateKey.decrypt(passphrase); for(let i = 0; i < encryptedMessages.length; i++){ const { data: decrypted } = await openpgp.decrypt({ message: await openpgp.message.readArmored(encryptedMessages[i]), privateKeys: [privateKey] }); $("#decrypted_messages_" + i).text(decrypted); } })(); bodyText = $("body")[0].innerText; re = new RegExp(markStr + ".*?-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----", "gms"); let publicKeys = bodyText.match(re); if(publicKeys){ re = new RegExp("(" + markStr + ".*?)(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----)", "ms"); for(let i = 0; i < publicKeys.length; i++){ publicKeys[i] = publicKeys[i].replace(re, "$2"); } let bodyHTML = $("body")[0].innerHTML; re = new RegExp("(" + markStr + "<br>)(-----BEGIN PGP PUBLIC KEY BLOCK-----.*?-----END PGP PUBLIC KEY BLOCK-----)"); for(let i = 0; i < publicKeys.length; i++){ bodyHTML = bodyHTML.replace(re, '$1<button id="use_pub_key_' + i + '" class="use_pub_key" type="button"/>使用以下公钥加密</button><br>$2'); } $("body")[0].innerHTML = bodyHTML; $(".use_pub_key").click(function(){ showEncryptMessageDialogAndFillPubKey(publicKeys[this.id.split("_")[3]]); }); } $("body").append( `<div id="encrypt_popup" style="width: 100vw;height: 100vh;background-color: rgba(0, 0, 0, .5);position: fixed;left: 0;top: 0;bottom: 0;right: 0;display: none;justify-content: center;align-items: center;"> <div style="overflow: auto;width: 800px;height: 500px;background-color: #fff;box-sizing: border-box;padding: 10px 30px;color: black;"> <button id="close_encrypt_popup" type="button">关闭</button> <button id="encrypt_message" type="button">加密</button> <button id="append_to_reply" type="button">密文附加到回复并关闭弹窗</button> <br> 需要加密的消息: <textarea id="message_to_be_encrypt" style="width: 100%;height: 200px;"></textarea><br> 密文: <textarea id="encrypted_message" style="width: 100%;height: 200px;"></textarea><br> 公钥: <textarea id="selected_pub_key" style="width: 100%;height: 200px;"></textarea><br> </div> </div>`); $("#close_encrypt_popup").click(function(){$("#encrypt_popup").css("display", "none");}); $("#encrypt_message").click(function(){encryptMessage();}); function showEncryptMessageDialogAndFillPubKey(pubKey){ $("#encrypt_popup").css("display", "flex"); $("#selected_pub_key").val(pubKey); } let encryptMessage = async () => { const publicKeyArmored = $("#selected_pub_key").val(); const { data: encrypted } = await openpgp.encrypt({ message: openpgp.message.fromText($("#message_to_be_encrypt").val()), publicKeys: (await openpgp.key.readArmored(publicKeyArmored)).keys }); $("#encrypted_message").val(encrypted); }; $("#append_to_reply").click(function(){ $("#reply_content").val($("#reply_content").val() + $("#encrypted_message").val()); $("#encrypt_popup").css("display", "none"); }); $('<button id="show_PGP_manager_popup" type="button"/>PGP</button>').insertBefore(".top[href='/']"); $('<button id="show_encrypt_message_dialog" type="button"/>加密</button>').insertBefore(".top[href='/']"); $("#show_encrypt_message_dialog").click(function(){ $("#encrypt_popup").css("display", "flex"); }); $("body").append( `<div id="PGP_manager_popup" style="width: 100vw;height: 100vh;background-color: rgba(0, 0, 0, .5);position: fixed;left: 0;top: 0;bottom: 0;right: 0;display: none;justify-content: center;align-items: center;"> <div style="overflow: auto;width: 800px;height: 500px;background-color: #fff;box-sizing: border-box;padding: 10px 30px;color: black;"> <button id="close_PGP_manager_popup" type="button">关闭</button> <button id="generate_key_pair" type="button">生成密钥</button> <button id="save_key_pair_and_pass" type="button">保存密钥和密码</button> <button id="load_key_pair_and_pass" type="button">加载密钥和密码</button> <button id="pgp_help" type="button">使用说明</button> <br> 姓名:<input type="text" id="pgp_name" size="40" value="Jon Smith"><br> 邮箱:<input type="text" id="pgp_email" size="40" value="[email protected]"><br> 密码:<input type="text" id="pgp_password" size="40" value="super long and hard to guess secret"><br> 建议手动备份以下三个密钥。点击保存密钥按钮只会把密钥和密码存储在浏览器的 Local Storage 里。 保存私钥是为了自动解密密文。Local Storage 里的东西重装浏览器或者清除浏览器历史记录可能会没。 理论上其他软件生成的公钥和私钥粘贴到这里再保存应该也可以,不过我没试过。<br> 公钥: <textarea id="pub_key" style="width: 100%;height: 200px;"></textarea><br> 私钥: <textarea id="pri_key" style="width: 100%;height: 200px;"></textarea><br> 撤销证书: <textarea id="rev_key" style="width: 100%;height: 200px;"></textarea> </div> </div>`); $("#show_PGP_manager_popup").on('click', function(){$("#PGP_manager_popup").css("display", "flex");}); $("#generate_key_pair").click(function(){genKeyPair();}); $("#close_PGP_manager_popup").click(function(){$("#PGP_manager_popup").css("display", "none");}); $("#save_key_pair_and_pass").click(function(){ let isHasSavedKeyOrPassword = false; if( localStorage.getItem("pgp_password") != null || localStorage.getItem("pub_key") != null || localStorage.getItem("pri_key") != null || localStorage.getItem("rev_key") != null ){ isHasSavedKeyOrPassword = true; } let isClickConfirm = false; if(isHasSavedKeyOrPassword){ isClickConfirm = confirm("存在已保存的密钥或密钥密码,确定覆盖?"); } if(!isHasSavedKeyOrPassword || (isHasSavedKeyOrPassword && isClickConfirm)){ localStorage.setItem("pgp_password", JSON.stringify($("#pgp_password").val())); localStorage.setItem("pub_key", JSON.stringify($("#pub_key").val())); localStorage.setItem("pri_key", JSON.stringify($("#pri_key").val())); localStorage.setItem("rev_key", JSON.stringify($("#rev_key").val())); } }); $("#load_key_pair_and_pass").click(function(){ $("#pgp_password").val(JSON.parse(localStorage.getItem("pgp_password"))); $("#pub_key").val(JSON.parse(localStorage.getItem("pub_key"))); $("#pri_key").val(JSON.parse(localStorage.getItem("pri_key"))); $("#rev_key").val(JSON.parse(localStorage.getItem("rev_key"))); $("#pgp_name").val(""); $("#pgp_email").val(""); }); let genKeyPair = async () => { const { privateKeyArmored, publicKeyArmored, revocationCertificate } = await openpgp.generateKey({ userIds: [{ name: $("#pgp_name").val(), email: $("#pgp_email").val() }], curve: 'ed25519', passphrase: $("#pgp_password").val() }); $("#pri_key").val(privateKeyArmored); $("#pub_key").val(publicKeyArmored); $("#rev_key").val(revocationCertificate); }; $("#pgp_help").click(function(){ alert( `第一步:点击右上角的“PGP”按钮。在弹出的窗口中填入姓名、邮箱和密码。然后点击“生成密钥”按钮。然后点击“保存密钥和密码”按钮。点击“关闭”按钮。 第二步:点击创建新主题的正文文本框或者回复文本框下面的“附加保存的公钥”按钮。 第三步:点击公钥上面的“使用以下公钥加密”按钮。在弹出的窗口中填入要加密的内容。点击“加密”按钮。点击“密文附加到回复并关闭弹窗”按钮。此步一般应该由他人完成。 第四步:刷新页面,使用自己发布的公钥加密的内容将自动解密。 注意1:多次回复带有同一链接会被 V2EX 判定为 spam。删除带链接的那行好像不影响加密解密。 注意2:公钥前面的那行不能删除。算是我的脚本的广告。 注意3:PGP 相关的文章好像不多,推荐搜“非对称加密”了解相关知识。`); }); $('<button id="append_saved_pub_key" type="button"/>附加保存的公钥</button>').insertAfter("textarea#topic_content"); $("#append_saved_pub_key").click(function(){ $("textarea#topic_content").val($("textarea#topic_content").val() + markStr + "\r\n" + JSON.parse(localStorage.getItem("pub_key"))); }); //创建主题和创建回复的文本框好像不会同时出现。 $('<button id="append_saved_pub_key" type="button"/>附加保存的公钥</button>').insertAfter("#reply_content"); $("#append_saved_pub_key").click(function(){ $("textarea#reply_content").val($("textarea#reply_content").val() + markStr + "\r\n" + JSON.parse(localStorage.getItem("pub_key"))); }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址