1. session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
  2. callback({ responseHeaders: Object.assign({
  3. "Content-Security-Policy": [ "default-src 'self'" ]
  4. }, details.responseHeaders)});
  5. });
  6. `default-src 'self'; connect-src 'self' https://apifree.com`

default-src 'self'; connect-src 'self' ws:

electron中实现跨域请求

很简单,在Electron的BrowserWindow模块中配置这样一个参数:

  1. // Create the browser window.
  2. mainWindow = new BrowserWindow({
  3. width: 800,
  4. height: 600,
  5. webPreferences: {
  6. nodeIntegration: true,
  7. webSecurity: false
  8. }
  9. })
  10. // and load the index.html of the app.
  11. //mainWindow.loadURL('window.html')
  12. mainWindow.loadFile('https://www.baidu.com')

webSecurity是什么意思呢?顾名思义,他是设置web安全性,如果参数设置为 false,它将禁用相同地方的规则 (通常测试服), 并且如果有2个非用户设置的参数,就设置 allowDisplayingInsecureContent 和 allowRunningInsecureContent的值为true。 (webSecurity的默认值为true)

allowDisplayingInsecureContent表示是否允许一个使用 https的界面来展示由 http URLs 传过来的资源。默认false。
allowRunningInsecureContent表示是否允许一个使用 https的界面来渲染由 http URLs 提交的html,css,javascript。默认为 false。
————————————————
版权声明:本文为CSDN博主「zhichaosong」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zhichaosong/article/details/89186356

  1. window.$ = window.jQuery = require('jquery');
  2. // ==UserScript==
  3. // @name Translator for Whatsapp
  4. // @namespace http://tampermonkey.net/
  5. // @homepage https://greasyfork.org/zh-CN/scripts/28218-translator-for-whatsapp
  6. // @version 2.4.3
  7. // @description Translator for Whatsapp web
  8. // @author JedLiu
  9. // @match https://web.whatsapp.com/*
  10. // @run-at document-start
  11. // @grant GM_setValue
  12. // @grant GM_getValue
  13. // @grant GM_xmlhttpRequest
  14. // @connect api-free.deepl.com
  15. // @require https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js
  16. // ==/UserScript==
  17. // DeepL需要修改:@connect api-free.deepl.com
  18. // 语言部分修改为:{id:'zh', name:'Chinese'},
  19. (function() {
  20. 'use strict';
  21. /*************************************************************
  22. 注意:
  23. 下面是所有支持的语言
  24. 如果要将某种语言包含进翻译范围,删除该语言前面的 // 即可
  25. *************************************************************/
  26. var all_languages = [
  27. {id:'zh', name:'Chinese'},
  28. // {id:'zh-CN', name:'Chinese Simplified'},
  29. //{id:'zh-TW', name:'Chinese Traditional'},
  30. //{id:'af', name:'Afrikaans'},
  31. //{id:'sq', name:'Albanian'},
  32. // {id:'ar', name:'Arabic'},
  33. //{id:'hy', name:'Armenian'},
  34. //{id:'az', name:'Azerbaijani'},
  35. //{id:'eu', name:'Basque'},
  36. //{id:'be', name:'Belarusian'},
  37. //{id:'bn', name:'Bengali'},
  38. //{id:'bs', name:'Bosnian'},
  39. //{id:'bg', name:'Bulgarian'},
  40. //{id:'ca', name:'Catalan'},
  41. //{id:'ceb', name:'Cebuano'},
  42. //{id:'ny', name:'Chichewa'},
  43. //{id:'co', name:'Corsican'},
  44. //{id:'hr', name:'Croatian'},
  45. //{id:'cs', name:'Czech'},
  46. //{id:'da', name:'Danish'},
  47. //{id:'nl', name:'Dutch'},
  48. {id:'en', name:'English'},
  49. //{id:'eo', name:'Esperanto'},
  50. //{id:'et', name:'Estonian'},
  51. //{id:'tl', name:'Filipino'},
  52. //{id:'fi', name:'Finnish'},
  53. {id:'fr', name:'French'},
  54. //{id:'fy', name:'Frisian'},
  55. //{id:'gl', name:'Galician'},
  56. //{id:'ka', name:'Georgian'},
  57. {id:'de', name:'German'},
  58. //{id:'el', name:'Greek'},
  59. //{id:'gu', name:'Gujarati'},
  60. //{id:'ht', name:'Haitian Creole'},
  61. //{id:'ha', name:'Hausa'},
  62. //{id:'haw', name:'Hawaiian'},
  63. //{id:'iw', name:'Hebrew'},
  64. {id:'hi', name:'Hindi'},
  65. //{id:'hmn', name:'Hmong'},
  66. //{id:'hu', name:'Hungarian'},
  67. //{id:'is', name:'Icelandic'},
  68. //{id:'ig', name:'Igbo'},
  69. //{id:'id', name:'Indonesian'},
  70. //{id:'ga', name:'Irish'},
  71. {id:'it', name:'Italian'},
  72. {id:'ja', name:'Japanese'},
  73. //{id:'jw', name:'Javanese'},
  74. //{id:'kn', name:'Kannada'},
  75. //{id:'kk', name:'Kazakh'},
  76. //{id:'km', name:'Khmer'},
  77. {id:'ko', name:'Korean'},
  78. //{id:'ku', name:'Kurdish (Kurmanji)'},
  79. //{id:'ky', name:'Kyrgyz'},
  80. //{id:'lo', name:'Lao'},
  81. //{id:'la', name:'Latin'},
  82. //{id:'lv', name:'Latvian'},
  83. //{id:'lt', name:'Lithuanian'},
  84. //{id:'lb', name:'Luxembourgish'},
  85. //{id:'mk', name:'Macedonian'},
  86. //{id:'mg', name:'Malagasy'},
  87. //{id:'ms', name:'Malay'},
  88. //{id:'ml', name:'Malayalam'},
  89. //{id:'mt', name:'Maltese'},
  90. //{id:'mi', name:'Maori'},
  91. //{id:'mr', name:'Marathi'},
  92. //{id:'mn', name:'Mongolian'},
  93. //{id:'my', name:'Myanmar (Burmese)'},
  94. //{id:'ne', name:'Nepali'},
  95. //{id:'no', name:'Norwegian'},
  96. //{id:'ps', name:'Pashto'},
  97. //{id:'fa', name:'Persian'},
  98. //{id:'pl', name:'Polish'},
  99. {id:'pt', name:'Portuguese'},
  100. //{id:'ma', name:'Punjabi'},
  101. //{id:'ro', name:'Romanian'},
  102. {id:'ru', name:'Russian'},
  103. //{id:'sm', name:'Samoan'},
  104. //{id:'gd', name:'Scots Gaelic'},
  105. //{id:'sr', name:'Serbian'},
  106. //{id:'st', name:'Sesotho'},
  107. //{id:'sn', name:'Shona'},
  108. //{id:'sd', name:'Sindhi'},
  109. //{id:'si', name:'Sinhala'},
  110. //{id:'sk', name:'Slovak'},
  111. //{id:'sl', name:'Slovenian'},
  112. //{id:'so', name:'Somali'},
  113. {id:'es', name:'Spanish'},
  114. //{id:'su', name:'Sudanese'},
  115. //{id:'sw', name:'Swahili'},
  116. //{id:'sv', name:'Swedish'},
  117. //{id:'tg', name:'Tajik'},
  118. //{id:'ta', name:'Tamil'},
  119. //{id:'te', name:'Telugu'},
  120. //{id:'th', name:'Thai'},
  121. //{id:'tr', name:'Turkish'},
  122. //{id:'uk', name:'Ukrainian'},
  123. //{id:'ur', name:'Urdu'},
  124. //{id:'uz', name:'Uzbek'},
  125. {id:'vi', name:'Vietnamese'},
  126. //{id:'cy', name:'Welsh'},
  127. //{id:'xh', name:'Xhosa'},
  128. //{id:'yi', name:'Yiddish'},
  129. //{id:'yo', name:'Yoruba'},
  130. //{id:'zu', name:'Zulu'}
  131. ];
  132. var SOURCE_LANGUAGE = 'zh',
  133. TRANSLATED_LANGUAGE = 'en';
  134. var $ = $ || window.$,
  135. addListenerInterval = null,
  136. translateInterval = null,
  137. translateTimeout = null,
  138. translate_enabled = true,
  139. translate_ready = false,
  140. translate_string = '',
  141. custom_style = '.language_selected{background-color: #00bfa5;}',
  142. image_uri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAFZklEQVR42sWXe0xTVxzHv5drWXkIKBQfE61Y2DIyR3Sy+FrqRgRF1IFD54IawU03dUE2I3ukxTgqPuYjK6KOZRndnFPYJoEpcUunokNxYnFT4wOQp9A/BshD4N6zc1sKvaWV0C7xhEt/59Hf93N+5/c7uWXwlBtjMV6JeBnz5r0KhmGG/BIhxKYPtLW1Qaf7Aa30c9gA4eFTof+9KJ5l2WzaDRhakIhs+sdT6/T5C5cSFi9JaB82wHsb1iFz5/ZmJ8UFy2Jv9JdN1DoLQGwnrcXWvbsJsYsWmB574n1jan/ZpHSXAU4VFA0CKCj4FaGhCjwXGiJI9s8LY6Ehij4gog4IlLsOkPzORptQiDvEajwmJhqLYqL6AWRjJrsGIDjiOF6kah2Jzs4upKRuwxtLYxE1/3WLcD9A4Nhg5wFsE+7q1Wuoq2tAZKQSUqnUdOaGihvQao8gdcsmKBTBgwDGjJviHMBOTbo40NRhebkBWYe+wpLFMViwYD4d47F7zwF0d3cjbVtq/zprgLHjFcMH2LAhGZmagRywympos47i5s1b2PpRCm78/Q9OnSrCh6mbIZdPtBUHzxP1+AkhrgHY1nl7ewcyd+9Da2sbOjs6sGLFMsydM8ueuCkCzwaFOg9g75Lp6elBru4YSkuvwF3ijqTk1XAPDEdF3TOgmn3AZoDG1hH6kkov/QCY7RGZPBtbKs9/c/v4inbucWsfwPpkUQ5YFldVV+Pb3GMwNhuR8GYcymhSGh7wePTCDirJ2LsJRZ+Dx/vtouritJjGUu1gAGFRVfUDFBf/RqugHMHBcqxKfAsyWQDdJY/ss904V69wRVx4+No/NGz9+Z1iAMuiO3fuQvfdcURHRSIiYroo20+W+yLvuo8r4ia77pyGsQJIgiYjnVg7fdwL3Gtm8fyYHtE5mgF8HYrHvsRhpBQouQPcb4ZDEAGg4UKmGWC9APB5Oken3Czi2wtHoqJ+BD6JbsX0oMf9DgRx4bEnPmEUQXZiL4RXCv0tQFPIOIwC3f0AwPLl8cjO2l9IJxZaxP+qkZhCL2EJPp7fgmlBXaZMF8TzDb52w540h8PicIILdPezFMDKwwxaOuxXBBUfAJBIJMjSfuH12jzlmtzLHgG/XJcq3T39lJaqkDId6u3R9Qj07oXOMFlZUumttBVn3QhykzhanoDuIoNDqwgO64GTVwaLC02IQGPJLth9/5oYd1w1clyY2lsmN/Vr9RlMnT7DZM/57KGKlfqqbRNubghBWgyPT/MZXL4PHHybwENCo5IDel+IxS0ReCIA6+6t9vSfBAHCGmBhRqPqEe+nts32jDgOE0YDiUcYcPSoFk4lSIli8IGOh6FGLG4G2MU8vOgAYErCCRXv5qkWbAHiRb8qhmm6aJpbtHKLqvi2p9o6w8f6EOSs5XGvCbh011xJnu7AshkMzlQQaAo4kbjw0N1TgN32AdIOnJHPnDmbniAm2Zvvpf5+vsbQMjU7XTObR0IEUFHTV8Z96wJ9gNFeQPxBDo+6xFeyANB0yQGAj18AdmQVyuWKsCdCHCsFGlpo8q2jZfUvkPK9OOGm0W/uXcli32kOP5Vxomqg4acAe+DwR8BQEMIR5JURzJhMoF4KaM8S5F8Vh9mNes/bzMLYRrD2aI8Ijoafaf7zCQAWCNX+fPm4oODVljEvb19lpZFRCuI9nKOrVpxw9ubp7ocGsNdSc2pVl2t91a6IC30q7hzAjK0177NSvy9dEafNSBNQZizdO3wARdzXXv5hy36kzqKFY3ZGnPDc+qoTS/I6G8qGD8C4SeAfFg/WY5TpzZ2Y/1l+qgzYZKAcbd+2O+pK0dVkMPsbLsD/3f4DRTYAbJ65vloAAAAASUVORK5CYII=',
  143. custom_html = '<div class="block-compose tranlate-bottom"><div tabindex="-1" class="input-container" style="padding-top:0px;padding-bottom:0px;padding-left:0px;"><button title="单击获取帮助!" class="trans_help_btn" style="float:left"><img alt="Translator" draggable="false" src="' + image_uri + '" style="width:30px;height:30px;padding-left:15px;padding-right:30px;padding-bottom:8px;"></button><div class="input" dir="auto" style="padding-top:6px;"></div></div></div>',
  144. html_language1 = '<div class="menu-item" style="display:table"><button title="单击获取帮助!" class="trans_help_btn"><img alt="Translator" draggable="false" src="data:'+ image_uri +'" style="width:32px;height:32px;"/></button></div>',
  145. username = '',
  146. is_debug = true,
  147. lan_select = '',
  148. help_url = 'https://greasyfork.org/zh-CN/scripts/28218-translator-for-whatsapp';
  149. // 生成 菜单 html
  150. for(var i=0;i<all_languages.length;i++){
  151. lan_select = lan_select + '<option value="'+ all_languages[i].id +'">' + all_languages[i].name +'</option>';
  152. }
  153. var lan_select_1 = '<span style="padding-left:5px;padding-right:5px;color:green;font-size:10pt;">From:</span><select class="languageSelect1" style="padding-right:5px;width: 126px; text-align-last:center;">' + lan_select + '</select>';
  154. var lan_select_2 = '<span style="padding-left:20px;padding-right:5px;color:green;font-size:10pt;">To:</span><select class="languageSelect" style="padding-right:5px;width: 126px; text-align-last:center;border-bottom-width: 0px !important;"><option value="off">OFF</option>' + lan_select + '</select>';
  155. html_language1 = html_language1 + '<div style="display:table;"><div style="display:table-row">'+ lan_select_1 +'</div><div style="display:table-row">'+ lan_select_2 +'</div></div>';
  156. //插入 style 样式
  157. var customStyleNode = document.createElement('style');
  158. customStyleNode.textContent = custom_style;
  159. document.querySelector('head').appendChild(customStyleNode);
  160. //替换所有函数
  161. function replaceAll(str, find, replace) {
  162. return str.replace(new RegExp(find, 'g'), replace);
  163. }
  164. //显示 debug 信息
  165. var debugMessage = function(mes){
  166. if(is_debug){
  167. console.info(mes);
  168. }
  169. };
  170. //显示 error 消息
  171. var showError = function(err){
  172. alert(err);
  173. console.error(err);
  174. };
  175. //translate 翻译函数
  176. //sl - source language
  177. //dl - target language
  178. //txt - 待翻译内容
  179. //cb - 翻译后回调
  180. var translate = function(sl,dl,txt,cb){
  181. debugMessage('原文:'+ txt);
  182. GM_xmlhttpRequest({
  183. method: "GET",
  184. // url: "https://translate.googleapis.com/translate_a/single?client=gtx&sl="+ sl + "&tl=" + dl +"&dt=t&q=" + encodeURI(txt),
  185. url: "https://api-free.deepl.com/v2/translate?auth_key=79d60834-077e-df8d-5033-a8a43412f476:fx&source_lang="+ sl +"&target_lang="+ dl +"&text="+ encodeURI(txt),
  186. onload: function(response) {
  187. //去除 \n
  188. // var _r_text = replaceAll(response.responseText, '\n"', '"');
  189. // var _r = eval(_r_text);
  190. // translate_string = '';
  191. // for(var i=0; i<_r[0].length;i++){
  192. // translate_string += _r[0][i][0];
  193. // }
  194. var json_obj={};
  195. json_obj = JSON.parse(response.responseText);
  196. translate_string = json_obj.translations[0].text;
  197. console.log(translate_string);
  198. debugMessage('待翻译内容:'+translate_string);
  199. cb.apply({text: translate_string});
  200. }
  201. });
  202. };
  203. //绑定元素,以获取用户输入
  204. var onInput = function(){
  205. var $_translate_input_1 = $('.tranlate-bottom').find('.input');
  206. $_translate_input_1.html('正在输入...');
  207. translate_ready = false;
  208. // var _this = $(this);
  209. // delay(function(){
  210. // var _input = $.trim(_this.text());
  211. // if(_input){
  212. // translate(SOURCE_LANGUAGE, TRANSLATED_LANGUAGE, _input, function(){
  213. // $_translate_input_1.html(this.text);
  214. // translate_ready = true;
  215. // });
  216. // }else{
  217. // $_translate_input_1.html('');
  218. // }
  219. // }, 1000);
  220. };
  221. //绑定元素,以发送翻译好的内容(xyx++ 按下回车键发送消息)
  222. //Updated: 2018-07-30
  223. var onEnterKeyPressed = function( event ) {
  224. if (event.which == 13 && translate_enabled) {
  225. var $_translate_input_1 = $('.tranlate-bottom').find('.input');
  226. $_translate_input_1.html('正在输入...');
  227. var _this = $(this);
  228. var _input = $.trim(_this.text());
  229. if(_input){
  230. translate(SOURCE_LANGUAGE, TRANSLATED_LANGUAGE, _input, function(){
  231. $_translate_input_1.html(this.text);
  232. translate_ready = true;
  233. });
  234. }else{
  235. $_translate_input_1.html('');
  236. }
  237. debugMessage('等待翻译');
  238. event.preventDefault();
  239. // var _this = $(this);
  240. translateInterval = setInterval(function(){
  241. if(translate_ready){
  242. debugMessage('正在发送消息:'+translate_string);
  243. sendTranslatedMessage(_this, translate_string);
  244. debugMessage('消息发送成功!');
  245. clearInterval(translateInterval);
  246. }
  247. }, 100);
  248. }
  249. };
  250. // 发送翻译好的消息
  251. //Updated: 2018-07-31
  252. var sendTranslatedMessage = function(inputTarget, message){
  253. translate_string = '';
  254. inputTarget.focus();
  255. document.execCommand("selectAll");
  256. document.execCommand("insertText", false, message);
  257. if($('footer button:has(span):last span').data('icon') == 'send'){
  258. $('footer button:has(span):last').click();
  259. }else{
  260. showError('无法发送翻译好的消息!');
  261. }
  262. translate_ready = false;
  263. }
  264. // 添加翻译绑定
  265. var addTranslateFunc = function(selectChange){
  266. if(!username){
  267. showError('无法获取 username');
  268. return;
  269. }
  270. if(selectChange){
  271. GM_setValue(username, $('.languageSelect').val());
  272. GM_setValue(username+'_o', $('.languageSelect1').val());
  273. }
  274. TRANSLATED_LANGUAGE = GM_getValue(username) ? GM_getValue(username) : TRANSLATED_LANGUAGE;
  275. SOURCE_LANGUAGE = GM_getValue(username+'_o') ? GM_getValue(username+'_o') : SOURCE_LANGUAGE;
  276. // 菜单 Menu
  277. debugMessage('原语言:' + SOURCE_LANGUAGE + ', 目标语言:'+ TRANSLATED_LANGUAGE);
  278. $('.languageSelect').val(TRANSLATED_LANGUAGE);
  279. $('.languageSelect1').val(SOURCE_LANGUAGE);
  280. // 添加翻译 input 控件
  281. var $_input_body = $('footer div.copyable-text.selectable-text');
  282. if(TRANSLATED_LANGUAGE !== 'off' && $('.tranlate-bottom').length === 0){
  283. $('footer').append($(custom_html));
  284. if($_input_body === null || $_input_body.length !== 1){
  285. showError('Whatsapp 翻译器插件绑定错误!');
  286. }else{
  287. $_input_body.on('input', onInput)
  288. .on('keydown', onEnterKeyPressed);
  289. }
  290. // 翻译已发送或之前接收到的消息
  291. $('.copyable-area').on('click', '.selectable-text', function(){
  292. if(TRANSLATED_LANGUAGE!='off'){
  293. var $_t_this = $(this);
  294. translate('', SOURCE_LANGUAGE, $(this).text(), function(){ // 使用 DeepL 时 第一个参数留空表示自动检测语言
  295. $_t_this.html(this.text);
  296. });
  297. }
  298. });
  299. // 访问帮助页面
  300. $('.trans_help_btn').on('click', function(){
  301. window.open(help_url,'_blank');
  302. });
  303. }else if(TRANSLATED_LANGUAGE === 'off' && $('.tranlate-bottom').length !== 0){
  304. // 移除绑定
  305. $('.tranlate-bottom').remove();
  306. $_input_body.off('input', onInput)
  307. .off('keydown', onEnterKeyPressed);
  308. }
  309. };
  310. // 当用户激活一个新聊天窗口时增加一个监听器
  311. addListenerInterval = setInterval(function(){
  312. var $_div_chat = $('#pane-side');
  313. //console.log('div_chat_length', $_div_chat.length);
  314. if($_div_chat.length){
  315. //console.log('found #pane-side');
  316. var contacts = document.querySelector('div[role="grid"]').children;
  317. if(!contacts || contacts.length === 0){
  318. showError('无法获取联系人侧边栏!');
  319. return;
  320. }
  321. const selector = contacts[0].className.split(' ').join('.');
  322. console.log('选择器: div.'+selector);
  323. //更新会经常导致这个地方需要修改
  324. $('#pane-side').on('click','div.'+selector, function(){
  325. // 获取 username
  326. //username = escape($(this).find('.chat-title').text());
  327. console.info($(this));
  328. var _tusername = '';
  329. $(this).find('span').each(function(i,x){
  330. if(x.hasAttribute('title')) {
  331. //console.info(x.title);
  332. _tusername = x.title;
  333. return false;
  334. }
  335. });
  336. if(_tusername !== ''){username = escape(_tusername);}
  337. else{showError('无法获取用户名!');}
  338. debugMessage('单击了聊天菜单!');
  339. // 添加了翻译输入控件后返回
  340. if($('.languageSelect').length>0){return;}
  341. var $header = $('#main header div:first').next();
  342. if($header.length != 1){showError('无法插入翻译菜单');}
  343. $header.after($(html_language1));
  344. // 绑定语言选择的 change 事件
  345. $('.languageSelect').on('change', function(){
  346. addTranslateFunc(true);
  347. });
  348. $('.languageSelect1').on('change', function(){
  349. addTranslateFunc(true);
  350. });
  351. // 应用 translate 函数
  352. addTranslateFunc();
  353. });
  354. clearInterval(addListenerInterval);
  355. }
  356. }, 1000);
  357. // delay 函数
  358. var delay = (function(){
  359. var timer = 0;
  360. return function(callback, ms){
  361. clearTimeout (timer);
  362. timer = setTimeout(callback, ms);
  363. };
  364. })();
  365. })();