summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2020-06-21 21:29:04 -0400
committerAndrew Cady <d@jerkface.net>2020-06-21 21:29:04 -0400
commit72ffbda9c4f4d9a7a9f3b34c0a965611d7222a84 (patch)
tree5bb6c3f5b2e0dcdcc9d1f93a4933ff89b0e6dbdc
parentd1152d842abe6927fec404a46d10eacba98e80db (diff)
add blog.md
-rw-r--r--firefox-sideloader/blog.md270
1 files changed, 270 insertions, 0 deletions
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 @@
1# Firefox has deprecated "side-loading" of extensions
2
3From [the announcement](https://blog.mozilla.org/addons/2020/03/10/support-for-extension-sideloading-has-ended/):
4
5> Today marks the release of Firefox 74 and as we announced last fall,
6> developers will no longer be able to install extensions without
7> the user taking an action. This installation method was typically
8> done through application installers, and is commonly referred to as
9> “sideloading.”
10>
11> If you are the developer of an extension that installs itself via
12> sideloading, please make sure that your users can install the
13> extension from your own website or from addons.mozilla.org (AMO).
14
15Of course, it is still possible to side-load. The browser itself is
16installing the extension, and the browser isn't even closed source. It
17can't hide what it's doing, just obfuscate and write annoying blog posts
18about how taking away features is making users safer.
19
20I spent some time yesterday figuring out how to side-load extensions
21and writing code to do this for my own purposes. I got a script working
22that gives an automated extension install into a new profile based on
23copying out of some other profile where the extension had been installed
24by firefox interactively.
25
26What I'm doing is very coarse -- mostly just copying entire files, but
27editing the paths within them to refer to the new extension directory
28instead of the old one.
29
30This works for me since I want to copy my entire list of extensions,
31but you want to surgically install just one extension. I didn't go
32that far with my code but I think I can tell you how to start the
33surgery based on what I found. You just need to edit some JSON. (BTW
34[jq](https://github.com/stedolan/jq) is great.)
35
36To get an extension running in a firefox profile, you need to edit the
37following files in the profile dir:
38
39```
40./extension-settings.json
41./extension-preferences.json
42./extensions.json
43./addonStartup.json.lz4
44./prefs.js
45```
46
47* `<profile_dir>/extensions/`
48
49 Put your `*.xpi` here.
50
51* `extensions.json`
52
53 Each extension needs a long entry in the `addons` array
54
55* `extension-settings.json`
56
57 Used to give extensions some special privileges, refers to extension by id
58 (the `id` field in `extensions.json`)
59
60* `extension-preferences.json`
61
62 Used to give extensions privilege to run in private tab, refers to extensions
63 by id
64
65* `addonStartup.json.lz4`
66
67 Contains one `addons` object within each of the four labels "app-builtin",
68 "app-profile", "app-system-defaults", "app-system-share".
69
70 I use https://github.com/jusw85/mozlz4 to decompress and compress this file.
71
72* prefs.js
73
74 Needed to set `extensions.webextensions.uuids` or to make an extension
75 run as the homepage or new tab page without user interaction. I also
76 use it to bypass confirmation/warning popups, mozilla upgrade notice,
77 etc.
78
79Here is an example of the JSON for each file for one extension. This is
80generated by script and the values are edited (by jq) so that only one extension
81is shown.
82
83## addonStartup.json.lz4
84```
85{
86 "app-profile": {
87 "addons": {
88 "dependencies": [],
89 "enabled": true,
90 "lastModifiedTime": 1592563110000,
91 "loader": null,
92 "path": "extension@tabliss.io.xpi",
93 "rootURI": "jar:file:///home/d/.mozilla/firefox/fm0hmz3f.second_gen4/extensions/extension@tabliss.io.xpi!/",
94 "runInSafeMode": false,
95 "signedState": 2,
96 "telemetryKey": "extension%40tabliss.io:2.0.3",
97 "version": "2.0.3"
98 }
99 }
100}
101```
102```
103+ mozlz4 addonStartup.json.lz4
104+ jq -c '.["app-profile"]["addons"]["extension@tabliss.io"] | keys'
105["dependencies","enabled","lastModifiedTime","loader","path","rootURI","runInSafeMode","signedState","telemetryKey","version"]
106```
107
108## extension-preferences.json
109```
110{
111 "extension@tabliss.io": {
112 "permissions": [
113 "internal:privateBrowsingAllowed"
114 ],
115 "origins": []
116 }
117}
118```
119```
120+ jq -c '.["extension@tabliss.io"] | keys' extension-preferences.json
121["origins","permissions"]
122```
123
124## extensions.json
125```
126{
127 "addons": [
128 {
129 "id": "extension@tabliss.io",
130 "syncGUID": "{c95f9e0d-6450-4383-87e4-2244586de7f5}",
131 "version": "2.0.3",
132 "type": "extension",
133 "loader": null,
134 "updateURL": null,
135 "optionsURL": null,
136 "optionsType": null,
137 "optionsBrowserStyle": true,
138 "aboutURL": null,
139 "defaultLocale": {
140 "name": "Tabliss",
141 "description": "A beautiful New Tab page with many customisable backgrounds and widgets that does not require any permissions.",
142 "creator": null,
143 "developers": null,
144 "translators": null,
145 "contributors": null
146 },
147 "visible": true,
148 "active": true,
149 "userDisabled": false,
150 "appDisabled": false,
151 "embedderDisabled": false,
152 "installDate": 1592563110000,
153 "updateDate": 1592563110000,
154 "applyBackgroundUpdates": 1,
155 "path": "/home/d/.mozilla/firefox/fm0hmz3f.second_gen4/extensions/extension@tabliss.io.xpi",
156 "skinnable": false,
157 "sourceURI": "https://addons.mozilla.org/firefox/downloads/file/3549950/tabliss_new_tab-2.0.3-fx.xpi?src=search",
158 "releaseNotesURI": null,
159 "softDisabled": false,
160 "foreignInstall": false,
161 "strictCompatibility": true,
162 "locales": [],
163 "targetApplications": [
164 {
165 "id": "toolkit@mozilla.org",
166 "minVersion": "54.0",
167 "maxVersion": "*"
168 }
169 ],
170 "targetPlatforms": [],
171 "signedState": 2,
172 "seen": true,
173 "dependencies": [],
174 "incognito": "spanning",
175 "userPermissions": {
176 "permissions": [
177 "storage"
178 ],
179 "origins": []
180 },
181 "optionalPermissions": {
182 "permissions": [],
183 "origins": []
184 },
185 "icons": {
186 "32": "icons/32.png",
187 "48": "icons/48.png",
188 "96": "icons/96.png",
189 "128": "icons/128.png"
190 },
191 "iconURL": null,
192 "blocklistState": 0,
193 "blocklistURL": null,
194 "startupData": null,
195 "hidden": false,
196 "installTelemetryInfo": {
197 "source": "amo",
198 "sourceURL": "https://addons.mozilla.org/en-US/firefox/addon/tabliss/?src=search",
199 "method": "amWebAPI"
200 },
201 "recommendationState": {
202 "validNotAfter": 1744746924000,
203 "validNotBefore": 1586958924000,
204 "states": [
205 "recommended"
206 ]
207 },
208 "rootURI": "jar:file:///home/d/.mozilla/firefox/fm0hmz3f.second_gen4/extensions/extension@tabliss.io.xpi!/",
209 "location": "app-profile"
210 }
211 ]
212}
213```
214```
215+ jq -c '.addons[] | select(.id == "extension@tabliss.io") | keys' extensions.json
216["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"]
217```
218
219## extension-settings.json
220```
221{
222 "url_overrides": {
223 "newTabURL": {
224 "precedenceList": {
225 "id": "extension@tabliss.io",
226 "installDate": 1592563110000,
227 "value": "moz-extension://5457f46b-efee-42b2-bea9-19bcb10f7618/index.html",
228 "enabled": true
229 }
230 }
231 }
232}
233```
234```
235+ jq -c keys extension-settings.json
236["commands","default_search","homepageNotification","newTabNotification","prefs","tabHideNotification","url_overrides","version"]
237```
238## prefs.js
239```
240user_pref("extensions.webextensions.uuids", "\{\"extension@tabliss.io\":\"5457f46b-efee-42b2-bea9-19bcb10f7618\"\}");
241```
242
243In total, I copy these prefs (...`.mstone` is assigned value "ignore" rather
244than copied):
245
246```
247browser.newtab.extensionControlled
248browser.newtab.privateAllowed
249browser.reader.detectedFirstArticle
250browser.rights.3.shown
251browser.startup.homepage
252browser.startup.homepage_override.buildID
253browser.startup.homepage_override.mstone
254browser.toolbarbuttons.introduced.pocket-button
255datareporting.policy.dataSubmissionPolicyAcceptedVersion
256datareporting.policy.dataSubmissionPolicyNotifiedTime
257extensions.webextensions.uuids
258```
259
260It appears only the last value -- `extensions.webextensions.uuids` -- is
261crucial. I know it's needed if you want the `browser.startup.homepage` to refer
262to such a uuid (i.e., to use an extension as the homepage). If you don't include
263it, mozilla will regenerate the uuids and any copied reference to the old uuid
264(hiding anywhere) will fail.
265
266This only matters if you are trying to copy configuration that refers to that
267UUID, otherwise Firefox just generates a new UUID for them. But since special
268preferences used by (at least) uBlock0 and tabliss.io extensions require UUID in
269`extension-settings.json`, you might need the configuration even if you don't
270want actual configuration.