summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/builders/packages/firefox.section.md40
-rw-r--r--doc/builders/packages/index.xml1
-rw-r--r--pkgs/applications/networking/browsers/firefox/wrapper.nix170
-rw-r--r--pkgs/build-support/fetchfirefoxaddon/default.nix37
-rw-r--r--pkgs/top-level/all-packages.nix2
5 files changed, 249 insertions, 1 deletions
diff --git a/doc/builders/packages/firefox.section.md b/doc/builders/packages/firefox.section.md
new file mode 100644
index 00000000000..2f89da2d459
--- /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 baf9b8db01b..c2e7ef9bf61 100644
--- a/doc/builders/packages/index.xml
+++ b/doc/builders/packages/index.xml
@@ -10,6 +10,7 @@
  <xi:include href="eclipse.xml" />
  <xi:include href="elm.xml" />
  <xi:include href="emacs.section.xml" />
+ <xi:include href="firefox.section.xml" />
  <xi:include href="ibus.xml" />
  <xi:include href="kakoune.section.xml" />
  <xi:include href="linux.section.xml" />
diff --git a/pkgs/applications/networking/browsers/firefox/wrapper.nix b/pkgs/applications/networking/browsers/firefox/wrapper.nix
index cc6cc72e27b..f9b7f2bb8a2 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" <<EOF
+          pref("general.config.filename", "mozilla.cfg");
+          pref("general.config.obscure_value", 0);
+        EOF
+
+        cat > "$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 00000000000..3426743b2cf
--- /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 81953358bc5..a3c3330ae37 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,