firefox-overlay.nix (223 lines of code) (raw):

# This file provide the latest binary versions of Firefox published by Mozilla. self: super: let # This URL needs to be updated about every 2 years when the subkey is rotated. pgpKey = super.fetchurl { url = "https://download.cdn.mozilla.net/pub/firefox/candidates/138.0b1-candidates/build1/KEY"; hash = "sha256-FOGtyDxtZpW6AbNdSj0QoK1AYkQYxHPypT8zJr2XYQk="; }; # This file is currently maintained manually, if this Nix expression attempt # to download the wrong version, this is likely to be the problem. # # Open a pull request against https://github.com/mozilla-releng/shipit to # update the version, as done in # https://github.com/mozilla-releng/shipit/pull/1467 firefox_versions = with builtins; fromJSON (readFile (fetchurl "https://product-details.mozilla.org/1.0/firefox_versions.json")); arch = if self.stdenv.system == "i686-linux" then "linux-i686" else "linux-x86_64"; yearOf = with super.lib; yyyymmddhhmmss: head (splitString "-" yyyymmddhhmmss); monthOf = with super.lib; yyyymmddhhmmss: head (tail (splitString "-" yyyymmddhhmmss)); # Given SHA512SUMS file contents and file name, extract matching sha512sum. extractSha512Sum = sha512sums: file: with builtins; # Nix 1.x do not have `builtins.split`. # Nix 2.0 have an bug in `builtins.match` (see https://github.com/NixOS/nix/issues/2147). # So I made separate logic for Nix 1.x and Nix 2.0. if builtins ? split then substring 0 128 (head (super.lib.filter (s: isString s && substring 128 (stringLength s) s == " ${file}") (split "\n" sha512sums))) else head (match ".*[\n]([0-9a-f]*) ${file}.*" sha512sums); # The timestamp argument is a yyyy-mm-dd-hh-mm-ss date, which corresponds to # one specific version. This is used mostly for bisecting. versionInfo = { name, version, release, system ? arch, timestamp ? null, info ? null, ... }: with builtins; if (info != null) then info else if release then # For versions such as Beta & Release: # https://download.cdn.mozilla.net/pub/firefox/releases/55.0b3/SHA256SUMS let dir = "https://download.cdn.mozilla.net/pub/firefox/releases/${version}"; # After version 134 firefox switched to using tar.xz instead of tar.bz2 majorVersion = super.lib.strings.toInt ( builtins.elemAt (super.lib.strings.splitString "." version) 0 ); extension = if majorVersion > 134 then "tar.xz" else "tar.bz2"; file = "${system}/en-US/firefox-${version}.${extension}"; sha512Of = chksum: file: extractSha512Sum (readFile (fetchurl chksum)) file; in rec { chksum = "${dir}/SHA512SUMS"; chksumSig = "${chksum}.asc"; chksumSha256 = hashFile "sha256" (fetchurl "${dir}/SHA512SUMS"); chksumSigSha256 = hashFile "sha256" (fetchurl "${chksum}.asc"); inherit file; url = "${dir}/${file}"; sha512 = sha512Of chksum file; sig = null; sigSha512 = null; } else # For Nightly versions: # https://download.cdn.mozilla.net/pub/firefox/nightly/latest-mozilla-central/firefox-56.0a1.en-US.linux-x86_64.checksums let dir = if timestamp == null then let buildhubJSON = with builtins; fromJSON (readFile (fetchurl "https://download.cdn.mozilla.net/pub/firefox/nightly/latest-mozilla-central/firefox-${version}.en-US.${system}.buildhub.json")); in builtins.replaceStrings [ "/${file}" ] [ "" ] buildhubJSON.download.url else "https://download.cdn.mozilla.net/pub/firefox/nightly/${yearOf timestamp}/${monthOf timestamp}/${timestamp}-mozilla-central" ; file = "firefox-${version}.en-US.${system}.tar.xz"; sha512Of = chksum: file: head (match ".*[\n]([0-9a-f]*) sha512 [0-9]* ${file}[\n].*" (readFile (fetchurl chksum))); in rec { chksum = "${dir}/firefox-${version}.en-US.${system}.checksums"; chksumSig = null; # file content: # <hash> sha512 62733881 firefox-56.0a1.en-US.linux-x86_64.tar.bz2 # <hash> sha256 62733881 firefox-56.0a1.en-US.linux-x86_64.tar.bz2 url = "${dir}/${file}"; sha512 = sha512Of chksum file; sig = "${dir}/${file}.asc"; sigSha512 = sha512Of chksum "${file}.asc"; }; # From the version info, check the authenticity of the check sum file, such # that we guarantee that we have verifyFileAuthenticity = { file, sha512, chksum, chksumSig }: assert extractSha512Sum (builtins.readFile chksum) file == sha512; super.runCommand "check-firefox-signature" { buildInputs = [ self.gnupg ]; FILE = chksum; ASC = chksumSig; } '' set -eu gpg --dearmor < ${pgpKey} > keyring.gpg gpgv --keyring=./keyring.gpg $ASC $FILE mkdir $out ''; # From the version info, create a fetchurl derivation which will get the # sources from the remote. fetchVersion = info: if info.chksumSig != null then super.fetchurl { inherit (info) url sha512; # This is a fixed derivation, but we still add as a dependency the # verification of the checksum. Thus, this fetch script can only be # executed once the verifyAuthenticity script finished successfully. postFetch = '' : # Authenticity Check (${verifyFileAuthenticity { inherit (info) file sha512; chksum = builtins.fetchurl { url = info.chksum; sha256 = info.chksumSha256; }; chksumSig = builtins.fetchurl { url = info.chksumSig; sha256 = info.chksumSigSha256; }; }}) ''; } else super.fetchurl { inherit (info) url sha512; # This would download the tarball, and then verify that the content # match the signature file. Fortunately, any failure of this code would # prevent the output from being reused. postFetch = let asc = super.fetchurl { url = info.sig; sha512 = info.sigSha512; }; in '' : # Authenticity Check set -eu export PATH="$PATH:${self.gnupg}/bin/" gpg --dearmor < ${pgpKey} > keyring.gpg gpgv --keyring=./keyring.gpg ${asc} $out ''; }; firefoxVersion = version: let info = versionInfo version; pkg = ((self.firefox-bin-unwrapped.override ({ generated = { version = version.version; sources = { inherit (info) url sha512; }; }; channel = version.channel; } // super.lib.optionalAttrs (self.firefox-bin-unwrapped.passthru ? applicationName) { applicationName = version.name; })).overrideAttrs (old: { # Add a dependency on the signature check. src = fetchVersion info; })); in super.wrapFirefox pkg ({ pname = "${pkg.binaryName}-bin"; wmClass = version.wmClass; } // super.lib.optionalAttrs (!self.firefox-bin-unwrapped.passthru ? applicationName) { desktopName = version.name; }); firefoxVariants = { firefox-nightly-bin = { name = "Firefox Nightly"; channel = "nightly"; wmClass = "firefox-nightly"; version = firefox_versions.FIREFOX_NIGHTLY; release = false; }; firefox-beta-bin = { name = "Firefox Beta"; channel = "beta"; wmClass = "firefox-beta"; version = firefox_versions.LATEST_FIREFOX_DEVEL_VERSION; release = true; }; firefox-bin = { name = "Firefox"; channel = "release"; wmClass = "firefox"; version = firefox_versions.LATEST_FIREFOX_VERSION; release = true; }; firefox-esr-bin = { name = "Firefox ESR"; channel = "release"; wmClass = "firefox"; version = firefox_versions.FIREFOX_ESR; release = true; }; }; in { lib = super.lib // { firefoxOverlay = { inherit pgpKey firefoxVersion versionInfo firefox_versions firefoxVariants; }; }; # Set of packages which are automagically updated. Do not rely on these for # reproducible builds. latest = (super.latest or {}) // (builtins.mapAttrs (n: v: firefoxVersion v) firefoxVariants); # Set of packages which used to build developer environment devEnv = (super.shell or {}) // { gecko = super.callPackage ./pkgs/gecko { inherit (self.python38Packages) setuptools; pythonFull = self.python38Full; nodejs = if builtins.compareVersions self.nodejs.name "nodejs-8.11.3" < 0 then self.nodejs-8_x else self.nodejs; rust-cbindgen = if !(self ? "rust-cbindgen") then self.rust-cbindgen-latest else if builtins.compareVersions self.rust-cbindgen.version self.rust-cbindgen-latest.version < 0 then self.rust-cbindgen-latest else self.rust-cbindgen; # Due to std::ascii::AsciiExt changes in 1.23, Gecko does not compile, so # use the latest Rust version before 1.23. # rust = (super.rustChannelOf { channel = "stable"; date = "2017-11-22"; }).rust; # rust = (super.rustChannelOf { channel = "stable"; date = "2020-03-12"; }).rust; inherit (self.latest.rustChannels.stable) rust; }; }; # Use rust-cbindgen imported from Nixpkgs (September 2018) unless the current # version of Nixpkgs already packages a version of rust-cbindgen. rust-cbindgen-latest = super.callPackage ./pkgs/cbindgen { rustPlatform = super.makeRustPlatform { cargo = self.latest.rustChannels.stable.rust; rustc = self.latest.rustChannels.stable.rust; }; }; jsdoc = super.callPackage ./pkgs/jsdoc {}; }