{ pkgs, lib }: with lib; rec { mozlz4 = pkgs.callPackage ./mozlz4.nix {}; flattenAttrs = set: let recurse = k: v: if isAttrs v then mapAttrsToList (k': recurse "${k}.${k'}") v else nameValuePair k v; in listToAttrs (flatten (mapAttrsToList recurse set)); mkValueString = v: if isInt v then toString v else if isString v then "\"${v}\"" else if true == v then "true" else if false == v then "false" else abort "unsupported value type: ${builtins.typeOf v}"; mkPrefs = settings: pkgs.writeText "prefs.js" ("// dummy line\n" + (lib.concatStringsSep "\n" (lib.mapAttrsToList (k: v: "pref(\"${k}\", ${mkValueString v}, locked);") (flattenAttrs settings)))); toSearchConfig = settings: pkgs.runCommand "search.json.mozlz4" {} '' ${mozlz4.compress} < ${pkgs.writeText "search.json" (builtins.toJSON settings)} > $out ''; profile = { preferences, search }: pkgs.runCommand "profile" {} '' mkdir $out ln -s ${toUserPrefs preferences} $out/user.js # ln -s ${toSearchConfig search} $out/search.json.mozlz4 cp ${../search-with-qj.json.mozlz4} $out/search.json.mozlz4 ''; mkPolicies = policies: pkgs.writeText "policies.json" (builtins.toJSON { inherit policies; }); mergeProfiles = profiles: let sanitise = args: { policies = args.policies or {}; preferences = args.preferences or {}; }; sanitised = map sanitise profiles; final = lib.foldl lib.recursiveUpdate {} sanitised; in final; bundle = { policies ? {}, preferences ? {} }: let firefox = pkgs.firefox-unwrapped; policies' = mkPolicies policies; preferences' = mkPrefs preferences; patched = pkgs.runCommand "firefox-bundle" { nativeBuildInputs = [ pkgs.nix ]; disallowedReferences = [ firefox ]; } '' cp -r ${firefox} $out chmod -R +w $out # correct argv[0], which is used to locate distribution and defaults substituteInPlace $out/bin/firefox \ --replace ${firefox} $out mkdir $out/lib/firefox/distribution cp ${policies'} $out/lib/firefox/distribution/policies.json cp ${preferences'} $out/lib/firefox/defaults/pref/99-custom.js ''; wrapped = (pkgs.wrapFirefox patched { browserName = "firefox"; version = "custom"; }) // { inherit policies preferences; }; in wrapped; launcher = firefox: pkgs.writeShellScriptBin "firefox" '' # FF doesn't accept ro profiles, tries to create lockfile TMP_PROFILE="$(mktemp -d)" function finish() { echo deleting profile # rm -rv "$TMP_PROFILE" } trap finish EXIT # cp -r ''${profile} "$TMP_PROFILE" chmod u+rwx -R "$TMP_PROFILE" ${firefox}/bin/firefox \ --no-remote \ --profile "$TMP_PROFILE" ''; }