Procházet zdrojové kódy

Merge branch 'ST2_0508_httpHeader' into feature_fingerPrint_js

chenliangyu před 4 měsíci
rodič
revize
9f71994607

+ 56 - 4
Module/mod_chromium/CModTools.cpp

@@ -204,6 +204,8 @@ namespace Chromium {
 			errPagePath.Append("homePageErr.html");
 		else if (errType._to_integral() == ERR_PAGE_REASON::startup)
 			errPagePath.Append("startPage.html");
+		else if (errType._to_integral() == ERR_PAGE_REASON::redirect)
+			errPagePath.Append("redirect.html");
 		else
 			errPagePath.Append("entityCheck.html");
 
@@ -585,9 +587,15 @@ namespace Chromium {
 #endif //RVC_OS_LINUX
 	}
 
+	bool startsWithHttpCaseInsensitive(std::string url) {
+		std::transform(url.begin(), url.end(), url.begin(), ::tolower);
+		return url.find("http") == 0;
+	}
+
 	std::string CModTools::generateCommonPage(std::string url, std::string name, int width, int height, int point_x, int point_y, int top)
 	{
 #if defined(RVC_OS_LINUX)
+		std::string dstUrl = url;
 		CSimpleStringA strBasePath(true);
 		this->m_pEntity->GetFunction()->GetPath("BaseDir", strBasePath);
 		std::string strPath(strBasePath.GetData());
@@ -636,7 +644,14 @@ namespace Chromium {
 			CSimpleStringA strUOSBrowserPath(execute_oldbrowser_path.c_str());
 			strParams.Append(" --new-window --no-first-run --disable-popup-blocking --disable-notifications --disable-desktop-notifications ");
 			if (ConfigManager::getInstance().m_extension_withTerminal)
+			{
 				strParams.Append(" --load-extension=").Append(ConfigManager::getInstance().m_extensionPath.c_str());
+				if (startsWithHttpCaseInsensitive(url))
+				{
+					auto redirctUrlRet = getErrUrl(ERR_PAGE_REASON::redirect);
+					dstUrl = "\"file:///" + redirctUrlRet.second + "?redirect_open=" + url + "&redirect_type=" + name + "\"";
+				}
+			}
 			strParams.Append(" --allow-running-insecure-content --disable-infobars --disable-suggestions-service --disable-save-password-bubble --disable-component-update");
 			
 			
@@ -653,7 +668,7 @@ namespace Chromium {
 			CSimpleStringA usrDataPath(tempPath);
 			usrDataPath.Append(SPLIT_SLASH_STR).Append("UOSBrowserConfig_").Append(name.c_str());
 			strParams.Append(" --user-data-dir=").Append(usrDataPath);
-			strParams.Append(" --app=").Append(url.c_str());
+			strParams.Append(" --app=").Append(dstUrl.c_str());
 			strUOSBrowserPath.Append(strParams);
 			return strUOSBrowserPath.GetData();
 		}
@@ -664,7 +679,14 @@ namespace Chromium {
 			CSimpleStringA strUOSBrowserPath(execute_newbrowser_path.c_str());
 			strParams.Append(" --allow-running-insecure-content --new-window");
 			if (ConfigManager::getInstance().m_extension_withTerminal)
+			{
 				strParams.Append(" --load-extension=").Append(ConfigManager::getInstance().m_extensionPath.c_str());
+				if (startsWithHttpCaseInsensitive(url))
+				{
+					auto redirctUrlRet = getErrUrl(ERR_PAGE_REASON::redirect);
+					dstUrl = "\"file:///" + redirctUrlRet.second + "?redirect_open=" + url + "&redirect_type=" + name + "\"";
+				}
+			}
 			CSimpleStringA tempPath;
 			this->m_pEntity->GetFunction()->GetPath("Temp", tempPath);
 			CSimpleStringA cachePath(tempPath);
@@ -677,7 +699,7 @@ namespace Chromium {
 			CSimpleStringA usrDataPath(tempPath);
 			usrDataPath.Append(SPLIT_SLASH_STR).Append("BrowserConfig_").Append(name.c_str());
 			strParams.Append(" --user-data-dir=").Append(usrDataPath);
-			strParams.Append(" --app=").Append(url.c_str());
+			strParams.Append(" --app=").Append(dstUrl.c_str());
 			strUOSBrowserPath.Append(strParams);
 			return strUOSBrowserPath.GetData();
 		}
@@ -751,12 +773,28 @@ namespace Chromium {
 #if defined(RVC_OS_LINUX)
     std::string CModTools::generateBrowserCMDForEverything(const std::string& url, int pageType, bool ignoreSecurity)
     {
+		std::string dstUrl = url;
         CSimpleStringA strBasePath(true);
         this->m_pEntity->GetFunction()->GetPath("BaseDir", strBasePath);
         std::string strPath(strBasePath.GetData());
         const std::string execute_newbrowser_path = strPath + SPLIT_SLASH_STR + "res" + SPLIT_SLASH_STR + "RunScript" + SPLIT_SLASH_STR + "startBrower.sh";
         const std::string execute_oldbrowser_path = strPath + SPLIT_SLASH_STR + "res" + SPLIT_SLASH_STR + "RunScript" + SPLIT_SLASH_STR + "startUOSBrower.sh";
 
+		std::string name = "";
+		if (pageType == 0 || pageType == 2 || pageType == 3) {
+			name = (+ERR_PAGE_REASON::main)._to_string();
+		}
+		else if (pageType == 1) {
+			name = (+ERR_PAGE_REASON::Ad)._to_string();
+		}
+		else if (pageType == 2) {
+			name = (+ERR_PAGE_REASON::breakdown)._to_string();
+		}
+		else if (pageType == 3) {
+			name = (+ERR_PAGE_REASON::OutsideRequest)._to_string();
+		}
+
+
 		auto getUnsafeDomain = [](const std::string& url)
 		{
 			// 移除协议部分
@@ -790,7 +828,14 @@ namespace Chromium {
 			if (!ConfigManager::getInstance().m_extension_debugOpen)
 				strParams.Append(" --kiosk");
 			if (ConfigManager::getInstance().m_extension_withTerminal)
+			{
 				strParams.Append(" --load-extension=").Append(ConfigManager::getInstance().m_extensionPath.c_str());
+				if (startsWithHttpCaseInsensitive(url))
+				{
+					auto redirctUrlRet = getErrUrl(ERR_PAGE_REASON::redirect);
+					dstUrl = "\"file:///" + redirctUrlRet.second + "?redirect_open=" + url + "&redirect_type=" + name + "\"";
+				}
+			}
 			if (pageType == 0 || pageType == 2 || pageType == 3) {
 
 			} else if (pageType == 1) {
@@ -835,7 +880,7 @@ namespace Chromium {
             }
             strParams.Append(" --user-data-dir=").Append(usrDataPath);
             strParams.Append(" ");
-            strParams.Append(url.c_str());
+            strParams.Append(dstUrl.c_str());
             strUOSBrowserPath.Append(strParams);
 
             if (pageType == 0) {
@@ -854,7 +899,14 @@ namespace Chromium {
 			if (!ConfigManager::getInstance().m_extension_debugOpen)
 				strParams.Append(" --kiosk");
 			if (ConfigManager::getInstance().m_extension_withTerminal)
+			{
 				strParams.Append(" --load-extension=").Append(ConfigManager::getInstance().m_extensionPath.c_str());
+				if (startsWithHttpCaseInsensitive(url))
+				{
+					auto redirctUrlRet = getErrUrl(ERR_PAGE_REASON::redirect);
+					dstUrl = "\"file:///" + redirctUrlRet.second + "?redirect_open=" + url + "&redirect_type=" + name + "\"";
+				}
+			}
             if (pageType == 0 || pageType == 2 || pageType == 3) {
 
             } else if (pageType == 1) {
@@ -899,7 +951,7 @@ namespace Chromium {
             }
             strParams.Append(" --user-data-dir=").Append(usrDataPath);
             strParams.Append(" ");
-            strParams.Append(url.c_str());
+            strParams.Append(dstUrl.c_str());
             strUOSBrowserPath.Append(strParams);
 
             if (pageType == 0) {

+ 1 - 1
Module/mod_chromium/CModTools.h

@@ -21,7 +21,7 @@ namespace Chromium {
 
 	BETTER_ENUM(ERR_PAGE_REASON, int, CameraConfig, CardStoreIsBusy, MachineTypeError, TerminalManagerKickOut,
 		TerminalManagerOff, breakdown, warnPrompt, disabled, jobuncomplete, ErrNotify, main, Ad, extend, OutsideRequest, SpecialPageFromOtherEntity
-		, Install, startup, performance_monitor, audioErr)
+		, Install, startup, performance_monitor, audioErr, redirect)
 
 		BETTER_ENUM(PAGE_TYPE, int, Deploy, CameraConfig, TerminalManager, errPage, Ad, slv, init, TradeManager
 			, breakdown, extend, CardStoreIsBusy, Install, startup, performance_monitor)

+ 5 - 1
Module/mod_chromium/CWebsocketServer.cpp

@@ -295,8 +295,12 @@ namespace Chromium {
 				t_type = LOG_TYPE_BUSINESS_USER;
 			else if (logType.second.Compare("VTMWeb", true) == 0)
 				t_type = LOG_TYPE_VTMWEB;
-			else if(logType.second.Compare("Sys", true) == 0)
+			else if (logType.second.Compare("Sys", true) == 0)
 				t_type = LOG_TYPE_BUSINESS_SYSTEM;
+			else if (logType.second.Compare("VTMSys", true) == 0)
+				t_type = LOG_TYPE_SYSTEM;
+			else if (logType.second.Compare("VTMUser", true) == 0)
+				t_type = LOG_TYPE_USER;
 
 			//通过变量方式进行处理
 			DbgWithLink t_obj(changeMessageTypeToLogLevel(messageType), t_type);

+ 19 - 0
addin/res/ManagerDesktop/redirect.html

@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <!-- 1. 从 URL 参数中提取目标地址 -->
+    <script>
+        const params = new URLSearchParams(window.location.search);
+        const targetUrl = params.get('redirect_open'); // 例如 ?url=http://oa.cmbchina.com
+        if (targetUrl) {
+            // 2. 延迟 5 秒后通过 meta 刷新跳转(无界面闪烁)
+            setTimeout(() => {
+                window.location.href = targetUrl + (targetUrl.includes('?') ? '&' : '?') + 'from_redirect=' + Date.now();
+            }, 5000);
+        }
+    </script>
+    <!-- 3. 确保页面完全空白 -->
+    <style>html, body { display: none; }</style>
+</head>
+<body></body>
+</html>

+ 471 - 277
addin/res/VTMModifyHeaders/background.js

@@ -8,7 +8,16 @@
  */
 
 
+//C:\Program Files\Google\Chrome\Application\chrome.exe --auto-open-devtools-for-tabs --load-extension=D:\mayun\LR04.02_RVCTerminalPlus_uos\addin\res\VTMModifyHeaders "file:///D:/redirect.html?url=http://oa.cmbchina.com"
+
+//"C:\Program Files\Google\Chrome\Application\chrome.exe" --auto-open-devtools-for-tabs --load-extension=D:\mayun\LR04.02_RVCTerminalPlus_uos\addin\res\VTMModifyHeaders "file:///D:/mayun/LR04.02_RVCTerminalPlus_uos/addin/res/ManagerDesktop/redirect.html?redirect_open=http://oa.cmbchina.com&redirect_type=ad"
+
 "use strict";
+// 创建自定义事件发射器
+const eventBus = new EventTarget();
+
+// 定义事件名
+const WS_CALLBACK_COMPLETE = 'wsCallbackComplete';
 
 let config;
 let started = 'on';
@@ -16,139 +25,321 @@ let debug_mode = true;
 const isChrome = true;
 let config_read_type = 'websocket';//local,file,websocket,http
 const wsUrl = 'ws://127.0.0.1:9002?name=vtm_modify_header';
+const wsLoggerUrl = 'ws://127.0.0.1:9002?name=header_';
 let socket = null;
+let isExtensionReady = false;
+
+function delay(ms) {
+    return new Promise(resolve => setTimeout(resolve, ms));
+}
+
+class WebSocketLogger {
+    constructor(options) {
+        // 默认配置
+        const defaults = {
+            url: wsLoggerUrl,
+            reconnectInterval: 5000,
+            maxReconnectAttempts: 3,
+            logging: true
+        };
+
+        this.config = { ...defaults, ...options };
+        this.ws = null;
+        this.reconnectAttempts = 0;
+        this.isConnected = false;
+        this.messageQueue = [];
+    }
+
+    // 初始化WebSocket连接
+    connect() {
+        this.ws = new WebSocket(this.config.url);
+
+        this.ws.onopen = () => {
+            this.isConnected = true;
+            this.reconnectAttempts = 0;
+            console.log('WebSocket connected');
+            this._flushMessageQueue(); // 发送积压的消息
+        };
+
+        this.ws.onclose = () => {
+            this.isConnected = false;
+            console.log('WebSocket disconnected');
+            this._attemptReconnect();
+        };
+
+        this.ws.onerror = (error) => {
+            console.error('WebSocket error:', error);
+        };
+    }
+
+    // 尝试重新连接
+    _attemptReconnect() {
+        if (this.reconnectAttempts < this.config.maxReconnectAttempts) {
+            this.reconnectAttempts++;
+            console.log(`Reconnecting attempt ${this.reconnectAttempts}...`);
+            setTimeout(() => this.connect(), this.config.reconnectInterval);
+        } else {
+            console.error('Max reconnection attempts reached');
+        }
+    }
+
+    // 发送日志消息
+    log(payload) {
+        const defaultPayload = {
+            messageType: 3080198,
+            EntityName: 'header_log',
+            ResultMsg: '',
+            LogType: 'VTMSys',
+            CostTime: 0,
+            ResultCode: 'SUC0000',
+            LogCode: '',
+            API: 'header_log',
+            SourceType: '',
+            BussID: '',
+            TipMsg: ''
+        };
+
+        const message = { ...defaultPayload, ...payload };
+
+        if (this.isConnected) {
+            this._sendMessage(message);
+        } else {
+            this.messageQueue.push(message); // 先存入队列
+            if (this.messageQueue.length === 1) {
+                this.connect(); // 首次断连时尝试重连
+            }
+        }
+    }
+
+    // 实际发送消息
+    _sendMessage(message) {
+        try {
+            this.ws.send(JSON.stringify(message));
+            if (this.config.logging) {
+                console.log('Log sent:', message);
+            }
+        } catch (error) {
+            console.error('Failed to send log:', error);
+            this.messageQueue.push(message); // 失败后重新入队
+        }
+    }
+
+    // 发送队列中的积压消息
+    _flushMessageQueue() {
+        while (this.messageQueue.length > 0 && this.isConnected) {
+            const message = this.messageQueue.shift();
+            this._sendMessage(message);
+        }
+    }
+
+    // 关闭连接
+    close() {
+        if (this.ws) {
+            this.ws.close();
+            this.isConnected = false;
+        }
+    }
+}
 
 loadConfigurationFromLocalStorage();
 
 addListener();
-// listen for change in configuration or start/stop
-chrome.runtime.onMessage.addListener(notify);
 
 function connectWebSocket(callback_function) {
-  let socket = null; // 初始化 socket 变量
-  let timeoutId = setTimeout(() => {
-    socket.close();
-    callback_function(null); // 超时回调 null
-  }, 3000); // 5秒 = 5000 毫秒
-  let connectionOpened = false; // 标记连接是否已经打开
-
-  try {
-    socket = new WebSocket(wsUrl);
-  } catch (error) {
-    log('WebSocket connection creation error: ' + error);
-    callback_function(null); // 连接创建失败,回调 null
-    return;
-  }
-
-
-  socket.onmessage = function (event) {
-    log('Received message:' + event.data);
-    clearTimeout(timeoutId); // 清除定时器
-    if (socket && socket.readyState === WebSocket.OPEN) { // 检查连接状态
-      socket.close();
+    let socket = null; // 初始化 socket 变量
+    let timeoutId = setTimeout(() => {
+        socket.close();
+        callback_function(null); // 超时回调 null
+    }, 3000); // 5秒 = 5000 毫秒
+    let connectionOpened = false; // 标记连接是否已经打开
+
+    try {
+        socket = new WebSocket(wsUrl);
+    } catch (error) {
+        console.log('WebSocket connection creation error: ' + error);
+        callback_function(null); // 连接创建失败,回调 null
+        return;
     }
-    callback_function(event.data);
-    return;
-  };
-
-  socket.onopen = function () {
-    log('WebSocket connection established');
-    connectionOpened = true; // 设置连接已打开标志
-    // 发送配置请求
-    let requestData = '{"messageType":131073}';
-    log('Send message:' + requestData);
-    socket.send(requestData);
-  };
-
-  socket.onerror = function (error) {
-    log('WebSocket connection error:' + error);
-    clearTimeout(timeoutId); // 清除定时器
-    if (socket && socket.readyState === WebSocket.OPEN) { // 检查连接状态
-      socket.close();
+
+
+    socket.onmessage = function (event) {
+        console.log('Received message:' + event.data);
+        clearTimeout(timeoutId); // 清除定时器
+        if (socket && socket.readyState === WebSocket.OPEN) { // 检查连接状态
+            socket.close();
+        }
+        callback_function(event.data);
+        return;
+    };
+
+    socket.onopen = function () {
+        console.log('WebSocket connection established');
+        connectionOpened = true; // 设置连接已打开标志
+        // 发送配置请求
+        let requestData = '{"messageType":131073}';
+        console.log('Send message:' + requestData);
+        socket.send(requestData);
+    };
+
+    socket.onerror = function (error) {
+        console.log('WebSocket connection error:' + error);
+        clearTimeout(timeoutId); // 清除定时器
+        if (socket && socket.readyState === WebSocket.OPEN) { // 检查连接状态
+            socket.close();
+        }
+        callback_function(null); // 错误回调 null
+    };
+
+    socket.onclose = function (event) {
+        console.log('WebSocket connection closed:' + event.reason);
+        clearTimeout(timeoutId); // 清除定时器
+        connectionOpened = false; // 重置连接已打开标志
+        if (event.reason !== 'Connection timed out') { // 如果不是超时关闭
+            callback_function(null); // 连接意外关闭,回调 null
+        }
+    };
+}
+
+function extractUrlFromFileProtocol(fileUrl) {
+    try {
+        const urlObj = new URL(fileUrl);
+        const params = new URLSearchParams(urlObj.search);
+        const targetUrl = params.get('redirect_open');
+
+        // 验证提取的 URL 是否合法
+        if (targetUrl && (targetUrl.startsWith('http://') || targetUrl.startsWith('https://'))) {
+            return targetUrl;
+        }
+    } catch (e) {
+        console.error('Failed to parse file:// URL:', e);
     }
-    callback_function(null); // 错误回调 null
-  };
-
-  socket.onclose = function (event) {
-    log('WebSocket connection closed:' + event.reason);
-    clearTimeout(timeoutId); // 清除定时器
-    connectionOpened = false; // 重置连接已打开标志
-    if (event.reason !== 'Connection timed out') { // 如果不是超时关闭
-      callback_function(null); // 连接意外关闭,回调 null
+    return null;
+}
+
+function extractTypeFromFileProtocol(fileUrl) {
+    try {
+        const urlObj = new URL(fileUrl);
+        const params = new URLSearchParams(urlObj.search);
+        const targetUrl = params.get('redirect_type');
+
+        // 验证提取的 URL 是否合法
+        if (targetUrl) {
+            return targetUrl;
+        }
+        else
+            return "log";
+    } catch (e) {
+        console.error('Failed to parse file:// URL:', e);
     }
-  };
+    return null;
 }
 
 
 function loadConfigurationFromLocalStorage() {
-  if (config_read_type == 'local') {
-    let headers = [];
-    headers.push({ url_contains: "", action: "add", header_name: "terminalno", header_value: "7555980178", comment: "test", apply_on: "req", status: "on" });
-    config = { format_version: "1.1", target_page: "", headers: headers, debug_mode: true, use_url_excepts: false };
-    log("current new config" + JSON.stringify(config));
-
-
-    storeInBrowserStorage({ config: JSON.stringify(config) });
-    started = 'on';
-  }
-  else if (config_read_type == 'file') {
-    log('loadConfigurationFromLocalStorage');
-    const filePath = 'file:///D:/Run/runinfo/runcfg/config.json'; // 指定本地文件路径
-    fetch(filePath)
-      .then(response => response.json())
-      .then(data => {
-        console.log('Current new config:', JSON.stringify(data));
-        config = data;
-        storeInBrowserStorage({ config: JSON.stringify(data) }); // 如果不需要存储到浏览器存储中,可以注释掉这行
-        started = 'on';
-      })
-      .catch(error => {
-        console.error('Error reading file:', error);
-      });
-  }
-  else if (config_read_type == 'websocket') {
-    connectWebSocket(function (dataStr) {
-      if (dataStr == null)
-        return;
-      let data = JSON.parse(dataStr);
-      log("current new config:" + JSON.stringify(data));
-      config = data
-      storeInBrowserStorage({ config: JSON.stringify(data) });
-      started = 'on';
+    let isSuc = false;
+    let dstWs_logger = wsLoggerUrl;
+    let currentUrl = "";
+    let urlParam = "";
+    if (config_read_type == 'websocket') {
+        connectWebSocket(function (dataStr) {
+            if (dataStr == null)
+                return;
+            let data = JSON.parse(dataStr);
+            log("current new config:" + JSON.stringify(data));
+
+            chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
+                if (tabs[0]) {
+                    currentUrl = tabs[0].url; // 当前标签页的 URL
+                    console.log("当前 URL:", currentUrl);
+                    const urlType = extractTypeFromFileProtocol(currentUrl);
+                    dstWs_logger = dstWs_logger + urlType;
+
+                    // 规则1: 如果是 file:// 开头,提取 url= 参数并跳转
+                    if (currentUrl.startsWith('file:///')) {
+                        console.log("begin with file:///");
+                        urlParam = extractUrlFromFileProtocol(currentUrl);
+                        console.log("解析的url为:" + urlParam);
+                        if (urlParam) {
+                            // 使插件生效
+                            config = data // modify config which make 
+                            storeInBrowserStorage({ config: JSON.stringify(data) });
+                            started = 'on';
+
+                            console.log("重载为:", urlParam);
+                            chrome.tabs.update(tabs[0].id, { url: urlParam });
+
+                            isSuc = true;
+                            eventBus.dispatchEvent(new CustomEvent(WS_CALLBACK_COMPLETE, {
+                                detail: { success: true, data: "操作完成" }
+                            }));
+
+                        }
+                    }
+                    else {
+                        isSuc = false
+                        started = 'off';
+                        eventBus.dispatchEvent(new CustomEvent(WS_CALLBACK_COMPLETE, {
+                            detail: { success: false, data: "操作失败" }
+                        }));
+                    }
+                }
+            });
+            /*
+                  chrome.tabs.query({ active: true }, (tabs) => {
+                    chrome.tabs.update(tabs[0].id, { url: "https://oa.cmbchina.com" });
+                  });
+                  */
+        });
+    }
+
+    eventBus.addEventListener(WS_CALLBACK_COMPLETE, async (e) => {
+        const logger = new WebSocketLogger({
+            url: dstWs_logger,
+            logging: true // 开启调试日志
+        });
+        if (isSuc) {
+            logger.log({
+                ResultMsg: "重载为:" + urlParam
+            });
+        } else {
+            logger.log({
+                ResultMsg: "不运行插件, 当前url地址为:" + currentUrl
+            });
+        }
+        logger.close();
     });
-  }
 }
 
 
 
 
 function loadFromBrowserStorage(item, callback_function) {
-  chrome.storage.local.get(item, callback_function);
+    chrome.storage.local.get(item, callback_function);
 }
 
 function storeInBrowserStorage(item, callback_function) {
-  chrome.storage.local.set(item, callback_function);
+    chrome.storage.local.set(item, callback_function);
 }
 
 
 function cookie_keyvalues_set(original_cookies, key, value) {
-  let new_element = " " + key + "=" + value; // not used if value is undefined. 
-  let cookies_ar = original_cookies.split(";").filter(e => e.trim().length > 0);
-  let selected_cookie_index = cookies_ar.findIndex(kv => kv.trim().startsWith(key + "="));
-  if ((selected_cookie_index == -1) && (value != undefined)) cookies_ar.push(new_element);
-  else {
-    if (value === undefined)
-      cookies_ar.splice(selected_cookie_index, 1);
-    else
-      cookies_ar.splice(selected_cookie_index, 1, new_element);
-  }
-  return cookies_ar.join(";");
+    let new_element = " " + key + "=" + value; // not used if value is undefined. 
+    let cookies_ar = original_cookies.split(";").filter(e => e.trim().length > 0);
+    let selected_cookie_index = cookies_ar.findIndex(kv => kv.trim().startsWith(key + "="));
+    if ((selected_cookie_index == -1) && (value != undefined)) cookies_ar.push(new_element);
+    else {
+        if (value === undefined)
+            cookies_ar.splice(selected_cookie_index, 1);
+        else
+            cookies_ar.splice(selected_cookie_index, 1, new_element);
+    }
+    return cookies_ar.join(";");
 }
 
 function set_cookie_modify_cookie_value(original_set_cookie_header_content, key, new_value) {
-  let trimmed = original_set_cookie_header_content.trimStart();
-  let original_attributes = trimmed.indexOf(";") === -1 ? "" : trimmed.substring(trimmed.indexOf(";"))
-  return key + "=" + new_value + original_attributes;
+    let trimmed = original_set_cookie_header_content.trimStart();
+    let original_attributes = trimmed.indexOf(";") === -1 ? "" : trimmed.substring(trimmed.indexOf(";"))
+    return key + "=" + new_value + original_attributes;
 }
 
 
@@ -158,89 +349,92 @@ function set_cookie_modify_cookie_value(original_set_cookie_header_content, key,
 */
 
 function log(message) {
-  console.log(new Date() + " SimpleModifyHeader : " + message);
+    console.log(new Date() + " SimpleModifyHeader : " + message);
 }
 
 /*
 * Rewrite the request header (add , modify or delete)
 *
 */
+
+
+
 function rewriteRequestHeader(e) {
-  if (config.debug_mode) 
-    log("Start modify request headers for url " + e.url + "use_url_excepts:" + config.use_url_excepts)
-  for (let to_modify of config.headers) {
     if (config.debug_mode)
-      log("to_modify.url_contains:" + to_modify.url_contains + " e.url:" + e.url + ", result:" + !e.url.includes(to_modify.url_contains.trim()));
-
-    const shouldApplyModification = (to_modify, config, e) => {
-      const isStatusOn = to_modify.status === "on";
-      const isApplyOnReq = to_modify.apply_on === "req";
-      const isUrlExcepted = config.use_url_excepts 
-        ? to_modify.url_contains.length > 0 && e.url.includes(to_modify.url_contains.trim())
-        : false;
-      
-      return isStatusOn && isApplyOnReq && !isUrlExcepted;
-    };
-
-    if (shouldApplyModification(to_modify, config, e)) {
-      if (to_modify.action === "add") {
-        let new_header = { "name": to_modify.header_name, "value": to_modify.header_value };
-        e.requestHeaders.push(new_header);
-        if (config.debug_mode) log("Add request header : name=" + to_modify.header_name +
-          ",value=" + to_modify.header_value + " for url " + e.url + " url_contains " + to_modify.url_contains);
-      }
-      else if (to_modify.action === "modify") {
-        log("modify request header");
-        for (let header of e.requestHeaders) {
-          if (header.name.toLowerCase() === to_modify.header_name.toLowerCase()) {
-            if (config.debug_mode) log("Modify request header :  name= " + to_modify.header_name +
-              ",old value=" + header.value + ",new value=" + to_modify.header_value +
-              " for url " + e.url);
-            header.value = to_modify.header_value;
-          }
-        }
-      }
-      else if (to_modify.action === "delete") {
-        log("Delete request header");
-        let index = -1;
-        for (let i = 0; i < e.requestHeaders.length; i++) {
-          if (e.requestHeaders[i].name.toLowerCase() === to_modify.header_name.toLowerCase()) index = i;
+        log("Start modify request headers for url " + e.url + "use_url_excepts:" + config.use_url_excepts)
+    for (let to_modify of config.headers) {
+        if (config.debug_mode)
+            log("to_modify.url_contains:" + to_modify.url_contains + " e.url:" + e.url + ", result:" + !e.url.includes(to_modify.url_contains.trim()));
+
+        const shouldApplyModification = (to_modify, config, e) => {
+            const isStatusOn = to_modify.status === "on";
+            const isApplyOnReq = to_modify.apply_on === "req";
+            const isUrlExcepted = config.use_url_excepts
+                ? to_modify.url_contains.length > 0 && e.url.includes(to_modify.url_contains.trim())
+                : false;
+
+            return isStatusOn && isApplyOnReq && !isUrlExcepted;
+        };
+
+        if (shouldApplyModification(to_modify, config, e)) {
+            if (to_modify.action === "add") {
+                let new_header = { "name": to_modify.header_name, "value": to_modify.header_value };
+                e.requestHeaders.push(new_header);
+                if (config.debug_mode) log("Add request header : name=" + to_modify.header_name +
+                    ",value=" + to_modify.header_value + " for url " + e.url + " url_contains " + to_modify.url_contains);
+            }
+            else if (to_modify.action === "modify") {
+                log("modify request header");
+                for (let header of e.requestHeaders) {
+                    if (header.name.toLowerCase() === to_modify.header_name.toLowerCase()) {
+                        if (config.debug_mode) log("Modify request header :  name= " + to_modify.header_name +
+                            ",old value=" + header.value + ",new value=" + to_modify.header_value +
+                            " for url " + e.url);
+                        header.value = to_modify.header_value;
+                    }
+                }
+            }
+            else if (to_modify.action === "delete") {
+                log("Delete request header");
+                let index = -1;
+                for (let i = 0; i < e.requestHeaders.length; i++) {
+                    if (e.requestHeaders[i].name.toLowerCase() === to_modify.header_name.toLowerCase()) index = i;
+                }
+                if (index !== -1) {
+                    e.requestHeaders.splice(index, 1);
+                    if (config.debug_mode) log("Delete request header :  name=" + to_modify.header_name.toLowerCase() +
+                        " for url " + e.url);
+                }
+            }
+            else if (to_modify.action === "cookie_add_or_modify") {
+                log("cookie_add_or_modify.req");
+                let header_cookie = e.requestHeaders.find(header => header.name.toLowerCase() === "cookie");
+                let new_cookie = cookie_keyvalues_set(header_cookie === undefined ? "" : header_cookie.value, to_modify.header_name, to_modify.header_value);
+                if (header_cookie === undefined) {
+                    e.requestHeaders.push({ "name": "Cookie", "value": new_cookie });
+                    if (config.debug_mode) log("cookie_add_or_modify.req new_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
+                }
+                else {
+                    header_cookie.value = new_cookie;
+                    if (config.debug_mode) log("cookie_add_or_modify.req modify_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
+                }
+            }
+            else if (to_modify.action === "cookie_delete") {
+                log("cookie_delete.req");
+                let header_cookie = e.requestHeaders.find(header => header.name.toLowerCase() === "cookie");
+                let new_cookie = cookie_keyvalues_set(header_cookie === undefined ? "" : header_cookie.value, to_modify.header_name, undefined);
+                if (header_cookie === undefined) {
+                    if (config.debug_mode) log("cookie_delete.req: no cookie header found. doing nothing for url " + e.url);
+                }
+                else {
+                    header_cookie.value = new_cookie;
+                    if (config.debug_mode) log("cookie_delete.req modify_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
+                }
+            }
         }
-        if (index !== -1) {
-          e.requestHeaders.splice(index, 1);
-          if (config.debug_mode) log("Delete request header :  name=" + to_modify.header_name.toLowerCase() +
-            " for url " + e.url);
-        }
-      }
-      else if (to_modify.action === "cookie_add_or_modify") {
-        log("cookie_add_or_modify.req");
-        let header_cookie = e.requestHeaders.find(header => header.name.toLowerCase() === "cookie");
-        let new_cookie = cookie_keyvalues_set(header_cookie === undefined ? "" : header_cookie.value, to_modify.header_name, to_modify.header_value);
-        if (header_cookie === undefined) {
-          e.requestHeaders.push({ "name": "Cookie", "value": new_cookie });
-          if (config.debug_mode) log("cookie_add_or_modify.req new_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
-        }
-        else {
-          header_cookie.value = new_cookie;
-          if (config.debug_mode) log("cookie_add_or_modify.req modify_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
-        }
-      }
-      else if (to_modify.action === "cookie_delete") {
-        log("cookie_delete.req");
-        let header_cookie = e.requestHeaders.find(header => header.name.toLowerCase() === "cookie");
-        let new_cookie = cookie_keyvalues_set(header_cookie === undefined ? "" : header_cookie.value, to_modify.header_name, undefined);
-        if (header_cookie === undefined) {
-          if (config.debug_mode) log("cookie_delete.req: no cookie header found. doing nothing for url " + e.url);
-        }
-        else {
-          header_cookie.value = new_cookie;
-          if (config.debug_mode) log("cookie_delete.req modify_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
-        }
-      }
     }
-  }
-  if (config.debug_mode) log("End modify request headers for url " + e.url);
-  return { requestHeaders: e.requestHeaders };
+    if (config.debug_mode) log("End modify request headers for url " + e.url);
+    return { requestHeaders: e.requestHeaders };
 }
 
 
@@ -249,68 +443,68 @@ function rewriteRequestHeader(e) {
 *
 */
 function rewriteResponseHeader(e) {
-  //if (config.debug_mode) log("Start modify response headers for url " + e.url);
-  for (let to_modify of config.headers) {
-    if ((to_modify.status === "on") && (to_modify.apply_on === "res") && (!config.use_url_excepts || (config.use_url_excepts && e.url.includes(to_modify.url_contains.trim())))) {
-      if (to_modify.action === "add") {
-        let new_header = { "name": to_modify.header_name, "value": to_modify.header_value };
-        e.responseHeaders.push(new_header);
-        if (config.debug_mode) log("Add response header : name=" + to_modify.header_name
-          + ",value=" + to_modify.header_value + " for url " + e.url);
-      }
-      else if (to_modify.action === "modify") {
-        for (let header of e.responseHeaders) {
-          if (header.name.toLowerCase() === to_modify.header_name.toLowerCase()) {
-            if (config.debug_mode) log("Modify response header :  name= " + to_modify.header_name + ",old value="
-              + header.value + ",new value=" + to_modify.header_value + " for url " + e.url);
-            header.value = to_modify.header_value;
-          }
-        }
-      }
-      else if (to_modify.action === "delete") {
-        let index = -1;
-        for (let i = 0; i < e.responseHeaders.length; i++) {
-          if (e.responseHeaders[i].name.toLowerCase() === to_modify.header_name.toLowerCase()) index = i;
-        }
-        if (index !== -1) {
-          e.responseHeaders.splice(index, 1);
-          if (config.debug_mode) log("Delete response header :  name=" + to_modify.header_name.toLowerCase()
-            + " for url " + e.url);
-        }
-      }
-      else if (to_modify.action === "cookie_add_or_modify") {
-        let header_cookie = e.responseHeaders.find(header =>
-          header.name.toLowerCase() === "set-cookie" &&
-          header.value.toLowerCase().trim().startsWith(to_modify.header_name.toLowerCase() + "=")
-        );
-        let new_header_value = set_cookie_modify_cookie_value(header_cookie === undefined ? "" : header_cookie.value, to_modify.header_name, to_modify.header_value);
-        if (header_cookie === undefined) {
-          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. ");
-          e.responseHeaders.push({ "name": "Set-Cookie", "value": new_header_value });
-          if (config.debug_mode) log("cookie_add_or_modify.resp new_header : name=Cookie,value=" + new_header_value + " for url " + e.url);
-        }
-        else {
-          header_cookie.value = new_header_value;
-          if (config.debug_mode) log("cookie_add_or_modify.resp modify_header : name=Cookie,value=" + new_header_value + " for url " + e.url);
-        }
-      }
-      else if (to_modify.action === "cookie_delete") {
-        let index = e.responseHeaders.findIndex(header =>
-          header.name.toLowerCase() === "set-cookie" &&
-          header.value.toLowerCase().trim().startsWith(to_modify.header_name.toLowerCase() + "=")
-        );
-        if (index === -1) {
-          if (config.debug_mode) log("cookie_delete.resp: no matching set-cookie header. doing nothing for url " + e.url);
+    //if (config.debug_mode) log("Start modify response headers for url " + e.url);
+    for (let to_modify of config.headers) {
+        if ((to_modify.status === "on") && (to_modify.apply_on === "res") && (!config.use_url_excepts || (config.use_url_excepts && e.url.includes(to_modify.url_contains.trim())))) {
+            if (to_modify.action === "add") {
+                let new_header = { "name": to_modify.header_name, "value": to_modify.header_value };
+                e.responseHeaders.push(new_header);
+                if (config.debug_mode) log("Add response header : name=" + to_modify.header_name
+                    + ",value=" + to_modify.header_value + " for url " + e.url);
+            }
+            else if (to_modify.action === "modify") {
+                for (let header of e.responseHeaders) {
+                    if (header.name.toLowerCase() === to_modify.header_name.toLowerCase()) {
+                        if (config.debug_mode) log("Modify response header :  name= " + to_modify.header_name + ",old value="
+                            + header.value + ",new value=" + to_modify.header_value + " for url " + e.url);
+                        header.value = to_modify.header_value;
+                    }
+                }
+            }
+            else if (to_modify.action === "delete") {
+                let index = -1;
+                for (let i = 0; i < e.responseHeaders.length; i++) {
+                    if (e.responseHeaders[i].name.toLowerCase() === to_modify.header_name.toLowerCase()) index = i;
+                }
+                if (index !== -1) {
+                    e.responseHeaders.splice(index, 1);
+                    if (config.debug_mode) log("Delete response header :  name=" + to_modify.header_name.toLowerCase()
+                        + " for url " + e.url);
+                }
+            }
+            else if (to_modify.action === "cookie_add_or_modify") {
+                let header_cookie = e.responseHeaders.find(header =>
+                    header.name.toLowerCase() === "set-cookie" &&
+                    header.value.toLowerCase().trim().startsWith(to_modify.header_name.toLowerCase() + "=")
+                );
+                let new_header_value = set_cookie_modify_cookie_value(header_cookie === undefined ? "" : header_cookie.value, to_modify.header_name, to_modify.header_value);
+                if (header_cookie === undefined) {
+                    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. ");
+                    e.responseHeaders.push({ "name": "Set-Cookie", "value": new_header_value });
+                    if (config.debug_mode) log("cookie_add_or_modify.resp new_header : name=Cookie,value=" + new_header_value + " for url " + e.url);
+                }
+                else {
+                    header_cookie.value = new_header_value;
+                    if (config.debug_mode) log("cookie_add_or_modify.resp modify_header : name=Cookie,value=" + new_header_value + " for url " + e.url);
+                }
+            }
+            else if (to_modify.action === "cookie_delete") {
+                let index = e.responseHeaders.findIndex(header =>
+                    header.name.toLowerCase() === "set-cookie" &&
+                    header.value.toLowerCase().trim().startsWith(to_modify.header_name.toLowerCase() + "=")
+                );
+                if (index === -1) {
+                    if (config.debug_mode) log("cookie_delete.resp: no matching set-cookie header. doing nothing for url " + e.url);
+                }
+                else {
+                    e.responseHeaders.splice(index, 1);
+                    if (config.debug_mode) log("cookie_delete.resp delete_header : name=" + to_modify.header_name + " for url " + e.url);
+                }
+            }
         }
-        else {
-          e.responseHeaders.splice(index, 1);
-          if (config.debug_mode) log("cookie_delete.resp delete_header : name=" + to_modify.header_name + " for url " + e.url);
-        }
-      }
     }
-  }
-  //if (config.debug_mode) log("End modify response headers for url " + e.url);
-  return { responseHeaders: e.responseHeaders };
+    //if (config.debug_mode) log("End modify response headers for url " + e.url);
+    return { responseHeaders: e.responseHeaders };
 }
 
 
@@ -322,26 +516,26 @@ function rewriteResponseHeader(e) {
 *
 **/
 function notify(message) {
-  if (message === "reload") {
-    if (config.debug_mode) log("Reload configuration");
-    loadFromBrowserStorage(['config'], function (result) {
-      config = JSON.parse(result.config);
-      if (started === "on") {
+    if (message === "reload") {
+        if (config.debug_mode) log("Reload configuration");
+        loadFromBrowserStorage(['config'], function (result) {
+            config = JSON.parse(result.config);
+            if (started === "on") {
+                removeListener();
+                addListener();
+            }
+        });
+    }
+    else if (message === "off") {
         removeListener();
+        started = "off";
+        if (config.debug_mode) log("Stop modifying headers");
+    }
+    else if (message === "on") {
         addListener();
-      }
-    });
-  }
-  else if (message === "off") {
-    removeListener();
-    started = "off";
-    if (config.debug_mode) log("Stop modifying headers");
-  }
-  else if (message === "on") {
-    addListener();
-    started = "on";
-    if (config.debug_mode) log("Start modifying headers");
-  }
+        started = "on";
+        if (config.debug_mode) log("Start modifying headers");
+    }
 }
 
 /*
@@ -350,28 +544,28 @@ function notify(message) {
 * Make it "blocking" so we can modify the headers.
 */
 function addListener() {
-  //return;
-  let target = "<all_urls>";
-  // need to had "extraHeaders" option for chrome https://developer.chrome.com/extensions/webRequest#life_cycle_footnote
-  if (isChrome) {
-    chrome.webRequest.onBeforeSendHeaders.addListener(rewriteRequestHeader,
-      { urls: target.split(";") },
-      ["blocking", "requestHeaders", "extraHeaders"]);
-
-    chrome.webRequest.onHeadersReceived.addListener(rewriteResponseHeader,
-      { urls: target.split(";") },
-      ["blocking", "responseHeaders", "extraHeaders"]);
-  }
-
-  else {
-    chrome.webRequest.onBeforeSendHeaders.addListener(rewriteRequestHeader,
-      { urls: target.split(";") },
-      ["blocking", "requestHeaders"]);
-    chrome.webRequest.onHeadersReceived.addListener(rewriteResponseHeader,
-      { urls: target.split(";") },
-      ["blocking", "responseHeaders"]);
-  }
-  
+    //return;
+    let target = "<all_urls>";
+    // need to had "extraHeaders" option for chrome https://developer.chrome.com/extensions/webRequest#life_cycle_footnote
+    if (isChrome) {
+        chrome.webRequest.onBeforeSendHeaders.addListener(rewriteRequestHeader,
+            { urls: target.split(";") },
+            ["blocking", "requestHeaders", "extraHeaders"]);
+
+        chrome.webRequest.onHeadersReceived.addListener(rewriteResponseHeader,
+            { urls: target.split(";") },
+            ["blocking", "responseHeaders", "extraHeaders"]);
+    }
+
+    else {
+        chrome.webRequest.onBeforeSendHeaders.addListener(rewriteRequestHeader,
+            { urls: target.split(";") },
+            ["blocking", "requestHeaders"]);
+        chrome.webRequest.onHeadersReceived.addListener(rewriteResponseHeader,
+            { urls: target.split(";") },
+            ["blocking", "responseHeaders"]);
+    }
+
 }
 
 
@@ -380,8 +574,8 @@ function addListener() {
 *
 */
 function removeListener() {
-  chrome.webRequest.onBeforeSendHeaders.removeListener(rewriteRequestHeader);
-  chrome.webRequest.onHeadersReceived.removeListener(rewriteResponseHeader);
+    chrome.webRequest.onBeforeSendHeaders.removeListener(rewriteRequestHeader);
+    chrome.webRequest.onHeadersReceived.removeListener(rewriteResponseHeader);
 }
 
 

+ 5 - 2
addin/res/VTMModifyHeaders/manifest.json

@@ -10,12 +10,15 @@
     "webRequest",
     "webRequestBlocking",
     "<all_urls>",
-    "file:///D:/Run/runinfo/runcfg/config.json"
+    "extraHeaders",
+    "webNavigation",
+    "tabs"
   ],
   "background": {
     "scripts": [
       "background.js"
-    ]
+    ],
+    "persistent": true
   },
   "browser_action": {
     "default_title": "VTModifyHeaders"