help-librejs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Remove dependency on jssha


From: Piper McCorkle
Subject: [PATCH] Remove dependency on jssha
Date: Thu, 22 Aug 2024 23:26:33 -0500

Now that the web crypto API is widespread, librejs doesn't need to
depend on jssha for SHA-512 hashing. Since web crypto is async, I've
propagated async-ness through the call stack for the hash function.

I'm looking to package librejs for Debian, and since jssha isn't already
packaged for Debian removing the dependency makes the packaging work
easier.
---
 README             |  2 +-
 bg/ListManager.js  |  4 ++--
 common/Storage.js  | 30 +++++++++++++++++++-----------
 docs/librejs.texi  |  2 +-
 main_background.js | 12 ++++++------
 package.json       |  9 +++++++++
 6 files changed, 38 insertions(+), 21 deletions(-)
 create mode 100644 package.json

diff --git a/README b/README
index 7c488cf..6efccf4 100644
--- a/README
+++ b/README
@@ -4,7 +4,7 @@
 BUILD:
 
 First, you need to get some stuff with npm:
-  $ npm install acorn jssha browserify
+  $ npm install
   $ export PATH=$PATH:./node_modules/.bin
 
 To build the extension run:
diff --git a/bg/ListManager.js b/bg/ListManager.js
index 2800c3f..4c45c2a 100644
--- a/bg/ListManager.js
+++ b/bg/ListManager.js
@@ -49,9 +49,9 @@ class ListManager {
     with a trailing (hash).
     Returns "blacklisted", "whitelisted" or defValue
   */
-  getStatus(key, defValue = 'unknown') {
+  async getStatus(key, defValue = 'unknown') {
     const { blacklist, whitelist } = this.lists;
-    const inline = ListStore.inlineItem(key);
+    const inline = await ListStore.inlineItem(key);
     if (inline) {
       return blacklist.contains(inline)
         ? 'blacklisted'
diff --git a/common/Storage.js b/common/Storage.js
index 0d27c01..398dbb4 100644
--- a/common/Storage.js
+++ b/common/Storage.js
@@ -67,12 +67,19 @@ class ListStore {
     });
   }
 
-  static inlineItem(url) {
+  static async inlineItem(url) {
     // here we simplify and hash inline script references
-    return url.startsWith('inline:') ? url
-      : url.startsWith('view-source:')
-      && url.replace(/^view-source:[\w-+]+:\/+([^/]+).*#line\d+/, 
'inline://$1#')
-        .replace(/\n[^]*/, s => s.replace(/\s+/g, ' ').substring(0, 16) + '…' 
+ hash(s.trim()));
+    if (url.startsWith('inline:')) {
+      return url;
+    } else if (url.startsWith('view-source:')) {
+      const replaced = 
url.replace(/^view-source:[\w-+]+:\/+([^/]+).*#line\d+/, 'inline://$1#');
+      const lines = replaced.split('\n');
+      for (let i = 1; i < lines.length; i++) {
+        lines[i] = lines[i].replace(/\s+/g, ' ').substring(0, 16) + '…' + 
await hash(s.trim());
+      }
+    } else {
+      return false;
+    }
   }
   static hashItem(hash) {
     return hash.startsWith('(') ? hash : `(${hash})`;
@@ -124,14 +131,15 @@ class ListStore {
   }
 }
 
-function hash(source) {
-  const shaObj = new jssha('SHA-256', 'TEXT')
-  shaObj.update(source);
-  return shaObj.getHash('HEX');
+async function hash(source) {
+  const encoder = new TextEncoder();
+  const data = encoder.encode(source);
+  const hashBuffer = await crypto.subtle.digest('SHA-256', data);
+  const hashArray = Array.from(new Uint8Array(hashBuffer));
+  const hashHex = hashArray.map((b) => b.toString(16).padStart(2, 
"0")).join("");
+  return hashHex;
 }
 
 if (typeof module === 'object') {
   module.exports = { ListStore, Storage, hash };
-  // TODO: eliminate the var
-  var jssha = require('jssha');
 }
diff --git a/docs/librejs.texi b/docs/librejs.texi
index c3e7ca7..15f665c 100644
--- a/docs/librejs.texi
+++ b/docs/librejs.texi
@@ -343,7 +343,7 @@ LibreJS @value{VERSION} depends on a number of 
Node.js-based libraries that
 can be installed using the @code{npm} utility:
 
 @verbatim
-  $ npm install acorn jssha browserify
+  $ npm install
   $ export PATH=$PATH:./node_modules/.bin
 @end verbatim
 
diff --git a/main_background.js b/main_background.js
index 87b80ae..40407df 100644
--- a/main_background.js
+++ b/main_background.js
@@ -66,7 +66,7 @@ async function createReport(initializer) {
   let [url] = (template.url || (await 
browser.tabs.get(initializer.tabId)).url).split('#');
   template.url = url;
   template.site = ListStore.siteItem(url);
-  template.siteStatus = listManager.getStatus(template.site);
+  template.siteStatus = await listManager.getStatus(template.site);
   const list = { 'whitelisted': whitelist, 'blacklisted': blacklist 
}[template.siteStatus];
   if (list) {
     template.listedSite = ListManager.siteMatch(template.site, list);
@@ -133,7 +133,7 @@ async function updateReport(tabId, oldReport, updateUI = 
false) {
     if (!Array.isArray(entries)) continue;
     const defValue = property === 'accepted' || property === 'blocked' ? 
property : 'unknown';
     for (const script of entries) {
-      const status = listManager.getStatus(script[0], defValue);
+      const status = await listManager.getStatus(script[0], defValue);
       if (Array.isArray(newReport[status])) newReport[status].push(script);
     }
   }
@@ -190,7 +190,7 @@ async function addReportEntry(tabId, action) {
   let entryType;
   // Update the report if the scriptName is new for the entryType.
   try {
-    entryType = listManager.getStatus(scriptName, actionType);
+    entryType = await listManager.getStatus(scriptName, actionType);
     const entries = report[entryType];
     if (!entries.find(e => e[0] === scriptName)) {
       dbgPrint(activityReports);
@@ -257,7 +257,7 @@ async function connected(p) {
         if (m.site) {
           key = ListStore.siteItem(m.site);
         } else {
-          key = ListStore.inlineItem(key) || key;
+          key = (await ListStore.inlineItem(key)) || key;
         }
         await listManager[action](key);
         update = true;
@@ -389,7 +389,7 @@ async function checkScriptAndUpdateReport(scriptSrc, url, 
tabId, whitelisted, is
       return `/* LibreJS: script whitelisted by user preference. 
*/\n${scriptSrc}`;
   }
 
-  const [accepted, editedSource, reason] = 
listManager.builtInHashes.has(hash(scriptSrc)) ? [true, scriptSrc, 'Common 
script known to be free software.'] : checkLib.checkScriptSource(scriptSrc, 
scriptName, isExternal);
+  const [accepted, editedSource, reason] = listManager.builtInHashes.has(await 
hash(scriptSrc)) ? [true, scriptSrc, 'Common script known to be free 
software.'] : checkLib.checkScriptSource(scriptSrc, scriptName, isExternal);
 
   if (tabId < 0) {
     return editedSource;
@@ -450,7 +450,7 @@ function blockGoogleAnalytics(request) {
 async function blockBlacklistedScripts(request) {
   const { tabId, documentUrl } = request;
   const url = ListStore.urlItem(request.url);
-  const status = listManager.getStatus(url);
+  const status = await listManager.getStatus(url);
   if (status !== 'blacklisted') return {};
   const blacklistedSite = ListManager.siteMatch(url, blacklist);
   await addReportEntry(tabId, {
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..e385007
--- /dev/null
+++ b/package.json
@@ -0,0 +1,9 @@
+{
+       "name": "librejs",
+       "dependencies": {
+               "acorn": "^8.12.1"
+       },
+       "devDependencies": {
+               "browserify": "^17.0.0"
+       }
+}
-- 
2.43.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]