mirror of
https://github.com/nix-community/home-manager
synced 2024-12-26 19:59:47 +01:00
aecd341dfe
Using a fixed application name in the salt for the search engine name hash can break with minor branding changes. For example, LibreWolf 127 used the application name "LibreWolf", but in version 128 it is "Firefox". The proper name can be found in about:support -> Application Basics. Because it doesn't have to be related to the product name visible in most of the browser (for example in the window title and help menus), we shouldn't rely on cfg.name for that. The application name can be read from lib/*/application.ini and we can use that if the browser was installed via Home Manager. If not, we can fall back to cfg.name.
269 lines
8.5 KiB
Nix
269 lines
8.5 KiB
Nix
{ config, lib, pkgs, appName, package, modulePath, profilePath }:
|
|
|
|
with lib;
|
|
|
|
let
|
|
jsonFormat = pkgs.formats.json { };
|
|
|
|
# Map of nice field names to internal field names.
|
|
# This is intended to be exhaustive and should be
|
|
# updated at every version bump.
|
|
internalFieldNames = (genAttrs [
|
|
"name"
|
|
"isAppProvided"
|
|
"loadPath"
|
|
"hasPreferredIcon"
|
|
"updateInterval"
|
|
"updateURL"
|
|
"iconUpdateURL"
|
|
"iconURL"
|
|
"iconMapObj"
|
|
"metaData"
|
|
"orderHint"
|
|
"definedAliases"
|
|
"urls"
|
|
] (name: "_${name}")) // {
|
|
searchForm = "__searchForm";
|
|
};
|
|
|
|
processCustomEngineInput = input:
|
|
(removeAttrs input [ "icon" ]) // optionalAttrs (input ? icon) {
|
|
# Convenience to specify absolute path to icon
|
|
iconURL = "file://${input.icon}";
|
|
} // (optionalAttrs (input ? iconUpdateURL) {
|
|
# Convenience to default iconURL to iconUpdateURL so
|
|
# the icon is immediately downloaded from the URL
|
|
iconURL = input.iconURL or input.iconUpdateURL;
|
|
} // {
|
|
# Required for custom engine configurations, loadPaths
|
|
# are unique identifiers that are generally formatted
|
|
# like: [source]/path/to/engine.xml
|
|
loadPath = "[home-manager]/${
|
|
concatStringsSep "." (map strings.escapeNixIdentifier
|
|
(modulePath ++ [ "engines" input.name ]))
|
|
}";
|
|
});
|
|
|
|
processEngineInput = name: input:
|
|
let
|
|
requiredInput = {
|
|
inherit name;
|
|
isAppProvided = input.isAppProvided or removeAttrs input [ "metaData" ]
|
|
== { };
|
|
metaData = input.metaData or { };
|
|
};
|
|
in if requiredInput.isAppProvided then
|
|
requiredInput
|
|
else
|
|
processCustomEngineInput (input // requiredInput);
|
|
|
|
buildEngineConfig = name: input:
|
|
mapAttrs' (name: value: {
|
|
name = internalFieldNames.${name} or name;
|
|
inherit value;
|
|
}) (processEngineInput name input);
|
|
|
|
sortEngineConfigs = configs:
|
|
let
|
|
buildEngineConfigWithOrder = order: name:
|
|
let
|
|
config = configs.${name} or {
|
|
_name = name;
|
|
_isAppProvided = true;
|
|
_metaData = { };
|
|
};
|
|
in config // { _metaData = config._metaData // { inherit order; }; };
|
|
|
|
engineConfigsWithoutOrder = attrValues (removeAttrs configs config.order);
|
|
|
|
sortedEngineConfigs = (imap buildEngineConfigWithOrder config.order)
|
|
++ engineConfigsWithoutOrder;
|
|
in sortedEngineConfigs;
|
|
|
|
engineInput = config.engines // {
|
|
# Infer config.default as an app provided
|
|
# engine if it's not in config.engines
|
|
${config.default} = config.engines.${config.default} or { };
|
|
} // {
|
|
${config.privateDefault} = config.engines.${config.privateDefault} or { };
|
|
};
|
|
|
|
settings = {
|
|
version = 6;
|
|
engines = sortEngineConfigs (mapAttrs buildEngineConfig engineInput);
|
|
|
|
metaData = optionalAttrs (config.default != null) {
|
|
current = config.default;
|
|
hash = "@hash@";
|
|
} // optionalAttrs (config.privateDefault != null) {
|
|
private = config.privateDefault;
|
|
privateHash = "@privateHash@";
|
|
} // {
|
|
useSavedOrder = config.order != [ ];
|
|
};
|
|
};
|
|
|
|
# Home Manager doesn't circumvent user consent and isn't acting
|
|
# maliciously. We're modifying the search outside of the browser, but
|
|
# a claim by Mozilla to remove this would be very anti-user, and
|
|
# is unlikely to be an issue for our use case.
|
|
disclaimer = "By modifying this file, I agree that I am doing so "
|
|
+ "only within @appName@ itself, using official, user-driven search "
|
|
+ "engine selection processes, and in a way which does not circumvent "
|
|
+ "user consent. I acknowledge that any attempt to change this file "
|
|
+ "from outside of @appName@ is a malicious act, and will be responded "
|
|
+ "to accordingly.";
|
|
|
|
salt = if config.default != null then
|
|
profilePath + config.default + disclaimer
|
|
else
|
|
null;
|
|
|
|
privateSalt = if config.privateDefault != null then
|
|
profilePath + config.privateDefault + disclaimer
|
|
else
|
|
null;
|
|
|
|
appNameVariable = if package == null then
|
|
"appName=${lib.escapeShellArg appName}"
|
|
else ''
|
|
applicationIni="$(find ${lib.escapeShellArg package} -maxdepth 3 -path ${
|
|
lib.escapeShellArg package
|
|
}'/lib/*/application.ini' -print -quit)"
|
|
if test -n "$applicationIni"; then
|
|
appName="$(sed -n 's/^Name=\(.*\)$/\1/p' "$applicationIni" | head -n1)"
|
|
else
|
|
appName=${lib.escapeShellArg appName}
|
|
fi
|
|
'';
|
|
|
|
file = pkgs.runCommand "search.json.mozlz4" {
|
|
nativeBuildInputs = with pkgs; [ mozlz4a openssl ];
|
|
json = builtins.toJSON settings;
|
|
inherit salt privateSalt;
|
|
} ''
|
|
${appNameVariable}
|
|
|
|
salt=''${salt//@appName@/"$appName"}
|
|
privateSalt=''${privateSalt//@appName@/"$appName"}
|
|
|
|
if [[ -n $salt ]]; then
|
|
export hash=$(echo -n "$salt" | openssl dgst -sha256 -binary | base64)
|
|
export privateHash=$(echo -n "$privateSalt" | openssl dgst -sha256 -binary | base64)
|
|
mozlz4a <(substituteStream json search.json.in --subst-var hash --subst-var privateHash) "$out"
|
|
else
|
|
mozlz4a <(echo "$json") "$out"
|
|
fi
|
|
'';
|
|
in {
|
|
imports = [ (pkgs.path + "/nixos/modules/misc/meta.nix") ];
|
|
|
|
meta.maintainers = with maintainers; [ kira-bruneau ];
|
|
|
|
options = {
|
|
enable = mkOption {
|
|
type = with types; bool;
|
|
default = config.default != null || config.privateDefault != null
|
|
|| config.order != [ ] || config.engines != { };
|
|
internal = true;
|
|
};
|
|
|
|
force = mkOption {
|
|
type = with types; bool;
|
|
default = false;
|
|
description = ''
|
|
Whether to force replace the existing search
|
|
configuration. This is recommended since ${appName} will
|
|
replace the symlink for the search configuration on every
|
|
launch, but note that you'll lose any existing configuration
|
|
by enabling this.
|
|
'';
|
|
};
|
|
|
|
default = mkOption {
|
|
type = with types; nullOr str;
|
|
default = null;
|
|
example = "DuckDuckGo";
|
|
description = ''
|
|
The default search engine used in the address bar and search
|
|
bar.
|
|
'';
|
|
};
|
|
|
|
privateDefault = mkOption {
|
|
type = with types; nullOr str;
|
|
default = null;
|
|
example = "DuckDuckGo";
|
|
description = ''
|
|
The default search engine used in the Private Browsing.
|
|
'';
|
|
};
|
|
|
|
order = mkOption {
|
|
type = with types; uniq (listOf str);
|
|
default = [ ];
|
|
example = [ "DuckDuckGo" "Google" ];
|
|
description = ''
|
|
The order the search engines are listed in. Any engines that
|
|
aren't included in this list will be listed after these in an
|
|
unspecified order.
|
|
'';
|
|
};
|
|
|
|
engines = mkOption {
|
|
type = with types; attrsOf (attrsOf jsonFormat.type);
|
|
default = { };
|
|
example = literalExpression ''
|
|
{
|
|
"Nix Packages" = {
|
|
urls = [{
|
|
template = "https://search.nixos.org/packages";
|
|
params = [
|
|
{ name = "type"; value = "packages"; }
|
|
{ name = "query"; value = "{searchTerms}"; }
|
|
];
|
|
}];
|
|
|
|
icon = "''${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
|
|
definedAliases = [ "@np" ];
|
|
};
|
|
|
|
"NixOS Wiki" = {
|
|
urls = [{ template = "https://wiki.nixos.org/index.php?search={searchTerms}"; }];
|
|
iconUpdateURL = "https://wiki.nixos.org/favicon.png";
|
|
updateInterval = 24 * 60 * 60 * 1000; # every day
|
|
definedAliases = [ "@nw" ];
|
|
};
|
|
|
|
"Bing".metaData.hidden = true;
|
|
"Google".metaData.alias = "@g"; # builtin engines only support specifying one additional alias
|
|
}
|
|
'';
|
|
|
|
description = ''
|
|
Attribute set of search engine configurations. Engines that
|
|
only have {var}`metaData` specified will be treated as builtin
|
|
to ${appName}.
|
|
|
|
See [SearchEngine.jsm](https://searchfox.org/mozilla-central/rev/669329e284f8e8e2bb28090617192ca9b4ef3380/toolkit/components/search/SearchEngine.jsm#1138-1177)
|
|
in ${appName}'s source for available options. We maintain a
|
|
mapping to let you specify all options in the referenced link
|
|
without underscores, but it may fall out of date with future
|
|
options.
|
|
|
|
Note, {var}`icon` is also a special option added by Home
|
|
Manager to make it convenient to specify absolute icon paths.
|
|
'';
|
|
};
|
|
|
|
file = mkOption {
|
|
type = with types; path;
|
|
default = file;
|
|
internal = true;
|
|
readOnly = true;
|
|
description = ''
|
|
Resulting search.json.mozlz4 file.
|
|
'';
|
|
};
|
|
};
|
|
}
|