background.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. *
  5. * @author didierfred@gmail.com
  6. * @version 0.4
  7. */
  8. "use strict";
  9. let config;
  10. let started = 'on';
  11. let debug_mode = true;
  12. const isChrome = false;
  13. let config_read_type = 'websocket';//local,file,websocket,http
  14. const wsUrl = 'ws://127.0.0.1:9002';
  15. let socket = null;
  16. loadConfigurationFromLocalStorage();
  17. addListener();
  18. // listen for change in configuration or start/stop
  19. chrome.runtime.onMessage.addListener(notify);
  20. function connectWebSocket(callback_function) {
  21. let socket = new WebSocket(wsUrl);
  22. let timeoutId; // 用于存储定时器 ID
  23. socket.onmessage = function (event) {
  24. log('Received message:' + event.data);
  25. clearTimeout(timeoutId); // 清除定时器
  26. socket.close();
  27. callback_function(event.data);
  28. return;
  29. };
  30. socket.onopen = function () {
  31. log('WebSocket connection established');
  32. // 发送配置请求
  33. let requestData = '{"messageType":131073}';
  34. log('Send message:' + requestData);
  35. socket.send(requestData);
  36. // 设置定时器,5秒后关闭连接
  37. timeoutId = setTimeout(() => {
  38. log('WebSocket connection timed out');
  39. socket.close();
  40. }, 5000); // 5秒 = 5000 毫秒
  41. };
  42. socket.onerror = function () {
  43. log('WebSocket connection error');
  44. clearTimeout(timeoutId); // 清除定时器
  45. };
  46. socket.onclose = function () {
  47. log('WebSocket connection closed');
  48. clearTimeout(timeoutId); // 清除定时器
  49. };
  50. }
  51. function loadConfigurationFromLocalStorage() {
  52. if(config_read_type == 'local')
  53. {
  54. let headers = [];
  55. headers.push({ url_contains: "", action: "add", header_name: "terminalno", header_value: "7555980178", comment: "test", apply_on: "req", status: "on" });
  56. config = { format_version: "1.1", target_page: "", headers: headers, debug_mode: true, use_url_contains: false };
  57. log("current new config" + JSON.stringify(config));
  58. storeInBrowserStorage({ config: JSON.stringify(config) });
  59. started = 'on';
  60. }
  61. else if(config_read_type == 'file')
  62. {
  63. log('loadConfigurationFromLocalStorage');
  64. const filePath = 'file:///D:/Run/runinfo/runcfg/config.json'; // 指定本地文件路径
  65. fetch(filePath)
  66. .then(response => response.json())
  67. .then(data => {
  68. console.log('Current new config:', JSON.stringify(data));
  69. config = data;
  70. storeInBrowserStorage({ config: JSON.stringify(data) }); // 如果不需要存储到浏览器存储中,可以注释掉这行
  71. started = 'on';
  72. })
  73. .catch(error => {
  74. console.error('Error reading file:', error);
  75. });
  76. }
  77. else if(config_read_type == 'websocket')
  78. {
  79. connectWebSocket(function(dataStr) {
  80. let data = JSON.parse(dataStr);
  81. log("current new config:" + JSON.stringify(data));
  82. config = data
  83. storeInBrowserStorage({ config: JSON.stringify(data) });
  84. started = 'on';
  85. });
  86. }
  87. }
  88. function loadFromBrowserStorage(item, callback_function) {
  89. chrome.storage.local.get(item, callback_function);
  90. }
  91. function storeInBrowserStorage(item, callback_function) {
  92. chrome.storage.local.set(item, callback_function);
  93. }
  94. function cookie_keyvalues_set(original_cookies, key, value) {
  95. let new_element = " " + key + "=" + value; // not used if value is undefined.
  96. let cookies_ar = original_cookies.split(";").filter(e => e.trim().length > 0);
  97. let selected_cookie_index = cookies_ar.findIndex(kv => kv.trim().startsWith(key+"="));
  98. if ((selected_cookie_index == -1) && (value != undefined)) cookies_ar.push(new_element);
  99. else {
  100. if (value === undefined)
  101. cookies_ar.splice(selected_cookie_index, 1);
  102. else
  103. cookies_ar.splice(selected_cookie_index, 1, new_element);
  104. }
  105. return cookies_ar.join(";");
  106. }
  107. function set_cookie_modify_cookie_value(original_set_cookie_header_content, key, new_value) {
  108. let trimmed = original_set_cookie_header_content.trimStart();
  109. let original_attributes = trimmed.indexOf(";") === -1 ? "" : trimmed.substring(trimmed.indexOf(";"))
  110. return key + "=" + new_value + original_attributes;
  111. }
  112. /*
  113. * Standard function to log messages
  114. *
  115. */
  116. function log(message) {
  117. console.log(new Date() + " SimpleModifyHeader : " + message);
  118. }
  119. /*
  120. * Rewrite the request header (add , modify or delete)
  121. *
  122. */
  123. function rewriteRequestHeader(e) {
  124. if (config.debug_mode) log("Start modify request headers for url " + e.url);
  125. for (let to_modify of config.headers) {
  126. if ((to_modify.status === "on") && (to_modify.apply_on === "req") && (!config.use_url_contains || (config.use_url_contains && e.url.includes(to_modify.url_contains.trim())))) {
  127. if (to_modify.action === "add") {
  128. let new_header = { "name": to_modify.header_name, "value": to_modify.header_value };
  129. e.requestHeaders.push(new_header);
  130. if (config.debug_mode) log("Add request header : name=" + to_modify.header_name +
  131. ",value=" + to_modify.header_value + " for url " + e.url);
  132. }
  133. else if (to_modify.action === "modify") {
  134. for (let header of e.requestHeaders) {
  135. if (header.name.toLowerCase() === to_modify.header_name.toLowerCase()) {
  136. if (config.debug_mode) log("Modify request header : name= " + to_modify.header_name +
  137. ",old value=" + header.value + ",new value=" + to_modify.header_value +
  138. " for url " + e.url);
  139. header.value = to_modify.header_value;
  140. }
  141. }
  142. }
  143. else if (to_modify.action === "delete") {
  144. let index = -1;
  145. for (let i = 0; i < e.requestHeaders.length; i++) {
  146. if (e.requestHeaders[i].name.toLowerCase() === to_modify.header_name.toLowerCase()) index = i;
  147. }
  148. if (index !== -1) {
  149. e.requestHeaders.splice(index, 1);
  150. if (config.debug_mode) log("Delete request header : name=" + to_modify.header_name.toLowerCase() +
  151. " for url " + e.url);
  152. }
  153. }
  154. else if (to_modify.action === "cookie_add_or_modify") {
  155. let header_cookie = e.requestHeaders.find(header => header.name.toLowerCase() === "cookie");
  156. let new_cookie = cookie_keyvalues_set(header_cookie === undefined ? "" : header_cookie.value, to_modify.header_name, to_modify.header_value);
  157. if (header_cookie === undefined) {
  158. e.requestHeaders.push({"name": "Cookie", "value": new_cookie});
  159. if (config.debug_mode) log("cookie_add_or_modify.req new_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
  160. }
  161. else {
  162. header_cookie.value = new_cookie;
  163. if (config.debug_mode) log("cookie_add_or_modify.req modify_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
  164. }
  165. }
  166. else if (to_modify.action === "cookie_delete") {
  167. let header_cookie = e.requestHeaders.find(header => header.name.toLowerCase() === "cookie");
  168. let new_cookie = cookie_keyvalues_set(header_cookie === undefined ? "" : header_cookie.value, to_modify.header_name, undefined);
  169. if (header_cookie === undefined) {
  170. if (config.debug_mode) log("cookie_delete.req: no cookie header found. doing nothing for url " + e.url);
  171. }
  172. else {
  173. header_cookie.value = new_cookie;
  174. if (config.debug_mode) log("cookie_delete.req modify_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
  175. }
  176. }
  177. }
  178. }
  179. if (config.debug_mode) log("End modify request headers for url " + e.url);
  180. return { requestHeaders: e.requestHeaders };
  181. }
  182. /*
  183. * Rewrite the response header (add , modify or delete)
  184. *
  185. */
  186. function rewriteResponseHeader(e) {
  187. if (config.debug_mode) log("Start modify response headers for url " + e.url);
  188. for (let to_modify of config.headers) {
  189. if ((to_modify.status === "on") && (to_modify.apply_on === "res") && (!config.use_url_contains || (config.use_url_contains && e.url.includes(to_modify.url_contains.trim())))) {
  190. if (to_modify.action === "add") {
  191. let new_header = { "name": to_modify.header_name, "value": to_modify.header_value };
  192. e.responseHeaders.push(new_header);
  193. if (config.debug_mode) log("Add response header : name=" + to_modify.header_name
  194. + ",value=" + to_modify.header_value + " for url " + e.url);
  195. }
  196. else if (to_modify.action === "modify") {
  197. for (let header of e.responseHeaders) {
  198. if (header.name.toLowerCase() === to_modify.header_name.toLowerCase()) {
  199. if (config.debug_mode) log("Modify response header : name= " + to_modify.header_name + ",old value="
  200. + header.value + ",new value=" + to_modify.header_value + " for url " + e.url);
  201. header.value = to_modify.header_value;
  202. }
  203. }
  204. }
  205. else if (to_modify.action === "delete") {
  206. let index = -1;
  207. for (let i = 0; i < e.responseHeaders.length; i++) {
  208. if (e.responseHeaders[i].name.toLowerCase() === to_modify.header_name.toLowerCase()) index = i;
  209. }
  210. if (index !== -1) {
  211. e.responseHeaders.splice(index, 1);
  212. if (config.debug_mode) log("Delete response header : name=" + to_modify.header_name.toLowerCase()
  213. + " for url " + e.url);
  214. }
  215. }
  216. else if (to_modify.action === "cookie_add_or_modify") {
  217. let header_cookie = e.responseHeaders.find(header =>
  218. header.name.toLowerCase() === "set-cookie" &&
  219. header.value.toLowerCase().trim().startsWith(to_modify.header_name.toLowerCase()+"=")
  220. );
  221. let new_header_value = set_cookie_modify_cookie_value(header_cookie === undefined ? "" : header_cookie.value, to_modify.header_name, to_modify.header_value);
  222. if (header_cookie === undefined) {
  223. log("SimpleModifyHeaders.Warning: you're using cookie_add_or_modify in Response. While adding new cookie in response, this plugin only generates `Set-Cookie: cookie-name=cookie-value `, without ANY additional attributes. Add a `Set-Cookie` header if you need them. ");
  224. e.responseHeaders.push({"name": "Set-Cookie", "value": new_header_value});
  225. if (config.debug_mode) log("cookie_add_or_modify.resp new_header : name=Cookie,value=" + new_header_value + " for url " + e.url);
  226. }
  227. else {
  228. header_cookie.value = new_header_value;
  229. if (config.debug_mode) log("cookie_add_or_modify.resp modify_header : name=Cookie,value=" + new_header_value + " for url " + e.url);
  230. }
  231. }
  232. else if (to_modify.action === "cookie_delete") {
  233. let index = e.responseHeaders.findIndex(header =>
  234. header.name.toLowerCase() === "set-cookie" &&
  235. header.value.toLowerCase().trim().startsWith(to_modify.header_name.toLowerCase()+"=")
  236. );
  237. if (index === -1) {
  238. if (config.debug_mode) log("cookie_delete.resp: no matching set-cookie header. doing nothing for url " + e.url);
  239. }
  240. else {
  241. e.responseHeaders.splice(index, 1);
  242. if (config.debug_mode) log("cookie_delete.resp delete_header : name=" + to_modify.header_name + " for url " + e.url);
  243. }
  244. }
  245. }
  246. }
  247. if (config.debug_mode) log("End modify response headers for url " + e.url);
  248. return { responseHeaders: e.responseHeaders };
  249. }
  250. /*
  251. * Listen for message form config.js
  252. * if message is reload : reload the configuration
  253. * if message is on : start the modify header
  254. * if message is off : stop the modify header
  255. *
  256. **/
  257. function notify(message) {
  258. if (message === "reload") {
  259. if (config.debug_mode) log("Reload configuration");
  260. loadFromBrowserStorage(['config'], function (result) {
  261. config = JSON.parse(result.config);
  262. if (started === "on") {
  263. removeListener();
  264. addListener();
  265. }
  266. });
  267. }
  268. else if (message === "off") {
  269. removeListener();
  270. started = "off";
  271. if (config.debug_mode) log("Stop modifying headers");
  272. }
  273. else if (message === "on") {
  274. addListener();
  275. started = "on";
  276. if (config.debug_mode) log("Start modifying headers");
  277. }
  278. }
  279. /*
  280. * Add rewriteRequestHeader as a listener to onBeforeSendHeaders, only for the target pages.
  281. * Add rewriteResponseHeader as a listener to onHeadersReceived, only for the target pages.
  282. * Make it "blocking" so we can modify the headers.
  283. */
  284. function addListener() {
  285. //return;
  286. let target = "<all_urls>";
  287. // need to had "extraHeaders" option for chrome https://developer.chrome.com/extensions/webRequest#life_cycle_footnote
  288. if (isChrome) {
  289. chrome.webRequest.onBeforeSendHeaders.addListener(rewriteRequestHeader,
  290. { urls: target.split(";") },
  291. ["blocking", "requestHeaders", "extraHeaders"]);
  292. chrome.webRequest.onHeadersReceived.addListener(rewriteResponseHeader,
  293. { urls: target.split(";") },
  294. ["blocking", "responseHeaders", "extraHeaders"]);
  295. }
  296. else {
  297. chrome.webRequest.onBeforeSendHeaders.addListener(rewriteRequestHeader,
  298. { urls: target.split(";") },
  299. ["blocking", "requestHeaders"]);
  300. chrome.webRequest.onHeadersReceived.addListener(rewriteResponseHeader,
  301. { urls: target.split(";") },
  302. ["blocking", "responseHeaders"]);
  303. }
  304. }
  305. /*
  306. * Remove the two listener
  307. *
  308. */
  309. function removeListener() {
  310. chrome.webRequest.onBeforeSendHeaders.removeListener(rewriteRequestHeader);
  311. chrome.webRequest.onHeadersReceived.removeListener(rewriteResponseHeader);
  312. }