diff --git a/doc/builders/packages/firefox.section.md b/doc/builders/packages/firefox.section.md
new file mode 100644
index 000000000000..2f89da2d4595
--- /dev/null
+++ b/doc/builders/packages/firefox.section.md
@@ -0,0 +1,40 @@
+# Firefox
+
+## Build wrapped Firefox with extensions and policies
+
+The `wrapFirefox` function allows to pass policies, preferences and extension that are available to firefox. With the help of `fetchFirefoxAddon` this allows build a firefox version that already comes with addons pre-installed:
+
+```nix
+{
+ myFirefox = wrapFirefox firefox-unwrapped {
+ extraExtensions = [
+ (fetchFirefoxAddon {
+ name = "ublock";
+ url = "https://addons.mozilla.org/firefox/downloads/file/3679754/ublock_origin-1.31.0-an+fx.xpi";
+ sha256 = "1h768ljlh3pi23l27qp961v1hd0nbj2vasgy11bmcrlqp40zgvnr";
+ })
+ ];
+
+ extraPolicies = {
+ CaptivePortal = false;
+ DisableFirefoxStudies = true;
+ DisablePocket = true;
+ DisableTelemetry = true;
+ DisableFirefoxAccounts = true;
+ FirefoxHome = {
+ Pocket = false;
+ Snippets = false;
+ };
+ UserMessaging = {
+ ExtensionRecommendations = false;
+ SkipOnboarding = true;
+ };
+ };
+
+ extraPrefs = ''
+ // Show more ssl cert infos
+ lockPref("security.identityblock.show_extended_validation", true);
+ '';
+ };
+}
+```
diff --git a/doc/builders/packages/index.xml b/doc/builders/packages/index.xml
index baf9b8db01be..c2e7ef9bf61c 100644
--- a/doc/builders/packages/index.xml
+++ b/doc/builders/packages/index.xml
@@ -10,6 +10,7 @@
+
diff --git a/pkgs/applications/networking/browsers/firefox/wrapper.nix b/pkgs/applications/networking/browsers/firefox/wrapper.nix
index cc6cc72e27be..f9b7f2bb8a2e 100644
--- a/pkgs/applications/networking/browsers/firefox/wrapper.nix
+++ b/pkgs/applications/networking/browsers/firefox/wrapper.nix
@@ -1,4 +1,5 @@
{ stdenv, lib, makeDesktopItem, makeWrapper, lndir, config
+, replace, fetchurl, zip, unzip, jq
## various stuff that can be plugged in
, flashplayer, hal-flash
@@ -31,6 +32,16 @@ let
, forceWayland ? false
, useGlvnd ? true
, cfg ? config.${browserName} or {}
+
+ ## Following options are needed for extra prefs & policies
+ # For more information about anti tracking (german website)
+ # visit https://wiki.kairaven.de/open/app/firefox
+ , extraPrefs ? ""
+ # For more information about policies visit
+ # https://github.com/mozilla/policy-templates#enterprisepoliciesenabled
+ , extraPolicies ? {}
+ , firefoxLibName ? "firefox" # Important for tor package or the like
+ , extraExtensions ? [ ]
}:
assert forceWayland -> (browser ? gtk3); # Can only use the wayland backend if gtk3 is being used
@@ -81,6 +92,61 @@ let
++ pkcs11Modules;
gtk_modules = [ libcanberra-gtk2 ];
+ #########################
+ # #
+ # EXTRA PREF CHANGES #
+ # #
+ #########################
+ policiesJson = builtins.toFile "policies.json"
+ (builtins.toJSON enterprisePolicies);
+
+ extensions = builtins.map (a:
+ if ! (builtins.hasAttr "extid" a) then
+ throw "extraExtensions has an invalid entry. Missing extid attribute. Please use fetchfirefoxaddon"
+ else
+ a
+ ) extraExtensions;
+
+ enterprisePolicies =
+ {
+ policies = {
+ DisableAppUpdate = true;
+ } //
+ {
+ ExtensionSettings = {
+ "*" = {
+ blocked_install_message = "You can't have manual extension mixed with nix extensions";
+ installation_mode = "blocked";
+ };
+
+ } // lib.foldr (e: ret:
+ ret // {
+ "${e.extid}" = {
+ installation_mode = "allowed";
+ };
+ }
+ ) {} extensions;
+ }
+ // extraPolicies;
+ };
+
+ mozillaCfg = builtins.toFile "mozilla.cfg" ''
+// First line must be a comment
+
+ // Disables addon signature checking
+ // to be able to install addons that do not have an extid
+ // Security is maintained because only user whitelisted addons
+ // with a checksum can be installed
+ lockPref("xpinstall.signatures.required", false);
+ ${extraPrefs}
+ '';
+
+ #############################
+ # #
+ # END EXTRA PREF CHANGES #
+ # #
+ #############################
+
in stdenv.mkDerivation {
inherit pname version;
@@ -106,6 +172,7 @@ let
nativeBuildInputs = [ makeWrapper lndir ];
buildInputs = lib.optional (browser ? gtk3) browser.gtk3;
+
buildCommand = lib.optionalString stdenv.isDarwin ''
mkdir -p $out/Applications
cp -R --no-preserve=mode,ownership ${browser}/Applications/${browserName}.app $out/Applications
@@ -117,7 +184,66 @@ let
exit 1
fi
- makeWrapper "$(readlink -v --canonicalize-existing "${browser}${browser.execdir or "/bin"}/${browserName}")" \
+ #########################
+ # #
+ # EXTRA PREF CHANGES #
+ # #
+ #########################
+ # Link the runtime. The executable itself has to be copied,
+ # because it will resolve paths relative to its true location.
+ # Any symbolic links have to be replicated as well.
+ cd "${browser}"
+ find . -type d -exec mkdir -p "$out"/{} \;
+
+ find . -type f \( -not -name "${browserName}" \) -exec ln -sT "${browser}"/{} "$out"/{} \;
+
+ find . -type f -name "${browserName}" -print0 | while read -d $'\0' f; do
+ cp -P --no-preserve=mode,ownership "${browser}/$f" "$out/$f"
+ chmod a+rwx "$out/$f"
+ done
+
+ # fix links and absolute references
+ cd "${browser}"
+
+ find . -type l -print0 | while read -d $'\0' l; do
+ target="$(readlink "$l" | ${replace}/bin/replace-literal -es -- "${browser}" "$out")"
+ ln -sfT "$target" "$out/$l"
+ done
+
+ # This will not patch binaries, only "text" files.
+ # Its there for the wrapper mostly.
+ cd "$out"
+ ${replace}/bin/replace-literal -esfR -- "${browser}" "$out"
+
+ # create the wrapper
+
+ executablePrefix="$out${browser.execdir or "/bin"}"
+ executablePath="$executablePrefix/${browserName}"
+
+ if [ ! -x "$executablePath" ]
+ then
+ echo "cannot find executable file \`${browser}${browser.execdir or "/bin"}/${browserName}'"
+ exit 1
+ fi
+
+ if [ ! -L "$executablePath" ]
+ then
+ # Careful here, the file at executablePath may already be
+ # a wrapper. That is why we postfix it with -old instead
+ # of -wrapped.
+ oldExe="$executablePrefix"/".${browserName}"-old
+ mv "$executablePath" "$oldExe"
+ else
+ oldExe="$(readlink -v --canonicalize-existing "$executablePath")"
+ fi
+
+ if [ ! -x "${browser}${browser.execdir or "/bin"}/${browserName}" ]
+ then
+ echo "cannot find executable file \`${browser}${browser.execdir or "/bin"}/${browserName}'"
+ exit 1
+ fi
+
+ makeWrapper "$oldExe" \
"$out${browser.execdir or "/bin"}/${browserName}${nameSuffix}" \
--suffix-each MOZ_PLUGIN_PATH ':' "$plugins" \
--suffix LD_LIBRARY_PATH ':' "$libs" \
@@ -137,6 +263,11 @@ let
--suffix XDG_DATA_DIRS : '${gnome3.adwaita-icon-theme}/share'
''
}
+ #############################
+ # #
+ # END EXTRA PREF CHANGES #
+ # #
+ #############################
if [ -e "${browser}/share/icons" ]; then
mkdir -p "$out/share"
@@ -166,6 +297,43 @@ let
# For manpages, in case the program supplies them
mkdir -p $out/nix-support
echo ${browser} > $out/nix-support/propagated-user-env-packages
+
+
+ #########################
+ # #
+ # EXTRA PREF CHANGES #
+ # #
+ #########################
+ # user customization
+ mkdir -p $out/lib/${firefoxLibName}
+
+ # creating policies.json
+ mkdir -p "$out/lib/${firefoxLibName}/distribution"
+
+ POL_PATH="$out/lib/${firefoxLibName}/distribution/policies.json"
+ rm -f "$POL_PATH"
+ cat ${policiesJson} >> "$POL_PATH"
+
+ # preparing for autoconfig
+ mkdir -p "$out/lib/${firefoxLibName}/defaults/pref"
+
+ cat > "$out/lib/${firefoxLibName}/defaults/pref/autoconfig.js" < "$out/lib/${firefoxLibName}/mozilla.cfg" < ${mozillaCfg}
+
+ mkdir -p $out/lib/${firefoxLibName}/distribution/extensions
+
+ for i in ${toString extensions}; do
+ ln -s -t $out/lib/${firefoxLibName}/distribution/extensions $i/*
+ done
+ #############################
+ # #
+ # END EXTRA PREF CHANGES #
+ # #
+ #############################
'';
preferLocalBuild = true;
diff --git a/pkgs/build-support/fetchfirefoxaddon/default.nix b/pkgs/build-support/fetchfirefoxaddon/default.nix
new file mode 100644
index 000000000000..3426743b2cf1
--- /dev/null
+++ b/pkgs/build-support/fetchfirefoxaddon/default.nix
@@ -0,0 +1,37 @@
+{stdenv, lib, coreutils, unzip, jq, zip, fetchurl,writeScript, ...}:
+{ name
+, url
+, md5 ? ""
+, sha1 ? ""
+, sha256 ? ""
+, sha512 ? ""
+}:
+stdenv.mkDerivation rec {
+
+ inherit name;
+ extid = "${src.outputHash}@${name}";
+ passthru = {
+ exitd=extid;
+ };
+
+ builder = writeScript "xpibuilder" ''
+ source $stdenv/setup
+
+ header "firefox addon $name into $out"
+
+ UUID="${extid}"
+ mkdir -p "$out/$UUID"
+ unzip -q ${src} -d "$out/$UUID"
+ NEW_MANIFEST=$(jq '. + {"applications": { "gecko": { "id": "${extid}" }}, "browser_specific_settings":{"gecko":{"id": "${extid}"}}}' "$out/$UUID/manifest.json")
+ echo "$NEW_MANIFEST" > "$out/$UUID/manifest.json"
+ cd "$out/$UUID"
+ zip -r -q -FS "$out/$UUID.xpi" *
+ rm -r "$out/$UUID"
+ '';
+ src = fetchurl {
+ url = url;
+ inherit md5 sha1 sha256 sha512;
+ };
+ nativeBuildInputs = [ coreutils unzip zip jq ];
+}
+
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 81953358bc59..a3c3330ae376 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -365,6 +365,8 @@ in
fetchhg = callPackage ../build-support/fetchhg { };
+ fetchFirefoxAddon = callPackage ../build-support/fetchfirefoxaddon {};
+
# `fetchurl' downloads a file from the network.
fetchurl = if stdenv.buildPlatform != stdenv.hostPlatform
then buildPackages.fetchurl # No need to do special overrides twice,