From 12459ffbcc9e2d8a6dc2b5fcaa0f6da696501354 Mon Sep 17 00:00:00 2001
From: Recolic Keghart <root@recolic.net>
Date: Sun, 31 Oct 2021 01:36:05 +0800
Subject: [PATCH] support cookie-response

---
 background.js | 64 +++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 60 insertions(+), 4 deletions(-)

diff --git a/background.js b/background.js
index c677ebc..e185e2a 100644
--- a/background.js
+++ b/background.js
@@ -108,6 +108,12 @@ function storeInBrowserStorage(item, callback_function) {
  * Also assuming that, all cookies doesn't contains semicolon. 
  *   (99.9% websites are following these rules)
  *
+ * Example: 
+ *   cookie_keyvalues_set("msg=good; user=recolic; password=test", "user", "p")
+ *     => "msg=good; user=p; password=test"
+ *   cookie_keyvalues_set("msg=good; user=recolic; password=test", "time", "night")
+ *     => "msg=good; user=recolic; password=test;time=night"
+ *
  * Recolic K <root@recolic.net>
  */
 function cookie_keyvalues_set(original_cookies, key, value) {
@@ -124,6 +130,26 @@ function cookie_keyvalues_set(original_cookies, key, value) {
     }
     return cookies_ar.join(";");
 }
+/* 
+ * This function modify the HTTP response header "Set-Cookie", 
+ *   and replace the value of its cookie, to some new_value. 
+ * If key doesn't match original_set_cookie_header_content, new key is used in result. 
+ *
+ * Example: 
+ *   set_cookie_modify_cookie_value("token=123; path=/; expires=Sat, 30 Oct 2021 17:57:32 GMT; secure; HttpOnly", "token", "bar")
+ *     => "token=bar; path=/; expires=Sat, 30 Oct 2021 17:57:32 GMT; secure; HttpOnly"
+ *   set_cookie_modify_cookie_value("  user=recolic", "user", "hacker")
+ *     => "user=hacker"
+ *   set_cookie_modify_cookie_value("user=recolic; path=/; HttpOnly", "token", "bar")
+ *     => "token=bar; path=/; HttpOnly"
+ *
+ * Recolic K <root@recolic.net>
+ */
+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;
+}
 
 
 /*
@@ -175,22 +201,22 @@ function rewriteRequestHeader(e) {
         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 new_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
+          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 modify_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
+          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") {
         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: no cookie header found. doing nothing for url " + e.url);
+          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 modify_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
+          if (config.debug_mode) log("cookie_delete.req modify_header : name=Cookie,value=" + new_cookie + " for url " + e.url);
         }
       }
     }
@@ -234,6 +260,36 @@ function rewriteResponseHeader(e) {
             + " for url " + e.url);
         }
       }
+      else if (to_modify.action === "cookie_add_or_modify") {
+        let header_cookie = e.requestHeaders.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.requestHeaders.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);
+        }
+      }
     }
   }
   if (config.debug_mode) log("End modify response headers for url " + e.url);
-- 
GitLab