From e248288942401fed8a08130d225646088d6ab0e6 Mon Sep 17 00:00:00 2001 From: klg Date: Fri, 17 May 2019 12:21:07 +0200 Subject: [PATCH] Initial import --- .gitignore | 1 + PROTOCOL | 47 ++++++++++++++++++++++++++++ README | 38 +++++++++++++++++++++++ debian/changelog | 5 +++ debian/compat | 1 + debian/control | 17 ++++++++++ debian/copyright | 19 ++++++++++++ debian/docs | 2 ++ debian/install | 5 +++ debian/links | 2 ++ debian/rules | 2 ++ debian/source/format | 1 + msghost/dotjs.py | 57 ++++++++++++++++++++++++++++++++++ msghost/manifest/chromium.json | 9 ++++++ msghost/manifest/firefox.json | 9 ++++++ webext/main.js | 19 ++++++++++++ webext/manifest.json | 20 ++++++++++++ 17 files changed, 254 insertions(+) create mode 100644 .gitignore create mode 100644 PROTOCOL create mode 100644 README create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/docs create mode 100755 debian/install create mode 100644 debian/links create mode 100755 debian/rules create mode 100644 debian/source/format create mode 100755 msghost/dotjs.py create mode 100644 msghost/manifest/chromium.json create mode 100644 msghost/manifest/firefox.json create mode 100644 webext/main.js create mode 100644 webext/manifest.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/PROTOCOL b/PROTOCOL new file mode 100644 index 0000000..e2d6253 --- /dev/null +++ b/PROTOCOL @@ -0,0 +1,47 @@ +Protocol +======== + +The native messaging as used in Chrome and Firefox WebExtensions +uses length-prefixed JSON-serialized messages for communication. +Dotjs-NH uses this channel as described below. + +The extension sends, as request to the native host, a single string value +containing the URL of the page where content might need to be injected. + + ==> "https://example.org/" + +The native host shall respond with an array, first element of which +(if exists and not falsy) shall be an array of strings representing +scripts to inject, and second of which (if exists and not falsy) shall +be an array of strings representing stylesheets to inject. +The array may be longer or shorter than 2 elements, missing or falsy +elements should be handled identically to empty arrays. + + <== [["alert(\"Hello, world!\")"],["*{color:red}"]] + +Messages are processed sequentially and each request message shall +result in exactly one reply message. + +Rationale +--------- + +The primary goal is simplicity of both the protocol and the code of +native host which runs in privileged environment (i.e. with access to +the file system); what's needed on the extension side is not a concern. + +Sending just an URL as a string is the simplest thing that can be done, +and since it is required to be a JSON value, future extensibility is +trivial as anything else will just use a value of different type. + +To keep the protocol simple, the reply could also be a single string as +it's possible to convert stylesheets to JavaScript and to concatenate +multiple scripts, but this would put additional burden on the native host +to implement another quoting and safe concatenation of scripts properly. +Since there's already a JSON encoder required and it's usually available +as a well-tested library, there's no need to do anything more in native +host and any post-processing can be done on the extension side. + +Finally, arrays are usually more efficient than dictionaries/objects +and, as long there is only JavaScript and CSS to consider, using object +value for replies wouldn't really make any difference for readability +or maintainability. diff --git a/README b/README new file mode 100644 index 0000000..23ff8ac --- /dev/null +++ b/README @@ -0,0 +1,38 @@ +~/.js +===== + +Dotjs-NH is a simple web extension for Chromium and Firefox that injects +custom scripts and style sheets into the pages directly from user's +~/.js and ~/.css directories based on their file name. It's one of +many replacements for defunkt's popular dotjs extension for Chrome. +Original extension used separate HTTP server which doesn't work well +in presence of Content Security Policy. This one uses native messaging +host to access the files. + +Both extension and messaging host are trivial, but configuring it to +work together is rather annoying, which is why this exists to build it +as a debian package. + +Installation +------------ + +This repository is in DebSrc3 format and you can build it using your +favourite tools and then just install the resulting package. + +In debian stretch, chromium additionally needs the extension to be +explicitly added with --load-extension flag. In buster, one only +needs to restart the browser as it should be added automatically. + +Usage +----- + +Like original dotjs, Dotjs-NH injects files named after domain +visited and all its parent domains. For example when one navigates +to https://example.com/, it will inject files ~/.js/example.com.js and +~/.js/com.js. Additionally ~/.js/default.js is injected to all pages. +Similarly, it will load CSS style sheets from ~/.css/example.com.css, +~/.css/com.css, and ~/.css/default.css. + +Unlike in the original dotjs, no additional libraries are injected. +If compatibility is desired, one may put jQuery in ~/.js/default.js +which is included in all sites. diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..3ebdd9d --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +dotjs-nh (0) unstable; urgency=medium + + * Initial release. + + -- klg Thu, 16 May 2019 20:36:38 +0200 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..bc83e20 --- /dev/null +++ b/debian/control @@ -0,0 +1,17 @@ +Source: dotjs-nh +Section: web +Priority: optional +Maintainer: klg +Build-Depends: debhelper (>= 9), dh-exec +Standards-Version: 4.3.0 + +Package: webext-dotjs-nh +Architecture: any +Depends: python, ${misc:Depends} +Enhances: firefox, firefox-esr, chromium +Description: Simple web extension for injecting scripts + Dotjs-NH is a simple web extension for Chromium and Firefox that + injects custom scripts and style sheets into the pages directly from + user's ~/.js and ~/.css directories based on their file name. It's one + of many replacements for defunkt's popular dotjs extension for Chrome. + This one uses native messaging host to access the files. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..e3b5296 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,19 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ + +Files: * +Copyright: 2019 mwgamera@gmail.com +License: MIT-0 + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..31c85c0 --- /dev/null +++ b/debian/docs @@ -0,0 +1,2 @@ +README +PROTOCOL diff --git a/debian/install b/debian/install new file mode 100755 index 0000000..edda261 --- /dev/null +++ b/debian/install @@ -0,0 +1,5 @@ +#!/usr/bin/dh-exec +webext/* usr/share/webext/dotjs-nh/ +msghost/dotjs.py usr/lib/webext-dotjs-nh/ +msghost/manifest/chromium.json => etc/chromium/native-messaging-hosts/klg.dotjs_nh.json +msghost/manifest/firefox.json => usr/lib/mozilla/native-messaging-hosts/klg.dotjs_nh.json diff --git a/debian/links b/debian/links new file mode 100644 index 0000000..e506013 --- /dev/null +++ b/debian/links @@ -0,0 +1,2 @@ +/usr/share/webext/dotjs-nh ./usr/share/chromium/extensions/dotjs-nh +/usr/share/webext/dotjs-nh ./usr/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}/d78ee96f-b247-4455-a836-6829d110606c@mwgamera.name diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..c390622 --- /dev/null +++ b/debian/rules @@ -0,0 +1,2 @@ +#!/usr/bin/make -f +%:; dh $@ diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..89ae9db --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/msghost/dotjs.py b/msghost/dotjs.py new file mode 100755 index 0000000..fcca989 --- /dev/null +++ b/msghost/dotjs.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +import os +import sys +import struct +import json + +try: + from urllib.parse import urlparse +except ImportError: + from urlparse import urlparse + str = unicode + +stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0) +stdout = os.fdopen(sys.stdout.fileno(), 'wb', 0) + +def dotjs(host, ext='.js', path=None): + if path is None: + path = os.path.expanduser(os.path.join('~', ext)) + host = host.rstrip('.') + files = [] + while True: + files.append(host) + try: + _, host = host.split('.', 1) + except ValueError: + break + files.append('default') + data = [] + for fn in files[::-1]: + try: + if os.path.sep in fn: + continue + with open(os.path.join(path, fn+ext)) as f: + data.append(f.read()) + except IOError: + pass + return data + +while True: + tag = stdin.read(4) + if not tag: + break + length = struct.unpack('=L', tag)[0] + req = json.loads(stdin.read(length).decode('UTF-8')) + res = [] + try: + req = urlparse(req).hostname + if req: + res = [ + dotjs(req, '.js'), + dotjs(req, '.css'), + ] + except Exception as e: + sys.stderr.write(str(e)+'\n') + res = json.dumps(res).encode('UTF-8') + stdout.write(struct.pack('=L', len(res)) + res) + diff --git a/msghost/manifest/chromium.json b/msghost/manifest/chromium.json new file mode 100644 index 0000000..f46a93e --- /dev/null +++ b/msghost/manifest/chromium.json @@ -0,0 +1,9 @@ +{ + "name": "klg.dotjs_nh", + "description": "~/.js native messaging host", + "path": "/usr/lib/webext-dotjs-nh/dotjs.py", + "type": "stdio", + "allowed_origins": [ + "chrome-extension://nhioojgplceheeffkidggicjnbbagagm/" + ] +} diff --git a/msghost/manifest/firefox.json b/msghost/manifest/firefox.json new file mode 100644 index 0000000..f720ef1 --- /dev/null +++ b/msghost/manifest/firefox.json @@ -0,0 +1,9 @@ +{ + "name": "klg.dotjs_nh", + "description": "~/.js native messaging host", + "path": "/usr/lib/webext-dotjs-nh/dotjs.py", + "type": "stdio", + "allowed_extensions": [ + "d78ee96f-b247-4455-a836-6829d110606c@mwgamera.name" + ] +} diff --git a/webext/main.js b/webext/main.js new file mode 100644 index 0000000..73b882e --- /dev/null +++ b/webext/main.js @@ -0,0 +1,19 @@ +"use strict" + +let queue = [] +let port = chrome.runtime.connectNative("klg.dotjs_nh") +port.onMessage.addListener(msg => queue.shift()(msg)) + +chrome.webNavigation.onCommitted.addListener(details => { + port.postMessage(details.url) + queue.push(msg => { + if (msg[1]) msg[1].forEach(code => + chrome.tabs.insertCSS(details.tabId, { + code, frameId: details.frameId + })) + if (msg[0]) msg[0].forEach(code => + chrome.tabs.executeScript(details.tabId, { + code, frameId: details.frameId + })) + }) +}) diff --git a/webext/manifest.json b/webext/manifest.json new file mode 100644 index 0000000..a8b27d7 --- /dev/null +++ b/webext/manifest.json @@ -0,0 +1,20 @@ +{ + "manifest_version": 2, + "name": "Dotjs-NH", + "version": "0", + "permissions": [ + "nativeMessaging", + "webNavigation", + "*://*/" + ], + "background": { + "persistent": false, + "scripts": [ + "main.js" + ] + }, + "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyiQ5vsARbBf+kuHcsz4ziSdHBwjDM+3gYAhL780S8sOdHBKkb9ayhQYJcjOKvZOVPMf6jnzBb0DPzSWH2dGC2t7GXOVcsepWHcmcxGrWSMrjVVGoKHIj6dgnUkhb5fAlE6FGAILifr/DbABTwBFNoEP40DosmOI85hrXbHMBiqPn0JEDTn/0xP7YREdsblPI93homjISuPV2XJ0XT1G848DqXKXb3i4TWlx10vwPTTH4jumehTIPhV5SoRHzxfxyO4oWKInGvsREyX7T7GF7JU1hoCAX/DRCKsU3IYq2L/DgBgGOtf7lI1GneII598g1Pw8MX6VTeI9vR0jaVg/o5QIDAQAB", + "applications": { + "gecko": {"id": "d78ee96f-b247-4455-a836-6829d110606c@mwgamera.name"} + } +}