Add custom Addons to Firefox (directly from https://addons.mozilla.org)

HI,
I’m trying to install new addons to my firefox home-manager config that aren’t available in the NUR. I found this repo with an implementation but can’t reproduce it in my current config.

This is my current flake.nix:

{
  description = "My dotfiles";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    nixos-hardware.url = "github:NixOS/nixos-hardware/master";
    sops-nix = {
      url = "github:Mic92/sops-nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    firefox-addons = {
      url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    stylix = {
      url = "github:danth/stylix";
      inputs.nixpkgs.follows = "nixpkgs";
    }; 
    arkenfox = {
      url = "github:dwarfmaster/arkenfox-nixos";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = inputs @ {
    self,
    nixpkgs,
    flake-utils,
    nixos-hardware,
    sops-nix,
    home-manager,
    firefox-addons,
    stylix,
    arkenfox,
      }: let
      system = "x86_64-linux";

      sharedModules = [
        sops-nix.nixosModules.sops
        stylix.nixosModules.stylix
        home-manager.nixosModules.home-manager
        # arkenfox.hmModules.default
        {
          home-manager = {
            useGlobalPkgs = true;
            useUserPackages = true;
            users.stew.imports = [ 
              ./nixos/home-manager/home.nix
            ];
            extraSpecialArgs = {inherit inputs;};
          };
        }
      ];
  in {
    nixosConfigurations.nixtop = nixpkgs.lib.nixosSystem {
      modules =
        [
          ./nixos/nixtop
        ]
        ++ sharedModules;
    };
  };
}

I copied the overlays.nix from the repo and added the addons.nix. My current adjusted flake.nix looks like this:

newflakes.nix

{
  description = "My dotfiles";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    nixos-hardware.url = "github:NixOS/nixos-hardware/master";
    sops-nix = {
      url = "github:Mic92/sops-nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    firefox-addons = {
      url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    stylix = {
      url = "github:danth/stylix";
      inputs.nixpkgs.follows = "nixpkgs";
    }; 
    arkenfox = {
      url = "github:dwarfmaster/arkenfox-nixos";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };
  outputs = inputs @ {
    self,
    nixpkgs,
    flake-utils,
    nixos-hardware,
    sops-nix,
    home-manager,
    firefox-addons,
    stylix,
    arkenfox,
      }: let
      system = "x86_64-linux";

      overlays = import ./lib/overlays.nix { inherit inputs system; };    

      pkgs = import inputs.nixpkgs {
        inherit overlays system;
        config.allowUnfree = true;
      };

      sharedModules = [
        sops-nix.nixosModules.sops
        stylix.nixosModules.stylix
        home-manager.nixosModules.home-manager
        # arkenfox.hmModules.default
        {
          home-manager = {
            useGlobalPkgs = true;
            useUserPackages = true;
            users.stew.imports = [ 
              ./nixos/home-manager/home.nix
            ];
            extraSpecialArgs = {inherit inputs overlays;};
          };
        }
      ];
  in {
    nixosConfigurations.nixtop = nixpkgs.lib.nixosSystem {
      modules =
        [
          ./nixos/nixtop
        ]
        ++ sharedModules;
    };
    out = { inherit pkgs overlays; };
  };
}

Now, I get the following error while building:

 error: attribute 'buildFirefoxXpiAddon' missing

       at /nix/store/6951a8rh9cc179a204g4mb5gx7zh6sfv-source/nixos/home-manager/browser.nix:641:52:

          640|
          641| 	   customAddons = pkgs.callPackage ./addons.nix {
             |                                                    ^
          642|         inherit lib;

But I added buildFirefoxXpiAddon as inputs:

browser.nix:

{
  config,
  pkgs,
  inputs,
  # arkenfox,
  lib,
  specialArgs,
  system,
  buildFirefoxXpiAddon,
  ...
}: {
...

      customAddons = pkgs.callPackage ./addons.nix {
        inherit lib;
        inherit (specialArgs) buildFirefoxXpiAddon;
      };

      extensions = with inputs.firefox-addons.packages."x86_64-linux"; [
        ublock-origin
      ] ++ (with customAddons; [ newAddon ]);

}

You added is as a function arg of browser.nix. You are however trying to take specialArgs.buildFirefoxXpiAddon there, and that attribute does not exist on specialArgs.

Just remove the (specialArgs).

You will then get a different error, because you never added that function to the module args (using specialArgs is a bit of a code smell anyway, if that attribute is on specialArgs it would also be a normal arg, so you don’t need to specify that, and likely should not in case the module system stops exposing that arg).

That user’s repository is a bit opaque since they use flake-schemas and some hand-written helpers that obfuscate what’s happening. It’s not a great repository to learn from, because in addition to having to know how NixOS works you also need to understand how those frameworks work to even begin to process what’s happening here. I’d recommend staying away from those in general, at least for NixOS/home-manager configurations, they offer basically no useful features for such.


To achieve getting this function into your module system to pass it to your addon function, you need to first add a new input to your flake to point to rycee’s flake:

inputs = {
  rycee-nurpkgs = {
    url = gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons;
    inputs.nixpkgs.follows = "nixpkgs";
  };
};

Since you already add inputs to your extraSpecialArgs, this will make inputs.rycee-nurpkgs available as an argument in your browser.nix (as well as all your other home-manager modules). You can then do this:

inherit (inputs.rycee-nurpkgs.lib) buildFirefoxXpiAddon;

To grab the builder and inherit it in the attribute set that you pass as an argument to the function you import from addons.nix. Assuming you made no other mistakes, that should then do what you wanted.

1 Like

Thanks for your reply and the detailed explanation.
Ironically enough, I wrote an answer in which something was still missing because the error was still there.
But I fixed it by copying the nix files over and saw the line that was missing ^^.

So this is my working setup:
flake.nix:

{
  description = "My dotfiles";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
    flake-utils.url = "github:numtide/flake-utils";
    nixos-hardware.url = "github:NixOS/nixos-hardware/master";
    sops-nix = {
      url = "github:Mic92/sops-nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    firefox-addons = {
      url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons";
      inputs.nixpkgs.follows = "nixpkgs";
    };
    stylix = {
      url = "github:danth/stylix";
      inputs.nixpkgs.follows = "nixpkgs";
    }; 
    arkenfox = {
      url = "github:dwarfmaster/arkenfox-nixos";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = inputs @ {
    self,
    nixpkgs,
    flake-utils,
    nixos-hardware,
    sops-nix,
    home-manager,
    firefox-addons,
    stylix,
    arkenfox,
      }: let
      system = "x86_64-linux";

      sharedModules = [
        sops-nix.nixosModules.sops
        stylix.nixosModules.stylix
        home-manager.nixosModules.home-manager
        # arkenfox.hmModules.default
        {
          home-manager = {
            useGlobalPkgs = true;
            useUserPackages = true;
            users.stew.imports = [ 
              ./nixos/home-manager/home.nix
            ];
            extraSpecialArgs = {inherit inputs;};
          };
        }
      ];
  in {
    nixosConfigurations.nixtop = nixpkgs.lib.nixosSystem {
      modules =
        [
          ./nixos/nixtop
        ]
        ++ sharedModules;
    };
  };
}

browser.nix (minimal):

{
  config,
  pkgs,
  inputs,
  lib,
  specialArgs,
  system,
  ...
}: let

  customAddons = pkgs.callPackage ./addons.nix {
    inherit lib;
    inherit (inputs.firefox-addons.lib."x86_64-linux") buildFirefoxXpiAddon;
  };

in 
{
  programs.firefox = {
    enable = true;

    profiles."defaultUser" = {
      id = 0;

      extensions = with inputs.firefox-addons.packages."x86_64-linux"; [
        ublock-origin
        darkreader
      ] ++ (with customAddons; [ old-github-feed ]);
    };
  };
}

addons.nix:

{ buildFirefoxXpiAddon, lib }:

{
  old-github-feed = buildFirefoxXpiAddon rec {
    pname = "return-old-github-feed";
    version = "1.0.1";
    addonId = "{9dfcb52a-5322-4d42-9924-9d3b8871ad90}";
    url = "https://addons.mozilla.org/firefox/downloads/file/4166201/${pname}-${version}.xpi";
    sha256 = "sha256-age3Nj2n4X3Zg1bTElChOpgDDGCQd4nOqHebW8zNsBQ=";
    meta = with lib;
      {
        homepage = "https://github.com/Siriusmart/return-github-feed";
        description = "This extension replaces the new and ugly GitHub feed with the real one from github.com/dashboard-feed";
        license = licenses.gpl3;
        platforms = platforms.all;
      };
  };
}
1 Like

Additionally, here is my extended browser.nix.
browser.nix (with useful policies, if you are interested):

{
  config,
  pkgs,
  inputs,
  lib,
  specialArgs,
  system,
  ...
}: let

  customAddons = pkgs.callPackage ./addons.nix {
    inherit lib;
    inherit (inputs.firefox-addons.lib."x86_64-linux") buildFirefoxXpiAddon;
  };

in 
{
  programs.firefox = {
    enable = true;
  
    policies = {
     DisableFormHistory = true;
     DisableFirefoxAccounts = true;
     NetworkPrediction = false;
     # CaptivePortal = false;

      UserMessaging = {
        WhatsNew = false;
        UrlbarInterventions = false;
        FeatureRecommendations = false;
        MoreFromMozilla = false;
        SkipOnboarding = true;
      };

      DisableFirefoxStudies = true;
      DisableTelemetry = true;
      DisablePocket = true;
      EnableTrackingProtection = {
        Value = true;
        Locked = true;
        Cryptomining = true;
        Fingerprinting = true;
      };
      HardwareAcceleration = true;
      AutofillAddressEnabled = false;
      AutofillCreditCardEnabled = false;
      # WindowsSSO = false;

      OfferToSaveLogins = false;
      # OfferToSaveLoginsDefault = false;
      PasswordManagerEnabled = false;
      FirefoxHome = {
          Search = true;
          Pocket = false;
          Snippets = false;
          TopSites = false;
          Highlights = false;
      };
 
      "3rdparty" = {
        Extensions = {
          "uBlock0@raymondhill.net" = {
            "sidebarPosition" = 1;
            "sidebarPosition:locked" = false;

            adminSettings = {
              "selectedFilterLists" = [
                "ublock-privacy"
                "ublock-badware"
                "ublock-filters"
                "ublock-quick-fixes"
                "ublock-unbreak"
                "user-filters"

                "easylist"
                "easyprivacy"
                "urlhaus-1"
                "plowe-0"
                
                "easylist-newsletters"

                "fanboy-cookiemonster"
                "ublock-cookies-easylist"

              ];
            };
            userSettings = [
              ["advancedUserEnabled" "true"]
              ["ignoreGeneticCosmeticFilters" "true"]
              ["popupPanelSections" "31"]
            ];
          };
        };
      };
    };

    profiles."defaultUser" = {
      id = 0;

      extensions = with inputs.firefox-addons.packages."x86_64-linux"; [
        ublock-origin
        darkreader
      ] ++ (with customAddons; [ old-github-feed ]);
    };
  };
}

Do you know useful repos for the average user to learn from?

None off the top of my head. User repos will always be a shot in the dark, sadly the frameworks are spreading a lot these days - I think it’s users copying from each other without really knowing why they are used in the first place.