From 72ffbda9c4f4d9a7a9f3b34c0a965611d7222a84 Mon Sep 17 00:00:00 2001 From: Andrew Cady Date: Sun, 21 Jun 2020 21:29:04 -0400 Subject: add blog.md --- firefox-sideloader/blog.md | 270 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 firefox-sideloader/blog.md diff --git a/firefox-sideloader/blog.md b/firefox-sideloader/blog.md new file mode 100644 index 0000000..13ab0ca --- /dev/null +++ b/firefox-sideloader/blog.md @@ -0,0 +1,270 @@ +# Firefox has deprecated "side-loading" of extensions + +From [the announcement](https://blog.mozilla.org/addons/2020/03/10/support-for-extension-sideloading-has-ended/): + +> Today marks the release of Firefox 74 and as we announced last fall, +> developers will no longer be able to install extensions without +> the user taking an action. This installation method was typically +> done through application installers, and is commonly referred to as +> “sideloading.” +> +> If you are the developer of an extension that installs itself via +> sideloading, please make sure that your users can install the +> extension from your own website or from addons.mozilla.org (AMO). + +Of course, it is still possible to side-load. The browser itself is +installing the extension, and the browser isn't even closed source. It +can't hide what it's doing, just obfuscate and write annoying blog posts +about how taking away features is making users safer. + +I spent some time yesterday figuring out how to side-load extensions +and writing code to do this for my own purposes. I got a script working +that gives an automated extension install into a new profile based on +copying out of some other profile where the extension had been installed +by firefox interactively. + +What I'm doing is very coarse -- mostly just copying entire files, but +editing the paths within them to refer to the new extension directory +instead of the old one. + +This works for me since I want to copy my entire list of extensions, +but you want to surgically install just one extension. I didn't go +that far with my code but I think I can tell you how to start the +surgery based on what I found. You just need to edit some JSON. (BTW +[jq](https://github.com/stedolan/jq) is great.) + +To get an extension running in a firefox profile, you need to edit the +following files in the profile dir: + +``` +./extension-settings.json +./extension-preferences.json +./extensions.json +./addonStartup.json.lz4 +./prefs.js +``` + +* `/extensions/` + + Put your `*.xpi` here. + +* `extensions.json` + + Each extension needs a long entry in the `addons` array + +* `extension-settings.json` + + Used to give extensions some special privileges, refers to extension by id + (the `id` field in `extensions.json`) + +* `extension-preferences.json` + + Used to give extensions privilege to run in private tab, refers to extensions + by id + +* `addonStartup.json.lz4` + + Contains one `addons` object within each of the four labels "app-builtin", + "app-profile", "app-system-defaults", "app-system-share". + + I use https://github.com/jusw85/mozlz4 to decompress and compress this file. + +* prefs.js + + Needed to set `extensions.webextensions.uuids` or to make an extension + run as the homepage or new tab page without user interaction. I also + use it to bypass confirmation/warning popups, mozilla upgrade notice, + etc. + +Here is an example of the JSON for each file for one extension. This is +generated by script and the values are edited (by jq) so that only one extension +is shown. + +## addonStartup.json.lz4 +``` +{ + "app-profile": { + "addons": { + "dependencies": [], + "enabled": true, + "lastModifiedTime": 1592563110000, + "loader": null, + "path": "extension@tabliss.io.xpi", + "rootURI": "jar:file:///home/d/.mozilla/firefox/fm0hmz3f.second_gen4/extensions/extension@tabliss.io.xpi!/", + "runInSafeMode": false, + "signedState": 2, + "telemetryKey": "extension%40tabliss.io:2.0.3", + "version": "2.0.3" + } + } +} +``` +``` ++ mozlz4 addonStartup.json.lz4 ++ jq -c '.["app-profile"]["addons"]["extension@tabliss.io"] | keys' +["dependencies","enabled","lastModifiedTime","loader","path","rootURI","runInSafeMode","signedState","telemetryKey","version"] +``` + +## extension-preferences.json +``` +{ + "extension@tabliss.io": { + "permissions": [ + "internal:privateBrowsingAllowed" + ], + "origins": [] + } +} +``` +``` ++ jq -c '.["extension@tabliss.io"] | keys' extension-preferences.json +["origins","permissions"] +``` + +## extensions.json +``` +{ + "addons": [ + { + "id": "extension@tabliss.io", + "syncGUID": "{c95f9e0d-6450-4383-87e4-2244586de7f5}", + "version": "2.0.3", + "type": "extension", + "loader": null, + "updateURL": null, + "optionsURL": null, + "optionsType": null, + "optionsBrowserStyle": true, + "aboutURL": null, + "defaultLocale": { + "name": "Tabliss", + "description": "A beautiful New Tab page with many customisable backgrounds and widgets that does not require any permissions.", + "creator": null, + "developers": null, + "translators": null, + "contributors": null + }, + "visible": true, + "active": true, + "userDisabled": false, + "appDisabled": false, + "embedderDisabled": false, + "installDate": 1592563110000, + "updateDate": 1592563110000, + "applyBackgroundUpdates": 1, + "path": "/home/d/.mozilla/firefox/fm0hmz3f.second_gen4/extensions/extension@tabliss.io.xpi", + "skinnable": false, + "sourceURI": "https://addons.mozilla.org/firefox/downloads/file/3549950/tabliss_new_tab-2.0.3-fx.xpi?src=search", + "releaseNotesURI": null, + "softDisabled": false, + "foreignInstall": false, + "strictCompatibility": true, + "locales": [], + "targetApplications": [ + { + "id": "toolkit@mozilla.org", + "minVersion": "54.0", + "maxVersion": "*" + } + ], + "targetPlatforms": [], + "signedState": 2, + "seen": true, + "dependencies": [], + "incognito": "spanning", + "userPermissions": { + "permissions": [ + "storage" + ], + "origins": [] + }, + "optionalPermissions": { + "permissions": [], + "origins": [] + }, + "icons": { + "32": "icons/32.png", + "48": "icons/48.png", + "96": "icons/96.png", + "128": "icons/128.png" + }, + "iconURL": null, + "blocklistState": 0, + "blocklistURL": null, + "startupData": null, + "hidden": false, + "installTelemetryInfo": { + "source": "amo", + "sourceURL": "https://addons.mozilla.org/en-US/firefox/addon/tabliss/?src=search", + "method": "amWebAPI" + }, + "recommendationState": { + "validNotAfter": 1744746924000, + "validNotBefore": 1586958924000, + "states": [ + "recommended" + ] + }, + "rootURI": "jar:file:///home/d/.mozilla/firefox/fm0hmz3f.second_gen4/extensions/extension@tabliss.io.xpi!/", + "location": "app-profile" + } + ] +} +``` +``` ++ jq -c '.addons[] | select(.id == "extension@tabliss.io") | keys' extensions.json +["aboutURL","active","appDisabled","applyBackgroundUpdates","blocklistState","blocklistURL","defaultLocale","dependencies","embedderDisabled","foreignInstall","hidden","iconURL","icons","id","incognito","installDate","installTelemetryInfo","loader","locales","location","optionalPermissions","optionsBrowserStyle","optionsType","optionsURL","path","recommendationState","releaseNotesURI","rootURI","seen","signedState","skinnable","softDisabled","sourceURI","startupData","strictCompatibility","syncGUID","targetApplications","targetPlatforms","type","updateDate","updateURL","userDisabled","userPermissions","version","visible"] +``` + +## extension-settings.json +``` +{ + "url_overrides": { + "newTabURL": { + "precedenceList": { + "id": "extension@tabliss.io", + "installDate": 1592563110000, + "value": "moz-extension://5457f46b-efee-42b2-bea9-19bcb10f7618/index.html", + "enabled": true + } + } + } +} +``` +``` ++ jq -c keys extension-settings.json +["commands","default_search","homepageNotification","newTabNotification","prefs","tabHideNotification","url_overrides","version"] +``` +## prefs.js +``` +user_pref("extensions.webextensions.uuids", "\{\"extension@tabliss.io\":\"5457f46b-efee-42b2-bea9-19bcb10f7618\"\}"); +``` + +In total, I copy these prefs (...`.mstone` is assigned value "ignore" rather +than copied): + +``` +browser.newtab.extensionControlled +browser.newtab.privateAllowed +browser.reader.detectedFirstArticle +browser.rights.3.shown +browser.startup.homepage +browser.startup.homepage_override.buildID +browser.startup.homepage_override.mstone +browser.toolbarbuttons.introduced.pocket-button +datareporting.policy.dataSubmissionPolicyAcceptedVersion +datareporting.policy.dataSubmissionPolicyNotifiedTime +extensions.webextensions.uuids +``` + +It appears only the last value -- `extensions.webextensions.uuids` -- is +crucial. I know it's needed if you want the `browser.startup.homepage` to refer +to such a uuid (i.e., to use an extension as the homepage). If you don't include +it, mozilla will regenerate the uuids and any copied reference to the old uuid +(hiding anywhere) will fail. + +This only matters if you are trying to copy configuration that refers to that +UUID, otherwise Firefox just generates a new UUID for them. But since special +preferences used by (at least) uBlock0 and tabliss.io extensions require UUID in +`extension-settings.json`, you might need the configuration even if you don't +want actual configuration. -- cgit v1.2.3