complete-computing-environment/firefox_nix.org

222 lines
11 KiB
Org Mode

:PROPERTIES:
:ID: cce/firefox_nix
:ROAM_ALIASES: "Firefox on Nix" "Firefox Nix"
:END:
#+TITLE: Managing Firefox with Nix home-manager
#+ARCOLOGY_KEY: cce/firefox-nix
#+AUTO_TANGLE: t
#+filetags: :CCE:
#+CCE_PRIORITY: 50
#+ARROYO_HOME_MODULE: hm/firefox.nix
#+ARROYO_SYSTEM_ROLE: endpoint
#+ARCOLOGY_ALLOW_CRAWL: t
This [[id:09779ac0-4d5f-40db-a340-49595c717e03][noweb]] document constructs a customized [[id:cce/a_basic_firefox_installation][Firefox]] installation:
- I deploy firefox with settings in both =about:config= below and enterprise policies [[id:firefox-with-policy][further down]].
- =userChrome.css= and =userContent.css= loaded from [[id:cce/firefox_user_chrome][A Custom Firefox User Chrome]]
- *this sucked and fought with firefox sync, didn't hit the security considerations I was hoping for*: Extensions are defined [[id:firefox-nix-extensions][below]] and bundled in to my Nix deployments
#+begin_src nix :tangle ~/arroyo-nix/hm/firefox.nix :noweb yes -r
{ config, pkgs, ... }:
{
xdg.mimeApps.enable = true;
xdg.mimeApps.defaultApplications = {
"x-scheme-handler/http" = ["firefox.desktop"];
"x-scheme-handler/https" = ["firefox.desktop"];
};
home.sessionVariables = {
GTK_USE_PORTAL = 1; # (ref:gtk-use-portal)
MOZ_ENABLE_WAYLAND = 1;
};
programs.firefox = {
enable = true;
package =
<<myFirefox>>
;
profiles.default = {
name = "default";
isDefault = true;
settings = {
"svg.context-properties.content.enabled" = true; # (ref:svgContextProperties)
"privacy.trackingprotection.enabled" = true;
"privacy.donottrackheader.enabled" = true;
"privacy.globalprivacycontrol.enabled" = true;
"privacy.globalprivacycontrol.functionality_enabled" = true;
"reader.color_scheme" = "dark";
"mousewheel.default.delta_multiplier_x" = 1000; # horizontal scroll multiplier
# "layout.css.devPixelsPerPx" = # (ref:hidpi)
# "1.5";
# (if config.hardware.video.hidpi.enable == true then
# "1.5"
# else
# "1.0");
"browser.aboutConfig.showWarning" = false;
"browser.sessionstore.warnOnQuit" = true;
"browser.newtabpage.activity-stream.showSponsored" = false;
"browser.newtabpage.activity-stream.showSponsoredTopSites" = false;
"toolkit.legacyUserProfileCustomizations.stylesheets" = true; # for userchrome and usercontent
"layout.css.prefers-color-scheme.content-override" = 2; # (ref:content-override)
};
userChrome = builtins.readFile ../files/userChrome.css;
userContent = builtins.readFile ../files/userContent.css;
};
};
}
#+end_src
- [[(gtk-use-portal)]] instructs Firefox to use the [[https://flatpak.github.io/xdg-desktop-portal/][XDG Desktop Portal]], and [[id:cce/kde_is_a_base_for_my_emacs_desktop][kde-base]] includes a Portal allowing Firefox to use e.g. KDE's file select dialogs. Very nice.
- [[(svgContextProperties)]] is used by the [[https://addons.mozilla.org/en-US/firefox/addon/simple-tab-groups/][simple tab groups]] addon
- [[(content-override)]] makes follow GTK dark theme -- enumerates values in [[https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/browserSettings/overrideContentColorScheme][overrideContentColorScheme]] (see also [[https://github.com/mozilla/gecko-dev/blob/master/modules/libpref/init/StaticPrefList.yaml#L7747-L7753][StaticPrefList.yaml]] h/t Snow
- I would love if [[(hidpi)]] could be set far up in [[id:cce/my_nixos_configuration][My NixOS configuration]] per-host ...
* NEXT it would be great if [[(hidpi)]] could use =config.hardware.video.hidpi.enable= in [[id:cce/my_nixos_configuration][My NixOS configuration]].
* Disabling Policies with wrapped Firefox
:PROPERTIES:
:ID: firefox-with-policy
:END:
per [[https://github.com/NixOS/nixpkgs/blob/master/doc/builders/packages/firefox.section.md][the docs]], we can distribute a Firefox with enterprise policies enabled; you can enable extensions here, but I enable them in my user profile instead up above.
#+NAME: myFirefox
#+begin_src nix
pkgs.wrapFirefox pkgs.firefox-unwrapped {
# nixExtensions = pkgs.callPackage ./firefox {}; # (ref:extensionsImport)
nativeMessagingHosts = [
pkgs.plasma5Packages.plasma-browser-integration
pkgs.browserpass
pkgs.tridactyl-native
];
extraPolicies = {
DisableFirefoxStudies = true;
DisablePocket = true;
DisableTelemetry = true;
FirefoxHome = {
Pocket = false;
Snippets = false;
};
UserMessaging = {
ExtensionRecommendations = false;
SkipOnboarding = true;
};
OfferToSaveLoginsDefault = false;
# Handlers can be set here for org-protocol
# https://github.com/mozilla/policy-templates/blob/master/README.md#Handlers
};
}
#+end_src
* [[id:cce/firefox_user_chrome][A Custom Firefox User Chrome]] make sure to tangle these when they're changed!
#+begin_src emacs-lisp
(org-babel-tangle-file "./firefox_user_chrome.org")
#+end_src
* Theoretically-Safe Firefox Extensions with [[id:c75d20e6-8888-4c5a-ac97-5997e2f1c711][Nix]]
:PROPERTIES:
:ID: firefox-nix-extensions
:END:
: I have this disabled right now ... it's likely easier to just use Firefox Sync for this since the XPIs are just being downloaded
So, Home Manager has the ability to manager a [[id:cce/a_basic_firefox_installation][Firefox]] profile and in doing so, it can side-load extensions which are compiled and managed by Nix. Very nice.
It's recommended in the =home-configuration.nix= manpage to pull firefox addons out of [[roam:Nix User Repositories]] (external: [[https://github.com/nix-community/NUR][NUR]]) but i'm not sure i'm comfortable running NUR as an integrated part of my system, I only want to use the minimal set of it. So my understanding of NUR's support for Firefox addons looks like this: [[https://github.com/nix-community/nur-combined/blob/master/repos/rycee/pkgs/firefox-addons/addons.json][addons.json]] provide an accessible format for machines to generate a [[https://github.com/nix-community/nur-combined/blob/master/repos/rycee/pkgs/firefox-addons/generated-firefox-addons.nix][generated-firefox-addons.nix]] with a script like this =generate-firefox-addons.sh= which also makes a =nixlib/firefox/default.nix= for importing at [[(extensionsImport)]].
#+NAME: generate-firefox-addons
#+begin_src sh :tangle ~/arroyo-nix/firefox/generate-firefox-addons.sh :mkdirp yes :shebang #!/usr/bin/env bash
nix run -f "https://github.com/nix-community/NUR/archive/master.tar.gz" repos.rycee.firefox-addons-generator \
--arg pkgs 'import <nixpkgs> {}' \
-c nixpkgs-firefox-addons addons.json ./generated.nix
#+end_src
Regularly running [[shell:pushd nixlib/firefox && ./generate-firefox-addons.sh &]] is "praxis".
=default.nix= looks like:
#+begin_src nix :tangle ~/arroyo-nix/firefox/default.nix
# Derived from: https://github.com/nix-community/nur-combined/blob/master/repos/ijohanne/pkgs/firefox-plugins/default.nix
{ pkgs ? import <nixpkgs> {} }:
let
buildFirefoxXpiAddon = { pname, url, sha256, meta, ... }: let
newMeta = if meta ? license
then meta
else meta // { license = pkgs.lib.licenses.unfree; };
in
(pkgs.fetchFirefoxAddon { inherit url sha256; name = pname; }) // { meta = newMeta;} ;
generated = pkgs.callPackage ./generated.nix { inherit buildFirefoxXpiAddon; };
in
pkgs.lib.mapAttrsToList
(name: value: value)
(pkgs.lib.filterAttrs # (ref:firefox-filterAttrs)
(name: value: (name != "override") &&
(name != "overrideDerivation") &&
(name != "recurseForDerivations"))
(generated))
#+end_src
The most complicated part of this is the map and filter functions in [[(firefox-filterAttrs)]] above: =programs.firefox.extensions= wants a list, the generated =addons= module returns a set with some overrides attached to it. I just want this to rip 'em out and map it to a list.
And here's an =addons.json= specifying some of my favorite slugs:
#+begin_src json :tangle ~/arroyo-nix/firefox/addons.json :comments none
[
{"slug": "awesome-rss"},
{"slug": "better-timing-for-no-race"},
{"slug": "browserpass-ce"},
{"slug": "clearurls"},
{"slug": "darkreader"},
{"slug": "decentraleyes"},
{"slug": "duckduckgo-for-firefox"},
{"slug": "facebook-container"},
{"slug": "https-everywhere"},
{"slug": "laboratory-by-mozilla"},
{"slug": "leechblock-ng"},
{"slug": "multi-account-containers"},
{"slug": "plasma-integration"},
{"slug": "privacy-badger17"},
{"slug": "simple-tab-groups"},
{"slug": "smart-amazon-smile"},
{"slug": "styl-us"},
{"slug": "tab-unload-for-tree-style-tab"},
{"slug": "tampermonkey"},
{"slug": "tree-style-tab"},
{"slug": "twemex-sidebar-for-twitter"},
{"slug": "ublock-origin"},
{"slug": "wallabagger"},
{"slug": "web-scrobbler"},
{"slug": "yet-another-hints-extension"},
{"slug": "youtube-feeds"}
]
#+end_src
This still fetches and repackages the XPIs! I'd like to build these more and more from source ... but they won't auto-update to something that'll super-own me for now. See [[id:untenable-position-of-powerful-user-agents][An Undeveloped Thought on Web Extensions and the untenable position of powerful user agents]] below...
** WAITING Add changelogs or git commits for these extensions to [[id:cce/universal_aggregator][Universal Aggregator]] [[id:e51ec96c-ffe1-4013-a5f2-be35abd84ae5][Software Release Feeds]]
- State "WAITING" from "NEXT" [2021-05-11 Tue 12:05]
** An [[id:09fa0674-ad3b-43c5-8d7c-6b532346a772][Undeveloped Thought]] on Web Extensions and the untenable position of powerful user agents
:PROPERTIES:
:ID: untenable-position-of-powerful-user-agents
:END:
With regards to the security model of web extensions:
I really don't think the browser extension model is great, but I think user-agents are powerful and powerful user agents are good. There has to be a balance. It's clear that the cloud-services-as-extension model like Grammarly or even AdBlock is ripe for abuse, or change of terms, and the nature of the ecosystem is that when open source developers burn out they can turn around and sell their module to a firm with no trust, and plenty of things to scrutinize.
When subscribing to the changelogs, I see limited authorship information as well as commit patterns: if the module suddenly changes authorship or the commits change from being a very verbose style to only dumping version updates, I need to ask why before it's too late.
The NUR stuff is all based around some automation in that repo which is just managed ad-hoc by a bunch of folks as their personal playgrounds, but I think I can co-opt that and define my own extension set using the same pattern. If I developed that way, this would just be a readme in a forked NUR repo, but here we are, I want to speak through the code, sorry.
By only managing and installing the core open source extensions I rely on, maybe I can keep myself from getting [[roam:Super Owned]] by some extension getting sold to some amoral surveillance apparatus, while managing the risk of security issues injected by the relatively lax =NUR= security model. The extensions I use largely don't interact with cloud services or even update very often themselves, and it's as easy to track the commit feeds or changelog for them in my [[id:26c9e4fd-4501-4b8b-95ce-a2a5230d7c1e][News feed pipeline]].