diff options
41 files changed, 1832 insertions, 1203 deletions
diff --git a/nixos/doc/manual/man-nixos-rebuild.xml b/nixos/doc/manual/man-nixos-rebuild.xml index d0ff81c1dbb37..4510fdd442255 100644 --- a/nixos/doc/manual/man-nixos-rebuild.xml +++ b/nixos/doc/manual/man-nixos-rebuild.xml @@ -113,6 +113,18 @@ <replaceable>path</replaceable> </arg> <arg> + <option>-L</option> + </arg> + <arg> + <option>--refresh</option> + </arg> + <arg> + <option>--no-net</option> + </arg> + <arg> + <option>--impure</option> + </arg> + <arg> <group choice='req'> <arg choice='plain'><option>--verbose</option></arg> <arg choice='plain'><option>-v</option></arg> @@ -131,6 +143,18 @@ <replaceable>number</replaceable> </arg> <arg> + <option>--fallback</option> + </arg> + <arg> + <option>--repair</option> + </arg> + <arg> + <group choice='req'> + <arg choice='plain'><option>--no-build-output</option></arg> + <arg choice='plain'><option>-Q</option></arg> + </group> + </arg> + <arg> <group choice='req'> <arg choice='plain'><option>--keep-failed</option></arg> <arg choice='plain'><option>-K</option></arg> @@ -567,10 +591,19 @@ <para> In addition, <command>nixos-rebuild</command> accepts various Nix-related - flags, including <option>--max-jobs</option> / <option>-j</option>, + flags: <option>-I</option>, <option>--max-jobs</option> / <option>-j</option>, <option>--show-trace</option>, <option>--keep-failed</option>, - <option>--keep-going</option>, <option>--impure</option>, and <option>--verbose</option> / + <option>--keep-going</option>, <option>--impure</option>, and <option>--verbose</option> / + <option>--builders</option>, <option>--show-trace</option>, + <option>--fallback</option>, <option>--repair</option>, + <option>--no-build-output</option> / <option>-Q</option>, + <option>--keep-failed</option> / <option>-K</option>, + <option>--keep-going</option> / <option>-k</option> and <option>--verbose</option> / <option>-v</option>. See the Nix manual for details. + + The following Nix flags that are support by the upcoming nix 2.4 version: + <option>-L</option>, <option>--refresh</option>, <option>--no-net</option>, + <option>--no-net</option>, <option>--impure</option>. See <command>nix --help</command> or <command>nix build --help</command> for details. </para> </refsection> diff --git a/nixos/modules/programs/command-not-found/command-not-found.nix b/nixos/modules/programs/command-not-found/command-not-found.nix index 656c255fcb185..da09488d82c7a 100644 --- a/nixos/modules/programs/command-not-found/command-not-found.nix +++ b/nixos/modules/programs/command-not-found/command-not-found.nix @@ -9,17 +9,9 @@ with lib; let cfg = config.programs.command-not-found; - commandNotFound = pkgs.substituteAll { - name = "command-not-found"; - dir = "bin"; - src = ./command-not-found.pl; - isExecutable = true; - inherit (pkgs) perl; + commandNotFound = pkgs.callPackage ./. { inherit (cfg) dbPath; - perlFlags = concatStrings (map (path: "-I ${path}/${pkgs.perl.libPrefix} ") - [ pkgs.perlPackages.DBI pkgs.perlPackages.DBDSQLite pkgs.perlPackages.StringShellQuote ]); }; - in { @@ -91,5 +83,4 @@ in environment.systemPackages = [ commandNotFound ]; }; - } diff --git a/nixos/modules/programs/command-not-found/command-not-found.pl b/nixos/modules/programs/command-not-found/command-not-found.pl deleted file mode 100644 index ab7aa204653cd..0000000000000 --- a/nixos/modules/programs/command-not-found/command-not-found.pl +++ /dev/null @@ -1,51 +0,0 @@ -#! @perl@/bin/perl -w @perlFlags@ - -use strict; -use DBI; -use DBD::SQLite; -use String::ShellQuote; -use Config; - -my $program = $ARGV[0]; - -my $dbPath = "@dbPath@"; - -my $dbh = DBI->connect("dbi:SQLite:dbname=$dbPath", "", "") - or die "cannot open database `$dbPath'"; -$dbh->{RaiseError} = 0; -$dbh->{PrintError} = 0; - -my $system = $ENV{"NIX_SYSTEM"} // $Config{myarchname}; - -my $res = $dbh->selectall_arrayref( - "select package from Programs where system = ? and name = ?", - { Slice => {} }, $system, $program); - -if (!defined $res || scalar @$res == 0) { - print STDERR "$program: command not found\n"; -} elsif (scalar @$res == 1) { - my $package = @$res[0]->{package}; - if ($ENV{"NIX_AUTO_INSTALL"} // "") { - print STDERR <<EOF; -The program ‘$program’ is currently not installed. It is provided by -the package ‘$package’, which I will now install for you. -EOF - ; - exit 126 if system("nix-env", "-iA", "nixos.$package") == 0; - } elsif ($ENV{"NIX_AUTO_RUN"} // "") { - exec("nix-shell", "-p", $package, "--run", shell_quote("exec", @ARGV)); - } else { - print STDERR <<EOF; -The program ‘$program’ is currently not installed. You can install it by typing: - nix-env -iA nixos.$package -EOF - } -} else { - print STDERR <<EOF; -The program ‘$program’ is currently not installed. It is provided by -several packages. You can install it by typing one of the following: -EOF - print STDERR " nix-env -iA nixos.$_->{package}\n" foreach @$res; -} - -exit 127; diff --git a/nixos/modules/programs/command-not-found/default.nix b/nixos/modules/programs/command-not-found/default.nix new file mode 100644 index 0000000000000..bbe949fa86a3c --- /dev/null +++ b/nixos/modules/programs/command-not-found/default.nix @@ -0,0 +1,18 @@ +{ stdenv, rustPlatform, pkgconfig, sqlite +, dbPath ? "/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite" }: + +rustPlatform.buildRustPackage { + name = "command-not-found"; + src = ./rust; + + DB_PATH = dbPath; + NIX_SYSTEM = stdenv.system; + + postInstall = '' + strip $out/bin/command-not-found + ''; + + buildInputs = [ sqlite ]; + nativeBuildInputs = [ pkgconfig ]; + cargoSha256 = "13q61bb4b1q40g424pbssyp3ln79q1a33vmyz9s9wlqnac34cibd"; +} diff --git a/nixos/modules/programs/command-not-found/rust/Cargo.lock b/nixos/modules/programs/command-not-found/rust/Cargo.lock new file mode 100644 index 0000000000000..ce3a9358c5c2d --- /dev/null +++ b/nixos/modules/programs/command-not-found/rust/Cargo.lock @@ -0,0 +1,131 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "command-not-found" +version = "0.1.0" +dependencies = [ + "rusqlite 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libsqlite3-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rusqlite" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libsqlite3-sys 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "smallvec" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "vcpkg" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +"checksum fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" +"checksum libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" +"checksum libsqlite3-sys 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e704a02bcaecd4a08b93a23f6be59d0bd79cd161e0963e9499165a0a35df7bd" +"checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" +"checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" +"checksum rusqlite 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)" = "45d0fd62e1df63d254714e6cb40d0a0e82e7a1623e7a27f679d851af092ae58b" +"checksum smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" +"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +"checksum vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/nixos/modules/programs/command-not-found/rust/Cargo.toml b/nixos/modules/programs/command-not-found/rust/Cargo.toml new file mode 100644 index 0000000000000..f965c7df76a5d --- /dev/null +++ b/nixos/modules/programs/command-not-found/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "command-not-found" +version = "0.1.0" +edition = "2018" + +[dependencies] +rusqlite = "0.*.*" + +[profile.release] +lto = true diff --git a/nixos/modules/programs/command-not-found/rust/src/main.rs b/nixos/modules/programs/command-not-found/rust/src/main.rs new file mode 100644 index 0000000000000..b0af2871cc295 --- /dev/null +++ b/nixos/modules/programs/command-not-found/rust/src/main.rs @@ -0,0 +1,52 @@ +use rusqlite::{params, Connection, Result}; +use std::env; +use std::process::exit; + +const NIX_SYSTEM: &str = env!("NIX_SYSTEM"); +const DB_PATH: &str = env!("DB_PATH"); + +fn query_packages(system: &str, program: &str) -> Result<Vec<String>> { + Ok(Connection::open(DB_PATH)? + .prepare("select package from Programs where system = ? and name = ?;")? + .query_map(params![system, program], |row| row.get("package"))? + .collect::<Result<Vec<String>>>()?) +} + +fn run_app() -> i32 { + let args: Vec<_> = env::args().collect(); + if args.len() < 2 { + eprintln!("USAGE: {} PROGRAMNAME", args[0]); + return 1; + } + let program = &args[1]; + let system = env::var("NIX_SYSTEM").unwrap_or_else(|_| NIX_SYSTEM.to_string()); + let packages = match query_packages(&system, program) { + Ok(packages) => packages, + Err(err) => { + eprintln!("Failed to query package database: {}", err); + return 1; + } + }; + if packages.is_empty() { + eprintln!("{}: command not found", program); + } else { + let advice = if packages.len() > 1 { + "It is provided by several packages. You can install it by typing on of the of following commands:" + } else { + "You can install it by typing:" + }; + eprintln!( + "The program '{}' is currently not installed. {}", + program, advice + ); + for pkg in packages { + eprintln!(" nix-env -iA nixos.{}", pkg); + } + } + + 127 +} + +fn main() { + exit(run_app()); +} diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix index 6b8853ae390b9..9988f382a1b10 100644 --- a/nixos/modules/services/databases/redis.nix +++ b/nixos/modules/services/databases/redis.nix @@ -12,7 +12,7 @@ let ${condOption "bind" cfg.bind} ${condOption "unixsocket" cfg.unixSocket} daemonize no - supervised systemd + #supervised systemd loglevel ${cfg.logLevel} logfile ${cfg.logfile} syslog-enabled ${redisBool cfg.syslog} @@ -242,7 +242,9 @@ in ExecStart = "${cfg.package}/bin/redis-server /run/redis/redis.conf"; RuntimeDirectory = "redis"; StateDirectory = "redis"; - Type = "notify"; + TimeoutStartSec = "infinity"; + TimeoutStopSec = "infinity"; + Type = "simple"; User = "redis"; Group = "redis"; }; diff --git a/nixos/modules/services/misc/home-assistant.nix b/nixos/modules/services/misc/home-assistant.nix index 1f2e13f373257..16fff215e6163 100644 --- a/nixos/modules/services/misc/home-assistant.nix +++ b/nixos/modules/services/misc/home-assistant.nix @@ -62,6 +62,17 @@ let lovelace.mode = "yaml"; }; + #pythonScripts = pkgs.runCommand "python_scripts" { + # nativeBuildInputs = [ pkgs.python3 ]; + # scripts = cfg.pythonScripts; + #} '' + # mkdir $out + # for s in $scripts; do + # echo "checking syntax of $s" + # python -m py_compile "$s" + # ln -s "$s" "$out/$(basename $s" + # done + #''; in { meta.maintainers = with maintainers; [ dotlambda ]; @@ -214,6 +225,17 @@ in { ''; }; + pythonScripts = mkOption { + #default = []; + #type = types.listOf types.path; + default = null; + type = types.nullOr types.path; + description = '' + List of python scripts to use in the <literal>python_scripts</literal> integration. + Also see in the <link xlink:href="https://www.home-assistant.io/integrations/python_script">Homeassistant documentation</link> + ''; + }; + openFirewall = mkOption { default = false; type = types.bool; @@ -224,6 +246,12 @@ in { config = mkIf cfg.enable { networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; + systemd.tmpfiles.rules = mkIf (cfg.pythonScripts != null) [ + "L+ ${cfg.configDir}/python_scripts - - - - ${cfg.pythonScripts}" + ]; + + services.home-assistant.config.python_script = mkIf (cfg.pythonScripts != null) {}; + systemd.services.home-assistant = { description = "Home Assistant"; after = [ "network.target" ]; diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix index 0eeff31d6c4d4..b0763c8d0de49 100644 --- a/nixos/modules/services/misc/nix-daemon.nix +++ b/nixos/modules/services/misc/nix-daemon.nix @@ -11,6 +11,7 @@ let nixVersion = getVersion nix; isNix23 = versionAtLeast nixVersion "2.3pre"; + isNix24 = versionAtLeast nixVersion "2.4pre"; makeNixBuildUser = nr: { name = "nixbld${toString nr}"; @@ -40,7 +41,11 @@ let max-jobs = ${toString (cfg.maxJobs)} cores = ${toString (cfg.buildCores)} sandbox = ${if (builtins.isBool cfg.useSandbox) then boolToString cfg.useSandbox else cfg.useSandbox} - extra-sandbox-paths = ${toString cfg.sandboxPaths} + + ${optionalString (!isNix24) '' + extra-sandbox-paths = ${toString cfg.sandboxPaths} + ''} + substituters = ${toString cfg.binaryCaches} trusted-substituters = ${toString cfg.trustedBinaryCaches} trusted-public-keys = ${toString cfg.binaryCachePublicKeys} diff --git a/nixos/modules/services/networking/privoxy.nix b/nixos/modules/services/networking/privoxy.nix index e3b34cb0c6160..7caae3282032c 100644 --- a/nixos/modules/services/networking/privoxy.nix +++ b/nixos/modules/services/networking/privoxy.nix @@ -16,7 +16,7 @@ let ${concatMapStrings (f: "actionsfile ${f}\n") cfg.actionsFiles} ${concatMapStrings (f: "filterfile ${f}\n") cfg.filterFiles} '' + optionalString cfg.enableTor '' - forward-socks4a / ${config.services.tor.client.socksListenAddressFaster} . + forward-socks5t / 127.0.0.1:9063 . toggle 1 enable-remote-toggle 0 enable-edit-actions 0 @@ -123,6 +123,11 @@ in serviceConfig.ProtectSystem = "full"; }; + services.tor.settings.SOCKSPort = mkIf cfg.enableTor [ + # Route HTTP traffic over a faster port (without IsolateDestAddr). + { addr = "127.0.0.1"; port = 9063; IsolateDestAddr = false; } + ]; + }; meta.maintainers = with lib.maintainers; [ rnhmjoj ]; diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix index 1cceee065b1bb..ececb633983c1 100644 --- a/nixos/modules/services/security/tor.nix +++ b/nixos/modules/services/security/tor.nix @@ -1,297 +1,300 @@ { config, lib, pkgs, ... }: +with builtins; with lib; let cfg = config.services.tor; - torDirectory = "/var/lib/tor"; - torRunDirectory = "/run/tor"; - - opt = name: value: optionalString (value != null) "${name} ${value}"; - optint = name: value: optionalString (value != null && value != 0) "${name} ${toString value}"; - - isolationOptions = { - type = types.listOf (types.enum [ - "IsolateClientAddr" - "IsolateSOCKSAuth" - "IsolateClientProtocol" - "IsolateDestPort" - "IsolateDestAddr" + stateDir = "/var/lib/tor"; + runDir = "/run/tor"; + descriptionGeneric = option: '' + See <link xlink:href="https://2019.www.torproject.org/docs/tor-manual.html.en#${option}">torrc manual</link>. + ''; + bindsPrivilegedPort = + any (p0: + let p1 = if p0 ? "port" then p0.port else p0; in + if p1 == "auto" then false + else let p2 = if isInt p1 then p1 else toInt p1; in + p1 != null && 0 < p2 && p2 < 1024) + (flatten [ + cfg.settings.ORPort + cfg.settings.DirPort + cfg.settings.DNSPort + cfg.settings.ExtORPort + cfg.settings.HTTPTunnelPort + cfg.settings.NATDPort + cfg.settings.SOCKSPort + cfg.settings.TransPort ]); + optionBool = optionName: mkOption { + type = with types; nullOr bool; + default = null; + description = descriptionGeneric optionName; + }; + optionInt = optionName: mkOption { + type = with types; nullOr int; + default = null; + description = descriptionGeneric optionName; + }; + optionString = optionName: mkOption { + type = with types; nullOr str; + default = null; + description = descriptionGeneric optionName; + }; + optionStrings = optionName: mkOption { + type = with types; listOf str; default = []; - example = [ - "IsolateClientAddr" - "IsolateSOCKSAuth" - "IsolateClientProtocol" - "IsolateDestPort" - "IsolateDestAddr" + description = descriptionGeneric optionName; + }; + optionAddress = mkOption { + type = with types; nullOr str; + default = null; + example = "0.0.0.0"; + description = '' + IPv4 or IPv6 (if between brackets) address. + ''; + }; + optionUnix = mkOption { + type = with types; nullOr path; + default = null; + description = '' + Unix domain socket path to use. + ''; + }; + optionPort = mkOption { + type = with types; nullOr (oneOf [port (enum ["auto"])]); + default = null; + }; + optionPorts = optionName: mkOption { + type = with types; listOf port; + default = []; + description = descriptionGeneric optionName; + }; + optionIsolablePort = with types; oneOf [ + port (enum ["auto"]) + (submodule ({config, ...}: { + options = { + addr = optionAddress; + port = optionPort; + flags = optionFlags; + SessionGroup = mkOption { type = nullOr int; default = null; }; + } // genAttrs isolateFlags (name: mkOption { type = types.bool; default = false; }); + config = { + flags = filter (name: config.${name} == true) isolateFlags ++ + optional (config.SessionGroup != null) "SessionGroup=${toString config.SessionGroup}"; + }; + })) + ]; + optionIsolablePorts = optionName: mkOption { + default = []; + type = with types; either optionIsolablePort (listOf optionIsolablePort); + description = descriptionGeneric optionName; + }; + isolateFlags = [ + "IsolateClientAddr" + "IsolateClientProtocol" + "IsolateDestAddr" + "IsolateDestPort" + "IsolateSOCKSAuth" + "KeepAliveIsolateSOCKSAuth" + ]; + optionSOCKSPort = doConfig: let + flags = [ + "CacheDNS" "CacheIPv4DNS" "CacheIPv6DNS" "GroupWritable" "IPv6Traffic" + "NoDNSRequest" "NoIPv4Traffic" "NoOnionTraffic" "OnionTrafficOnly" + "PreferIPv6" "PreferIPv6Automap" "PreferSOCKSNoAuth" "UseDNSCache" + "UseIPv4Cache" "UseIPv6Cache" "WorldWritable" + ] ++ isolateFlags; + in with types; oneOf [ + port (submodule ({config, ...}: { + options = { + unix = optionUnix; + addr = optionAddress; + port = optionPort; + flags = optionFlags; + SessionGroup = mkOption { type = nullOr int; default = null; }; + } // genAttrs flags (name: mkOption { type = types.bool; default = false; }); + config = mkIf doConfig { # Only add flags in SOCKSPort to avoid duplicates + flags = filter (name: config.${name} == true) flags ++ + optional (config.SessionGroup != null) "SessionGroup=${toString config.SessionGroup}"; + }; + })) ]; - description = "Tor isolation options"; + optionFlags = mkOption { + type = with types; listOf str; + default = []; + }; + optionORPort = optionName: mkOption { + default = []; + example = 443; + type = with types; oneOf [port (enum ["auto"]) (listOf (oneOf [ + port + (enum ["auto"]) + (submodule ({config, ...}: + let flags = [ "IPv4Only" "IPv6Only" "NoAdvertise" "NoListen" ]; + in { + options = { + addr = optionAddress; + port = optionPort; + flags = optionFlags; + } // genAttrs flags (name: mkOption { type = types.bool; default = false; }); + config = { + flags = filter (name: config.${name} == true) flags; + }; + })) + ]))]; + description = descriptionGeneric optionName; + }; + optionBandwith = optionName: mkOption { + type = with types; nullOr (either int str); + default = null; + description = descriptionGeneric optionName; + }; + optionPath = optionName: mkOption { + type = with types; nullOr path; + default = null; + description = descriptionGeneric optionName; }; - - torRc = '' - User tor - DataDirectory ${torDirectory} - ${optionalString cfg.enableGeoIP '' - GeoIPFile ${cfg.package.geoip}/share/tor/geoip - GeoIPv6File ${cfg.package.geoip}/share/tor/geoip6 - ''} - - ${optint "ControlPort" cfg.controlPort} - ${optionalString cfg.controlSocket.enable "ControlPort unix:${torRunDirectory}/control GroupWritable RelaxDirModeCheck"} - '' - # Client connection config - + optionalString cfg.client.enable '' - SOCKSPort ${cfg.client.socksListenAddress} ${toString cfg.client.socksIsolationOptions} - SOCKSPort ${cfg.client.socksListenAddressFaster} - ${opt "SocksPolicy" cfg.client.socksPolicy} - - ${optionalString cfg.client.transparentProxy.enable '' - TransPort ${cfg.client.transparentProxy.listenAddress} ${toString cfg.client.transparentProxy.isolationOptions} - ''} - - ${optionalString cfg.client.dns.enable '' - DNSPort ${cfg.client.dns.listenAddress} ${toString cfg.client.dns.isolationOptions} - AutomapHostsOnResolve 1 - AutomapHostsSuffixes ${concatStringsSep "," cfg.client.dns.automapHostsSuffixes} - ''} - '' - # Explicitly disable the SOCKS server if the client is disabled. In - # particular, this makes non-anonymous hidden services possible. - + optionalString (! cfg.client.enable) '' - SOCKSPort 0 - '' - # Relay config - + optionalString cfg.relay.enable '' - ORPort ${toString cfg.relay.port} - ${opt "Address" cfg.relay.address} - ${opt "Nickname" cfg.relay.nickname} - ${opt "ContactInfo" cfg.relay.contactInfo} - - ${optint "RelayBandwidthRate" cfg.relay.bandwidthRate} - ${optint "RelayBandwidthBurst" cfg.relay.bandwidthBurst} - ${opt "AccountingMax" cfg.relay.accountingMax} - ${opt "AccountingStart" cfg.relay.accountingStart} - - ${if (cfg.relay.role == "exit") then - opt "ExitPolicy" cfg.relay.exitPolicy - else - "ExitPolicy reject *:*"} - - ${optionalString (elem cfg.relay.role ["bridge" "private-bridge"]) '' - BridgeRelay 1 - ServerTransportPlugin ${concatStringsSep "," cfg.relay.bridgeTransports} exec ${pkgs.obfs4}/bin/obfs4proxy managed - ExtORPort auto - ${optionalString (cfg.relay.role == "private-bridge") '' - ExtraInfoStatistics 0 - PublishServerDescriptor 0 - ''} - ''} - '' - # Hidden services - + concatStrings (flip mapAttrsToList cfg.hiddenServices (n: v: '' - HiddenServiceDir ${torDirectory}/onion/${v.name} - ${optionalString (v.version != null) "HiddenServiceVersion ${toString v.version}"} - ${flip concatMapStrings v.map (p: '' - HiddenServicePort ${toString p.port} ${p.destination} - '')} - ${optionalString (v.authorizeClient != null) '' - HiddenServiceAuthorizeClient ${v.authorizeClient.authType} ${concatStringsSep "," v.authorizeClient.clientNames} - ''} - '')) - + cfg.extraConfig; - - torRcFile = pkgs.writeText "torrc" torRc; - + mkValueString = k: v: + if v == null then "" + else if isBool v then + (if v then "1" else "0") + else if v ? "unix" && v.unix != null then + "unix:"+v.unix + + optionalString (v ? "flags") (" " + concatStringsSep " " v.flags) + else if v ? "port" && v.port != null then + optionalString (v ? "addr" && v.addr != null) "${v.addr}:" + + toString v.port + + optionalString (v ? "flags") (" " + concatStringsSep " " v.flags) + else if k == "ServerTransportPlugin" then + optionalString (v.transports != []) "${concatStringsSep "," v.transports} exec ${v.exec}" + else if k == "HidServAuth" then + concatMapStringsSep "\n${k} " (settings: settings.onion + " " settings.auth) v + else generators.mkValueStringDefault {} v; + genTorrc = settings: + generators.toKeyValue { + listsAsDuplicateKeys = true; + mkKeyValue = k: generators.mkKeyValueDefault { mkValueString = mkValueString k; } " " k; + } + (lib.mapAttrs (k: v: + # Not necesssary, but prettier rendering + if elem k [ "AutomapHostsSuffixes" "DirPolicy" "ExitPolicy" "SocksPolicy" ] + && v != [] + then concatStringsSep "," v + else v) + (lib.filterAttrs (k: v: !(v == null || v == "")) + settings)); + torrc = pkgs.writeText "torrc" ( + genTorrc cfg.settings + + concatStrings (mapAttrsToList (name: onion: + "HiddenServiceDir ${onion.path}\n" + + genTorrc onion.settings) cfg.relay.onionServices) + ); in { imports = [ - (mkRemovedOptionModule [ "services" "tor" "client" "privoxy" "enable" ] '' - Use services.privoxy.enable and services.privoxy.enableTor instead. - '') - (mkRenamedOptionModule [ "services" "tor" "relay" "portSpec" ] [ "services" "tor" "relay" "port" ]) + (mkRenamedOptionModule [ "services" "tor" "client" "dns" "automapHostsSuffixes" ] [ "services" "tor" "settings" "AutomapHostsSuffixes" ]) + (mkRemovedOptionModule [ "services" "tor" "client" "dns" "isolationOptions" ] "Use services.tor.settings.DNSPort instead.") + (mkRemovedOptionModule [ "services" "tor" "client" "dns" "listenAddress" ] "Use services.tor.settings.DNSPort instead.") + (mkRemovedOptionModule [ "services" "tor" "client" "privoxy" "enable" ] "Use services.privoxy.enable and services.privoxy.enableTor instead.") + (mkRemovedOptionModule [ "services" "tor" "client" "socksIsolationOptions" ] "Use services.tor.settings.SOCKSPort instead.") + (mkRemovedOptionModule [ "services" "tor" "client" "socksListenAddressFaster" ] "Use services.tor.settings.SOCKSPort instead.") + (mkRenamedOptionModule [ "services" "tor" "client" "socksPolicy" ] [ "services" "tor" "settings" "SocksPolicy" ]) + (mkRemovedOptionModule [ "services" "tor" "client" "transparentProxy" "isolationOptions" ] "Use services.tor.settings.TransPort instead.") + (mkRemovedOptionModule [ "services" "tor" "client" "transparentProxy" "listenAddress" ] "Use services.tor.settings.TransPort instead.") + (mkRenamedOptionModule [ "services" "tor" "controlPort" ] [ "services" "tor" "settings" "ControlPort" ]) + (mkRemovedOptionModule [ "services" "tor" "extraConfig" ] "Plese use services.tor.settings instead.") + (mkRenamedOptionModule [ "services" "tor" "hiddenServices" ] [ "services" "tor" "relay" "onionServices" ]) + (mkRenamedOptionModule [ "services" "tor" "relay" "accountingMax" ] [ "services" "tor" "settings" "AccountingMax" ]) + (mkRenamedOptionModule [ "services" "tor" "relay" "accountingStart" ] [ "services" "tor" "settings" "AccountingStart" ]) + (mkRenamedOptionModule [ "services" "tor" "relay" "address" ] [ "services" "tor" "settings" "Address" ]) + (mkRenamedOptionModule [ "services" "tor" "relay" "bandwidthBurst" ] [ "services" "tor" "settings" "BandwidthBurst" ]) + (mkRenamedOptionModule [ "services" "tor" "relay" "bandwidthRate" ] [ "services" "tor" "settings" "BandwidthRate" ]) + (mkRenamedOptionModule [ "services" "tor" "relay" "bridgeTransports" ] [ "services" "tor" "settings" "ServerTransportPlugin" "transports" ]) + (mkRenamedOptionModule [ "services" "tor" "relay" "contactInfo" ] [ "services" "tor" "settings" "ContactInfo" ]) + (mkRenamedOptionModule [ "services" "tor" "relay" "exitPolicy" ] [ "services" "tor" "settings" "ExitPolicy" ]) (mkRemovedOptionModule [ "services" "tor" "relay" "isBridge" ] "Use services.tor.relay.role instead.") (mkRemovedOptionModule [ "services" "tor" "relay" "isExit" ] "Use services.tor.relay.role instead.") + (mkRenamedOptionModule [ "services" "tor" "relay" "nickname" ] [ "services" "tor" "settings" "Nickname" ]) + (mkRenamedOptionModule [ "services" "tor" "relay" "port" ] [ "services" "tor" "settings" "ORPort" ]) + (mkRenamedOptionModule [ "services" "tor" "relay" "portSpec" ] [ "services" "tor" "settings" "ORPort" ]) ]; options = { services.tor = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Enable the Tor daemon. By default, the daemon is run without - relay, exit, bridge or client connectivity. - ''; - }; + enable = mkEnableOption ''Tor daemon. + By default, the daemon is run without + relay, exit, bridge or client connectivity''; + + openFirewall = mkEnableOption "opening of the relay port(s) in the firewall"; package = mkOption { type = types.package; default = pkgs.tor; defaultText = "pkgs.tor"; example = literalExample "pkgs.tor"; - description = '' - Tor package to use - ''; + description = "Tor package to use."; }; - enableGeoIP = mkOption { - type = types.bool; - default = true; - description = '' - Whenever to configure Tor daemon to use GeoIP databases. + enableGeoIP = mkEnableOption ''use of GeoIP databases. + Disabling this will disable by-country statistics for bridges and relays + and some client and third-party software functionality'' // { default = true; }; - Disabling this will disable by-country statistics for - bridges and relays and some client and third-party software - functionality. - ''; - }; - - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Extra configuration. Contents will be added verbatim to the - configuration file at the end. - ''; - }; - - controlPort = mkOption { - type = types.nullOr (types.either types.int types.str); - default = null; - example = 9051; - description = '' - If set, Tor will accept connections on the specified port - and allow them to control the tor process. - ''; - }; - - controlSocket = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable Tor control socket. Control socket is created - in <literal>${torRunDirectory}/control</literal> - ''; - }; - }; + controlSocket.enable = mkEnableOption ''control socket, + created in <literal>${runDir}/control</literal>''; client = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable Tor daemon to route application - connections. You might want to disable this if you plan - running a dedicated Tor relay. - ''; - }; + enable = mkEnableOption ''the routing of application connections. + You might want to disable this if you plan running a dedicated Tor relay''; - socksListenAddress = mkOption { - type = types.str; - default = "127.0.0.1:9050"; - example = "192.168.0.1:9100"; - description = '' - Bind to this address to listen for connections from - Socks-speaking applications. Provides strong circuit - isolation, separate circuit per IP address. - ''; - }; + transparentProxy.enable = mkEnableOption "transparent proxy"; + dns.enable = mkEnableOption "DNS resolver"; - socksListenAddressFaster = mkOption { - type = types.str; - default = "127.0.0.1:9063"; - example = "192.168.0.1:9101"; + socksListenAddress = mkOption { + type = optionSOCKSPort false; + default = {addr = "127.0.0.1"; port = 9050; IsolateDestAddr = true;}; + example = {addr = "192.168.0.1"; port = 9090; IsolateDestAddr = true;}; description = '' Bind to this address to listen for connections from - Socks-speaking applications. Same as - <option>socksListenAddress</option> but uses weaker - circuit isolation to provide performance suitable for a - web browser. - ''; - }; - - socksPolicy = mkOption { - type = types.nullOr types.str; - default = null; - example = "accept 192.168.0.0/16, reject *"; - description = '' - Entry policies to allow/deny SOCKS requests based on IP - address. First entry that matches wins. If no SocksPolicy - is set, we accept all (and only) requests from - <option>socksListenAddress</option>. + Socks-speaking applications. ''; }; - socksIsolationOptions = mkOption (isolationOptions // { - default = ["IsolateDestAddr"]; - }); - - transparentProxy = { - enable = mkOption { - type = types.bool; - default = false; - description = "Whether to enable tor transparent proxy"; - }; - - listenAddress = mkOption { - type = types.str; - default = "127.0.0.1:9040"; - example = "192.168.0.1:9040"; - description = '' - Bind transparent proxy to this address. - ''; - }; - - isolationOptions = mkOption isolationOptions; - }; - - dns = { - enable = mkOption { - type = types.bool; - default = false; - description = "Whether to enable tor dns resolver"; - }; - - listenAddress = mkOption { - type = types.str; - default = "127.0.0.1:9053"; - example = "192.168.0.1:9053"; - description = '' - Bind tor dns to this address. - ''; - }; - - isolationOptions = mkOption isolationOptions; - - automapHostsSuffixes = mkOption { - type = types.listOf types.str; - default = [".onion" ".exit"]; - example = [".onion"]; - description = "List of suffixes to use with automapHostsOnResolve"; + onionServices = mkOption { + description = descriptionGeneric "HiddenServiceDir"; + default = {}; + example = { + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" = { + clientAuthorizations = ["/run/keys/tor/alice.prv.x25519"]; + }; }; + type = types.attrsOf (types.submodule ({name, config, ...}: { + options.clientAuthorizations = mkOption { + description = '' + Clients' authorizations for a v3 hidden service, + as a list of files containing each one private key, in the format: + <screen>descriptor:x25519:<base32-private-key></screen> + '' + descriptionGeneric "_client_authorization"; + type = with types; listOf path; + default = []; + example = ["/run/keys/tor/alice.prv.x25519"]; + }; + })); }; }; relay = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable relaying TOR traffic for others. + enable = mkEnableOption ''relaying of Tor traffic for others. - See <link xlink:href="https://www.torproject.org/docs/tor-doc-relay" /> - for details. + See <link xlink:href="https://www.torproject.org/docs/tor-doc-relay" /> + for details. - Setting this to true requires setting - <option>services.tor.relay.role</option> - and - <option>services.tor.relay.port</option> - options. - ''; - }; + Setting this to true requires setting + <option>services.tor.relay.role</option> + and + <option>services.tor.settings.ORPort</option> + options''; role = mkOption { type = types.enum [ "exit" "relay" "bridge" "private-bridge" ]; @@ -310,13 +313,13 @@ in <important><para> Running an exit relay may expose you to abuse complaints. See - <link xlink:href="https://www.torproject.org/faq.html.en#ExitPolicies" /> + <link xlink:href="https://www.torproject.org/faq.html.en#ExitPolicies"/> for more info. </para></important> <para> You can specify which services Tor users may access via - your exit relay using <option>exitPolicy</option> option. + your exit relay using <option>settings.ExitPolicy</option> option. </para> </listitem> </varlistentry> @@ -369,15 +372,14 @@ in <important> <para> WARNING: THE FOLLOWING PARAGRAPH IS NOT LEGAL ADVICE. - Consult with your lawer when in doubt. + Consult with your lawyer when in doubt. </para> <para> This role should be safe to use in most situations (unless the act of forwarding traffic for others is a punishable offence under your local laws, which - would be pretty insane as it would make ISP - illegal). + would be pretty insane as it would make ISP illegal). </para> </important> @@ -404,7 +406,7 @@ in <para> Use this if you want to run a private bridge, for - example because you'll give out your bridge address + example because you'll give out your bridge addr manually to your friends. </para> @@ -426,269 +428,393 @@ in ''; }; - bridgeTransports = mkOption { - type = types.listOf types.str; - default = ["obfs4"]; - example = ["obfs2" "obfs3" "obfs4" "scramblesuit"]; - description = "List of pluggable transports"; - }; - - nickname = mkOption { - type = types.str; - default = "anonymous"; - description = '' - A unique handle for your TOR relay. - ''; - }; - - contactInfo = mkOption { - type = types.nullOr types.str; - default = null; - example = "admin@relay.com"; - description = '' - Contact information for the relay owner (e.g. a mail - address and GPG key ID). - ''; - }; - - accountingMax = mkOption { - type = types.nullOr types.str; - default = null; - example = "450 GBytes"; - description = '' - Specify maximum bandwidth allowed during an accounting period. This - allows you to limit overall tor bandwidth over some time period. - See the <literal>AccountingMax</literal> option by looking at the - tor manual <citerefentry><refentrytitle>tor</refentrytitle> - <manvolnum>1</manvolnum></citerefentry> for more. - - Note this limit applies individually to upload and - download; if you specify <literal>"500 GBytes"</literal> - here, then you may transfer up to 1 TBytes of overall - bandwidth (500 GB upload, 500 GB download). - ''; - }; - - accountingStart = mkOption { - type = types.nullOr types.str; - default = null; - example = "month 1 1:00"; - description = '' - Specify length of an accounting period. This allows you to limit - overall tor bandwidth over some time period. See the - <literal>AccountingStart</literal> option by looking at the tor - manual <citerefentry><refentrytitle>tor</refentrytitle> - <manvolnum>1</manvolnum></citerefentry> for more. - ''; - }; - - bandwidthRate = mkOption { - type = types.nullOr types.int; - default = null; - example = 100; - description = '' - Specify this to limit the bandwidth usage of relayed (server) - traffic. Your own traffic is still unthrottled. Units: bytes/second. - ''; - }; - - bandwidthBurst = mkOption { - type = types.nullOr types.int; - default = cfg.relay.bandwidthRate; - example = 200; - description = '' - Specify this to allow bursts of the bandwidth usage of relayed (server) - traffic. The average usage will still be as specified in relayBandwidthRate. - Your own traffic is still unthrottled. Units: bytes/second. - ''; - }; - - address = mkOption { - type = types.nullOr types.str; - default = null; - example = "noname.example.com"; - description = '' - The IP address or full DNS name for advertised address of your relay. - Leave unset and Tor will guess. - ''; - }; - - port = mkOption { - type = types.either types.int types.str; - example = 143; - description = '' - What port to advertise for Tor connections. This corresponds to the - <literal>ORPort</literal> section in the Tor manual; see - <citerefentry><refentrytitle>tor</refentrytitle> - <manvolnum>1</manvolnum></citerefentry> for more details. - - At a minimum, you should just specify the port for the - relay to listen on; a common one like 143, 22, 80, or 443 - to help Tor users who may have very restrictive port-based - firewalls. - ''; - }; - - exitPolicy = mkOption { - type = types.nullOr types.str; - default = null; - example = "accept *:6660-6667,reject *:*"; - description = '' - A comma-separated list of exit policies. They're - considered first to last, and the first match wins. If you - want to _replace_ the default exit policy, end this with - either a reject *:* or an accept *:*. Otherwise, you're - _augmenting_ (prepending to) the default exit policy. - Leave commented to just use the default, which is - available in the man page or at - <link xlink:href="https://www.torproject.org/documentation.html" />. - - Look at - <link xlink:href="https://www.torproject.org/faq-abuse.html#TypicalAbuses" /> - for issues you might encounter if you use the default - exit policy. - - If certain IPs and ports are blocked externally, e.g. by - your firewall, you should update your exit policy to - reflect this -- otherwise Tor users will be told that - those destinations are down. - ''; + onionServices = mkOption { + description = descriptionGeneric "HiddenServiceDir"; + default = {}; + example = { + "example.org/www" = { + map = [ 80 ]; + authorizedClients = [ + "descriptor:x25519:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + ]; + }; + }; + type = types.attrsOf (types.submodule ({name, config, ...}: { + options.path = mkOption { + type = types.path; + description = '' + Path where to store the data files of the hidden service. + If the <option>secretKey</option> is null + this defaults to <literal>${stateDir}/onion/$onion</literal>, + otherwise to <literal>${runDir}/onion/$onion</literal>. + ''; + }; + options.secretKey = mkOption { + type = with types; nullOr path; + default = null; + example = "/run/keys/tor/onion/expyuzz4wqqyqhjn/hs_ed25519_secret_key"; + description = '' + Secret key of the onion service. + If null, Tor reuses any preexisting secret key (in <option>path</option>) + or generates a new one. + The associated public key and hostname are deterministically regenerated + from this file if they do not exist. + ''; + }; + options.authorizeClient = mkOption { + description = descriptionGeneric "HiddenServiceAuthorizeClient"; + default = null; + type = types.nullOr (types.submodule ({...}: { + options = { + authType = mkOption { + type = types.enum [ "basic" "stealth" ]; + description = '' + Either <literal>"basic"</literal> for a general-purpose authorization protocol + or <literal>"stealth"</literal> for a less scalable protocol + that also hides service activity from unauthorized clients. + ''; + }; + clientNames = mkOption { + type = with types; nonEmptyListOf (strMatching "[A-Za-z0-9+-_]+"); + description = '' + Only clients that are listed here are authorized to access the hidden service. + Generated authorization data can be found in <filename>${stateDir}/onion/$name/hostname</filename>. + Clients need to put this authorization data in their configuration file using + <xref linkend="opt-services.tor.settings.HidServAuth"/>. + ''; + }; + }; + })); + }; + options.authorizedClients = mkOption { + description = '' + Authorized clients for a v3 hidden service, + as a list of public key, in the format: + <screen>descriptor:x25519:<base32-public-key></screen> + '' + descriptionGeneric "_client_authorization"; + type = with types; listOf str; + default = []; + example = ["descriptor:x25519:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"]; + }; + options.map = mkOption { + description = descriptionGeneric "HiddenServicePort"; + type = with types; listOf (oneOf [ + port (submodule ({...}: { + options = { + port = optionPort; + target = mkOption { + default = null; + type = nullOr (submodule ({...}: { + options = { + unix = optionUnix; + addr = optionAddress; + port = optionPort; + }; + })); + }; + }; + })) + ]); + apply = map (v: if isInt v then {port=v; target=null;} else v); + }; + options.version = mkOption { + description = descriptionGeneric "HiddenServiceVersion"; + type = with types; nullOr (enum [2 3]); + default = null; + }; + options.settings = mkOption { + description = '' + Settings of the onion service. + '' + descriptionGeneric "_hidden_service_options"; + default = {}; + type = types.submodule { + freeformType = with types; + (attrsOf (nullOr (oneOf [str int bool (listOf str)]))) // { + description = "settings option"; + }; + options.HiddenServiceAllowUnknownPorts = optionBool "HiddenServiceAllowUnknownPorts"; + options.HiddenServiceDirGroupReadable = optionBool "HiddenServiceDirGroupReadable"; + options.HiddenServiceExportCircuitID = mkOption { + description = descriptionGeneric "HiddenServiceExportCircuitID"; + type = with types; nullOr (enum ["haproxy"]); + default = null; + }; + options.HiddenServiceMaxStreams = mkOption { + description = descriptionGeneric "HiddenServiceMaxStreams"; + type = with types; nullOr (ints.between 0 65535); + default = null; + }; + options.HiddenServiceMaxStreamsCloseCircuit = optionBool "HiddenServiceMaxStreamsCloseCircuit"; + options.HiddenServiceNumIntroductionPoints = mkOption { + description = descriptionGeneric "HiddenServiceNumIntroductionPoints"; + type = with types; nullOr (ints.between 0 20); + default = null; + }; + options.HiddenServiceSingleHopMode = optionBool "HiddenServiceSingleHopMode"; + options.RendPostPeriod = optionString "RendPostPeriod"; + }; + }; + config = { + path = mkDefault ((if config.secretKey == null then stateDir else runDir) + "/onion/${name}"); + settings.HiddenServiceVersion = config.version; + settings.HiddenServiceAuthorizeClient = + if config.authorizeClient != null then + config.authorizeClient.authType + " " + + concatStringsSep "," config.authorizeClient.clientNames + else null; + settings.HiddenServicePort = map (p: mkValueString "" p.port + " " + mkValueString "" p.target) config.map; + }; + })); }; }; - hiddenServices = mkOption { + settings = mkOption { description = '' - A set of static hidden services that terminate their Tor - circuits at this node. - - Every element in this set declares a virtual onion host. - - You can specify your onion address by putting corresponding - private key to an appropriate place in ${torDirectory}. - - For services without private keys in ${torDirectory} Tor - daemon will generate random key pairs (which implies random - onion addresses) on restart. The latter could take a while, - please be patient. - - <note><para> - Hidden services can be useful even if you don't intend to - actually <emphasis>hide</emphasis> them, since they can - also be seen as a kind of NAT traversal mechanism. - - E.g. the example will make your sshd, whatever runs on - "8080" and your mail server available from anywhere where - the Tor network is available (which, with the help from - bridges, is pretty much everywhere), even if both client - and server machines are behind NAT you have no control - over. - </para></note> + See <link xlink:href="https://2019.www.torproject.org/docs/tor-manual.html.en">torrc manual</link> + for documentation. ''; default = {}; - example = literalExample '' - { "my-hidden-service-example".map = [ - { port = 22; } # map ssh port to this machine's ssh - { port = 80; toPort = 8080; } # map http port to whatever runs on 8080 - { port = "sip"; toHost = "mail.example.com"; toPort = "imap"; } # because we can - ]; - } - ''; - type = types.attrsOf (types.submodule ({name, ...}: { - options = { - - name = mkOption { - type = types.str; - description = '' - Name of this tor hidden service. - - This is purely descriptive. - - After restarting Tor daemon you should be able to - find your .onion address in - <literal>${torDirectory}/onion/$name/hostname</literal>. - ''; - }; - - map = mkOption { - default = []; - description = "Port mapping for this hidden service."; - type = types.listOf (types.submodule ({config, ...}: { - options = { - - port = mkOption { - type = types.either types.int types.str; - example = 80; - description = '' - Hidden service port to "bind to". - ''; - }; - - destination = mkOption { - internal = true; - type = types.str; - description = "Forward these connections where?"; - }; - - toHost = mkOption { - type = types.str; - default = "127.0.0.1"; - description = "Mapping destination host."; - }; - - toPort = mkOption { - type = types.either types.int types.str; - example = 8080; - description = "Mapping destination port."; - }; - - }; - - config = { - toPort = mkDefault config.port; - destination = mkDefault "${config.toHost}:${toString config.toPort}"; - }; - })); - }; - - authorizeClient = mkOption { - default = null; - description = "If configured, the hidden service is accessible for authorized clients only."; - type = types.nullOr (types.submodule ({...}: { - - options = { - - authType = mkOption { - type = types.enum [ "basic" "stealth" ]; - description = '' - Either <literal>"basic"</literal> for a general-purpose authorization protocol - or <literal>"stealth"</literal> for a less scalable protocol - that also hides service activity from unauthorized clients. - ''; - }; - - clientNames = mkOption { - type = types.nonEmptyListOf (types.strMatching "[A-Za-z0-9+-_]+"); - description = '' - Only clients that are listed here are authorized to access the hidden service. - Generated authorization data can be found in <filename>${torDirectory}/onion/$name/hostname</filename>. - Clients need to put this authorization data in their configuration file using <literal>HidServAuth</literal>. - ''; - }; - }; - })); - }; - - version = mkOption { - default = null; - description = "Rendezvous service descriptor version to publish for the hidden service. Currently, versions 2 and 3 are supported. (Default: 2)"; - type = types.nullOr (types.enum [ 2 3 ]); - }; + type = types.submodule { + freeformType = with types; + (attrsOf (nullOr (oneOf [str int bool (listOf str)]))) // { + description = "settings option"; + }; + options.Address = optionString "Address"; + options.AssumeReachable = optionBool "AssumeReachable"; + options.AccountingMax = optionBandwith "AccountingMax"; + options.AccountingStart = optionString "AccountingStart"; + options.AuthDirHasIPv6Connectivity = optionBool "AuthDirHasIPv6Connectivity"; + options.AuthDirListBadExits = optionBool "AuthDirListBadExits"; + options.AuthDirPinKeys = optionBool "AuthDirPinKeys"; + options.AuthDirSharedRandomness = optionBool "AuthDirSharedRandomness"; + options.AuthDirTestEd25519LinkKeys = optionBool "AuthDirTestEd25519LinkKeys"; + options.AuthoritativeDirectory = optionBool "AuthoritativeDirectory"; + options.AutomapHostsOnResolve = optionBool "AutomapHostsOnResolve"; + options.AutomapHostsSuffixes = optionStrings "AutomapHostsSuffixes" // { + default = [".onion" ".exit"]; + example = [".onion"]; }; - - config = { - name = mkDefault name; + options.BandwidthBurst = optionBandwith "BandwidthBurst"; + options.BandwidthRate = optionBandwith "BandwidthRate"; + options.BridgeAuthoritativeDir = optionBool "BridgeAuthoritativeDir"; + options.BridgeRecordUsageByCountry = optionBool "BridgeRecordUsageByCountry"; + options.BridgeRelay = optionBool "BridgeRelay" // { default = false; }; + options.CacheDirectory = optionPath "CacheDirectory"; + options.CacheDirectoryGroupReadable = optionBool "CacheDirectoryGroupReadable"; # default is null and like "auto" + options.CellStatistics = optionBool "CellStatistics"; + options.ClientAutoIPv6ORPort = optionBool "ClientAutoIPv6ORPort"; + options.ClientDNSRejectInternalAddresses = optionBool "ClientDNSRejectInternalAddresses"; + options.ClientOnionAuthDir = mkOption { + description = descriptionGeneric "ClientOnionAuthDir"; + default = null; + type = with types; nullOr path; + }; + options.ClientPreferIPv6DirPort = optionBool "ClientPreferIPv6DirPort"; # default is null and like "auto" + options.ClientPreferIPv6ORPort = optionBool "ClientPreferIPv6ORPort"; # default is null and like "auto" + options.ClientRejectInternalAddresses = optionBool "ClientRejectInternalAddresses"; + options.ClientUseIPv4 = optionBool "ClientUseIPv4"; + options.ClientUseIPv6 = optionBool "ClientUseIPv6"; + options.ConnDirectionStatistics = optionBool "ConnDirectionStatistics"; + options.ConstrainedSockets = optionBool "ConstrainedSockets"; + options.ContactInfo = optionString "ContactInfo"; + options.ControlPort = mkOption rec { + description = descriptionGeneric "ControlPort"; + default = []; + example = [{port = 9051;}]; + type = with types; oneOf [port (enum ["auto"]) (listOf (oneOf [ + port (enum ["auto"]) (submodule ({config, ...}: let + flags = ["GroupWritable" "RelaxDirModeCheck" "WorldWritable"]; + in { + options = { + unix = optionUnix; + flags = optionFlags; + addr = optionAddress; + port = optionPort; + } // genAttrs flags (name: mkOption { type = types.bool; default = false; }); + config = { + flags = filter (name: config.${name} == true) flags; + }; + })) + ]))]; + }; + options.ControlPortFileGroupReadable= optionBool "ControlPortFileGroupReadable"; + options.ControlPortWriteToFile = optionPath "ControlPortWriteToFile"; + options.ControlSocket = optionPath "ControlSocket"; + options.ControlSocketsGroupWritable = optionBool "ControlSocketsGroupWritable"; + options.CookieAuthFile = optionPath "CookieAuthFile"; + options.CookieAuthFileGroupReadable = optionBool "CookieAuthFileGroupReadable"; + options.CookieAuthentication = optionBool "CookieAuthentication"; + options.DataDirectory = optionPath "DataDirectory" // { default = stateDir; }; + options.DataDirectoryGroupReadable = optionBool "DataDirectoryGroupReadable"; + options.DirPortFrontPage = optionPath "DirPortFrontPage"; + options.DirAllowPrivateAddresses = optionBool "DirAllowPrivateAddresses"; + options.DormantCanceledByStartup = optionBool "DormantCanceledByStartup"; + options.DormantOnFirstStartup = optionBool "DormantOnFirstStartup"; + options.DormantTimeoutDisabledByIdleStreams = optionBool "DormantTimeoutDisabledByIdleStreams"; + options.DirCache = optionBool "DirCache"; + options.DirPolicy = mkOption { + description = descriptionGeneric "DirPolicy"; + type = with types; listOf str; + default = []; + example = ["accept *:*"]; + }; + options.DirPort = optionORPort "DirPort"; + options.DirReqStatistics = optionBool "DirReqStatistics"; + options.DisableAllSwap = optionBool "DisableAllSwap"; + options.DisableDebuggerAttachment = optionBool "DisableDebuggerAttachment"; + options.DisableNetwork = optionBool "DisableNetwork"; + options.DisableOOSCheck = optionBool "DisableOOSCheck"; + options.DNSPort = optionIsolablePorts "DNSPort"; + options.DoSCircuitCreationEnabled = optionBool "DoSCircuitCreationEnabled"; + options.DoSConnectionEnabled = optionBool "DoSConnectionEnabled"; # default is null and like "auto" + options.DoSRefuseSingleHopClientRendezvous = optionBool "DoSRefuseSingleHopClientRendezvous"; + options.DownloadExtraInfo = optionBool "DownloadExtraInfo"; + options.EnforceDistinctSubnets = optionBool "EnforceDistinctSubnets"; + options.EntryStatistics = optionBool "EntryStatistics"; + options.ExitPolicy = optionStrings "ExitPolicy" // { + default = ["reject *:*"]; + example = ["accept *:*"]; + }; + options.ExitPolicyRejectLocalInterfaces = optionBool "ExitPolicyRejectLocalInterfaces"; + options.ExitPolicyRejectPrivate = optionBool "ExitPolicyRejectPrivate"; + options.ExitPortStatistics = optionBool "ExitPortStatistics"; + options.ExitRelay = optionBool "ExitRelay"; # default is null and like "auto" + options.ExtORPort = mkOption { + description = descriptionGeneric "ExtORPort"; + default = null; + type = with types; nullOr (oneOf [ + port (enum ["auto"]) (submodule ({...}: { + options = { + addr = optionAddress; + port = optionPort; + }; + })) + ]); + apply = p: if isInt p || isString p then { port = p; } else p; }; - })); + options.ExtORPortCookieAuthFile = optionPath "ExtORPortCookieAuthFile"; + options.ExtORPortCookieAuthFileGroupReadable = optionBool "ExtORPortCookieAuthFileGroupReadable"; + options.ExtendAllowPrivateAddresses = optionBool "ExtendAllowPrivateAddresses"; + options.ExtraInfoStatistics = optionBool "ExtraInfoStatistics"; + options.FascistFirewall = optionBool "FascistFirewall"; + options.FetchDirInfoEarly = optionBool "FetchDirInfoEarly"; + options.FetchDirInfoExtraEarly = optionBool "FetchDirInfoExtraEarly"; + options.FetchHidServDescriptors = optionBool "FetchHidServDescriptors"; + options.FetchServerDescriptors = optionBool "FetchServerDescriptors"; + options.FetchUselessDescriptors = optionBool "FetchUselessDescriptors"; + options.ReachableAddresses = optionStrings "ReachableAddresses"; + options.ReachableDirAddresses = optionStrings "ReachableDirAddresses"; + options.ReachableORAddresses = optionStrings "ReachableORAddresses"; + options.GeoIPFile = optionPath "GeoIPFile"; + options.GeoIPv6File = optionPath "GeoIPv6File"; + options.GuardfractionFile = optionPath "GuardfractionFile"; + options.HidServAuth = mkOption { + description = descriptionGeneric "HidServAuth"; + default = []; + type = with types; listOf (oneOf [ + (submodule { + options = { + onion = mkOption { + type = strMatching "[a-z2-7]{16}(\\.onion)?"; + description = "Onion address."; + example = "xxxxxxxxxxxxxxxx.onion"; + }; + auth = mkOption { + type = strMatching "[A-Za-z0-9+/]{22}"; + description = "Authentication cookie."; + }; + }; + }) + ]); + }; + options.HiddenServiceNonAnonymousMode = optionBool "HiddenServiceNonAnonymousMode"; + options.HiddenServiceStatistics = optionBool "HiddenServiceStatistics"; + options.HSLayer2Nodes = optionStrings "HSLayer2Nodes"; + options.HSLayer3Nodes = optionStrings "HSLayer3Nodes"; + options.HTTPTunnelPort = optionIsolablePorts "HTTPTunnelPort"; + options.IPv6Exit = optionBool "IPv6Exit"; + options.KeyDirectory = optionPath "KeyDirectory"; + options.KeyDirectoryGroupReadable = optionBool "KeyDirectoryGroupReadable"; + options.LogMessageDomains = optionBool "LogMessageDomains"; + options.LongLivedPorts = optionPorts "LongLivedPorts"; + options.MainloopStats = optionBool "MainloopStats"; + options.MaxAdvertisedBandwidth = optionBandwith "MaxAdvertisedBandwidth"; + options.MaxCircuitDirtiness = optionInt "MaxCircuitDirtiness"; + options.MaxClientCircuitsPending = optionInt "MaxClientCircuitsPending"; + options.NATDPort = optionIsolablePorts "NATDPort"; + options.NewCircuitPeriod = optionInt "NewCircuitPeriod"; + options.Nickname = optionString "Nickname"; + options.ORPort = optionORPort "ORPort"; + options.OfflineMasterKey = optionBool "OfflineMasterKey"; + options.OptimisticData = optionBool "OptimisticData"; # default is null and like "auto" + options.PaddingStatistics = optionBool "PaddingStatistics"; + options.PerConnBWBurst = optionBandwith "PerConnBWBurst"; + options.PerConnBWRate = optionBandwith "PerConnBWRate"; + options.PidFile = optionPath "PidFile"; + options.ProtocolWarnings = optionBool "ProtocolWarnings"; + options.PublishHidServDescriptors = optionBool "PublishHidServDescriptors"; + options.PublishServerDescriptor = mkOption { + description = descriptionGeneric "PublishServerDescriptor"; + type = with types; nullOr (enum [false true 0 1 "0" "1" "v3" "bridge"]); + default = null; + }; + options.ReducedExitPolicy = optionBool "ReducedExitPolicy"; + options.RefuseUnknownExits = optionBool "RefuseUnknownExits"; # default is null and like "auto" + options.RejectPlaintextPorts = optionPorts "RejectPlaintextPorts"; + options.RelayBandwidthBurst = optionBandwith "RelayBandwidthBurst"; + options.RelayBandwidthRate = optionBandwith "RelayBandwidthRate"; + #options.RunAsDaemon + options.Sandbox = optionBool "Sandbox"; + options.ServerDNSAllowBrokenConfig = optionBool "ServerDNSAllowBrokenConfig"; + options.ServerDNSAllowNonRFC953Hostnames = optionBool "ServerDNSAllowNonRFC953Hostnames"; + options.ServerDNSDetectHijacking = optionBool "ServerDNSDetectHijacking"; + options.ServerDNSRandomizeCase = optionBool "ServerDNSRandomizeCase"; + options.ServerDNSResolvConfFile = optionPath "ServerDNSResolvConfFile"; + options.ServerDNSSearchDomains = optionBool "ServerDNSSearchDomains"; + options.ServerTransportPlugin = mkOption { + description = descriptionGeneric "ServerTransportPlugin"; + default = null; + type = with types; nullOr (submodule ({...}: { + options = { + transports = mkOption { + description = "List of pluggable transports."; + type = listOf str; + example = ["obfs2" "obfs3" "obfs4" "scramblesuit"]; + }; + exec = mkOption { + type = types.str; + description = "Command of pluggable transport."; + }; + }; + })); + }; + options.SocksPolicy = optionStrings "SocksPolicy" // { + example = ["accept *:*"]; + }; + options.SOCKSPort = mkOption { + description = descriptionGeneric "SOCKSPort"; + default = if cfg.settings.HiddenServiceNonAnonymousMode == true then [{port = 0;}] else []; + example = [{port = 9090;}]; + type = types.listOf (optionSOCKSPort true); + }; + options.TestingTorNetwork = optionBool "TestingTorNetwork"; + options.TransPort = optionIsolablePorts "TransPort"; + options.TransProxyType = mkOption { + description = descriptionGeneric "TransProxyType"; + type = with types; nullOr (enum ["default" "TPROXY" "ipfw" "pf-divert"]); + default = null; + }; + #options.TruncateLogFile + options.UnixSocksGroupWritable = optionBool "UnixSocksGroupWritable"; + options.UseDefaultFallbackDirs = optionBool "UseDefaultFallbackDirs"; + options.UseMicrodescriptors = optionBool "UseMicrodescriptors"; + options.V3AuthUseLegacyKey = optionBool "V3AuthUseLegacyKey"; + options.V3AuthoritativeDirectory = optionBool "V3AuthoritativeDirectory"; + options.VersioningAuthoritativeDirectory = optionBool "VersioningAuthoritativeDirectory"; + options.VirtualAddrNetworkIPv4 = optionString "VirtualAddrNetworkIPv4"; + options.VirtualAddrNetworkIPv6 = optionString "VirtualAddrNetworkIPv6"; + options.WarnPlaintextPorts = optionPorts "WarnPlaintextPorts"; + }; }; }; }; @@ -696,79 +822,217 @@ in config = mkIf cfg.enable { # Not sure if `cfg.relay.role == "private-bridge"` helps as tor # sends a lot of stats - warnings = optional (cfg.relay.enable && cfg.hiddenServices != {}) + warnings = optional (cfg.settings.BridgeRelay && + flatten (mapAttrsToList (n: o: o.map) cfg.relay.onionServices) != []) '' Running Tor hidden services on a public relay makes the presence of hidden services visible through simple statistical analysis of publicly available data. + See https://trac.torproject.org/projects/tor/ticket/8742 You can safely ignore this warning if you don't intend to actually hide your hidden services. In either case, you can always create a container/VM with a separate Tor daemon instance. - ''; + '' ++ + flatten (mapAttrsToList (n: o: + optional (o.settings.HiddenServiceVersion == 2) [ + (optional (o.settings.HiddenServiceExportCircuitID != null) '' + HiddenServiceExportCircuitID is used in the HiddenService: ${n} + but this option is only for v3 hidden services. + '') + ] ++ + optional (o.settings.HiddenServiceVersion != 2) [ + (optional (o.settings.HiddenServiceAuthorizeClient != null) '' + HiddenServiceAuthorizeClient is used in the HiddenService: ${n} + but this option is only for v2 hidden services. + '') + (optional (o.settings.RendPostPeriod != null) '' + RendPostPeriod is used in the HiddenService: ${n} + but this option is only for v2 hidden services. + '') + ] + ) cfg.relay.onionServices); users.groups.tor.gid = config.ids.gids.tor; users.users.tor = { description = "Tor Daemon User"; createHome = true; - home = torDirectory; + home = stateDir; group = "tor"; uid = config.ids.uids.tor; }; - # We have to do this instead of using RuntimeDirectory option in - # the service below because systemd has no way to set owners of - # RuntimeDirectory and putting this into the service below - # requires that service to relax it's sandbox since this needs - # writable /run - systemd.services.tor-init = - { description = "Tor Daemon Init"; - wantedBy = [ "tor.service" ]; - script = '' - install -m 0700 -o tor -g tor -d ${torDirectory} ${torDirectory}/onion - install -m 0750 -o tor -g tor -d ${torRunDirectory} - ''; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - }; + services.tor.settings = mkMerge [ + (mkIf cfg.enableGeoIP { + GeoIPFile = "${cfg.package.geoip}/share/tor/geoip"; + GeoIPv6File = "${cfg.package.geoip}/share/tor/geoip6"; + }) + (mkIf cfg.controlSocket.enable { + ControlPort = [ { unix = runDir + "/control"; GroupWritable=true; RelaxDirModeCheck=true; } ]; + }) + (mkIf cfg.relay.enable ( + optionalAttrs (cfg.relay.role != "exit") { + ExitPolicy = mkForce ["reject *:*"]; + } // + optionalAttrs (elem cfg.relay.role ["bridge" "private-bridge"]) { + BridgeRelay = true; + ExtORPort.port = mkDefault "auto"; + ServerTransportPlugin.transports = mkDefault ["obfs4"]; + ServerTransportPlugin.exec = mkDefault "${pkgs.obfs4}/bin/obfs4proxy managed"; + } // optionalAttrs (cfg.relay.role == "private-bridge") { + ExtraInfoStatistics = false; + PublishServerDescriptor = false; + } + )) + (mkIf (!cfg.relay.enable) { + # Avoid surprises when leaving ORPort/DirPort configurations in cfg.settings, + # because it would still enable Tor as a relay, + # which can trigger all sort of problems when not carefully done, + # like the blocklisting of the machine's IP addresses + # by some hosting providers... + DirPort = mkForce []; + ORPort = mkForce []; + PublishServerDescriptor = mkForce false; + }) + (mkIf cfg.client.enable ( + { SOCKSPort = [ cfg.client.socksListenAddress ]; + } // optionalAttrs cfg.client.transparentProxy.enable { + TransPort = [{ addr = "127.0.0.1"; port = 9040; }]; + } // optionalAttrs cfg.client.dns.enable { + DNSPort = [{ addr = "127.0.0.1"; port = 9053; }]; + AutomapHostsOnResolve = true; + AutomapHostsSuffixes = cfg.client.dns.automapHostsSuffixes; + } // optionalAttrs (flatten (mapAttrsToList (n: o: o.clientAuthorizations) cfg.client.onionServices) != []) { + ClientOnionAuthDir = runDir + "/ClientOnionAuthDir"; + } + )) + ]; - systemd.services.tor = - { description = "Tor Daemon"; - path = [ pkgs.tor ]; - - wantedBy = [ "multi-user.target" ]; - after = [ "tor-init.service" "network.target" ]; - restartTriggers = [ torRcFile ]; - - serviceConfig = - { Type = "simple"; - # Translated from the upstream contrib/dist/tor.service.in - ExecStartPre = "${cfg.package}/bin/tor -f ${torRcFile} --verify-config"; - ExecStart = "${cfg.package}/bin/tor -f ${torRcFile}"; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - KillSignal = "SIGINT"; - TimeoutSec = 30; - Restart = "on-failure"; - LimitNOFILE = 32768; - - # Hardening - # this seems to unshare /run despite what systemd.exec(5) says - PrivateTmp = mkIf (!cfg.controlSocket.enable) "yes"; - PrivateDevices = "yes"; - ProtectHome = "yes"; - ProtectSystem = "strict"; - InaccessiblePaths = "/home"; - ReadOnlyPaths = "/"; - ReadWritePaths = [ torDirectory torRunDirectory ]; - NoNewPrivileges = "yes"; - - # tor.service.in has this in, but this line it fails to spawn a namespace when using hidden services - #CapabilityBoundingSet = "CAP_SETUID CAP_SETGID CAP_NET_BIND_SERVICE"; - }; + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = + concatMap (o: optional (isInt o && o > 0 || o ? "port" && isInt o.port && o.port > 0) o.port) + (flatten [ + cfg.settings.ORPort + cfg.settings.DirPort + ]); + }; + + systemd.services.tor = { + description = "Tor Daemon"; + path = [ pkgs.tor ]; + + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + restartTriggers = [ torrc ]; + + serviceConfig = { + Type = "simple"; + User = "tor"; + Group = "tor"; + ExecStartPre = [ + "${cfg.package}/bin/tor -f ${torrc} --verify-config" + # DOC: Appendix G of https://spec.torproject.org/rend-spec-v3 + ("+" + pkgs.writeShellScript "ExecStartPre" (concatStringsSep "\n" (flatten (["set -eu"] ++ + mapAttrsToList (name: onion: + optional (onion.authorizedClients != []) '' + rm -rf ${escapeShellArg onion.path}/authorized_clients + install -d -o tor -g tor -m 0700 ${escapeShellArg onion.path} ${escapeShellArg onion.path}/authorized_clients + '' ++ + imap0 (i: pubKey: '' + echo ${pubKey} | + install -o tor -g tor -m 0400 /dev/stdin ${escapeShellArg onion.path}/authorized_clients/${toString i}.auth + '') onion.authorizedClients ++ + optional (onion.secretKey != null) '' + install -d -o tor -g tor -m 0700 ${escapeShellArg onion.path} + key="$(cut -f1 -d: ${escapeShellArg onion.secretKey})" + case "$key" in + ("== ed25519v"*"-secret") + install -o tor -g tor -m 0400 ${escapeShellArg onion.secretKey} ${escapeShellArg onion.path}/hs_ed25519_secret_key;; + (*) echo >&2 "NixOS does not (yet) support secret key type for onion: ${name}"; exit 1;; + esac + '' + ) cfg.relay.onionServices ++ + mapAttrsToList (name: onion: imap0 (i: prvKeyPath: + let hostname = removeSuffix ".onion" name; in '' + printf "%s:" ${escapeShellArg hostname} | cat - ${escapeShellArg prvKeyPath} | + install -o tor -g tor -m 0700 /dev/stdin \ + ${runDir}/ClientOnionAuthDir/${escapeShellArg hostname}.${toString i}.auth_private + '') onion.clientAuthorizations) + cfg.client.onionServices + )))) + ]; + ExecStart = "${cfg.package}/bin/tor -f ${torrc}"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + KillSignal = "SIGINT"; + TimeoutSec = 30; + Restart = "on-failure"; + LimitNOFILE = 32768; + RuntimeDirectory = [ + # g+x allows access to the control socket + "tor" + "tor/root" + # g+x can't be removed in ExecStart=, but will be removed by Tor + "tor/ClientOnionAuthDir" + ]; + RuntimeDirectoryMode = "0710"; + StateDirectoryMode = "0700"; + StateDirectory = [ + "tor" + "tor/onion" + ] ++ + flatten (mapAttrsToList (name: onion: + optional (onion.secretKey == null) "tor/onion/${name}" + ) cfg.relay.onionServices); + # The following options are only to optimize: + # systemd-analyze security tor + RootDirectory = runDir + "/root"; + RootDirectoryStartOnly = true; + #InaccessiblePaths = [ "-+${runDir}/root" ]; + UMask = "0066"; + BindPaths = [ stateDir ]; + BindReadOnlyPaths = [ storeDir "/etc" ]; + AmbientCapabilities = [""] ++ lib.optional bindsPrivilegedPort "CAP_NET_BIND_SERVICE"; + CapabilityBoundingSet = [""] ++ lib.optional bindsPrivilegedPort "CAP_NET_BIND_SERVICE"; + # ProtectClock= adds DeviceAllow=char-rtc r + DeviceAllow = ""; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateMounts = true; + PrivateNetwork = mkDefault false; + PrivateTmp = true; + # Tor cannot currently bind privileged port when PrivateUsers=true, + # see https://gitlab.torproject.org/legacy/trac/-/issues/20930 + PrivateUsers = !bindsPrivilegedPort; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectSystem = "strict"; + RemoveIPC = true; + RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + # See also the finer but experimental option settings.Sandbox + SystemCallFilter = [ + "@system-service" + # Groups in @system-service which do not contain a syscall listed by: + # perf stat -x, 2>perf.log -e 'syscalls:sys_enter_*' tor + # in tests, and seem likely not necessary for tor. + "~@aio" "~@chown" "~@keyring" "~@memlock" "~@resources" "~@setuid" "~@timer" + ]; + SystemCallArchitectures = "native"; + SystemCallErrorNumber = "EPERM"; }; + }; environment.systemPackages = [ cfg.package ]; }; + + meta.maintainers = with lib.maintainers; [ julm ]; } diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix index d720f254b8135..43b05c5b14d12 100644 --- a/nixos/modules/services/system/nscd.nix +++ b/nixos/modules/services/system/nscd.nix @@ -50,10 +50,20 @@ in systemd.services.nscd = { description = "Name Service Cache Daemon"; - wantedBy = [ "nss-lookup.target" "nss-user-lookup.target" ]; - environment = { LD_LIBRARY_PATH = nssModulesPath; }; + # We need system users to be resolveable in late-boot. nscd is the proxy between + # nss-modules in NixOS and thus if you have nss-modules providing system users + # (e.g. when using DynamicUser) then nscd needs to be available before late-boot is ready + # We add a dependency of sysinit.target to nscd to ensure + # these units are started after nscd is fully started. + unitConfig.DefaultDependencies = false; + wantedBy = [ "sysinit.target" ]; + before = [ "sysinit.target" "shutdown.target" ]; + conflicts = [ "shutdown.target" ]; + wants = [ "local-fs.target" ]; + after = [ "local-fs.target" ]; + restartTriggers = [ config.environment.etc.hosts.source config.environment.etc."nsswitch.conf".source @@ -66,20 +76,19 @@ in # privileges after all the NSS modules have read their configuration # files. So prefix the ExecStart command with "!" to prevent systemd # from dropping privileges early. See ExecStart in systemd.service(5). - serviceConfig = - { ExecStart = "!@${nscd}/sbin/nscd nscd"; - Type = "forking"; - DynamicUser = true; - RuntimeDirectory = "nscd"; - PIDFile = "/run/nscd/nscd.pid"; - Restart = "always"; - ExecReload = - [ "${nscd}/sbin/nscd --invalidate passwd" - "${nscd}/sbin/nscd --invalidate group" - "${nscd}/sbin/nscd --invalidate hosts" - ]; - }; + serviceConfig = { + ExecStart = "!@${nscd}/sbin/nscd nscd"; + Type = "forking"; + DynamicUser = true; + RuntimeDirectory = "nscd"; + PIDFile = "/run/nscd/nscd.pid"; + Restart = "always"; + ExecReload = [ + "${nscd}/sbin/nscd --invalidate passwd" + "${nscd}/sbin/nscd --invalidate group" + "${nscd}/sbin/nscd --invalidate hosts" + ]; + }; }; - }; } diff --git a/nixos/modules/services/web-servers/nginx/default.nix b/nixos/modules/services/web-servers/nginx/default.nix index 62671e9d74849..2bde2a68a6bc9 100644 --- a/nixos/modules/services/web-servers/nginx/default.nix +++ b/nixos/modules/services/web-servers/nginx/default.nix @@ -179,6 +179,12 @@ let ${cfg.httpConfig} }''} + ${optionalString (cfg.streamConfig != "") '' + stream { + ${cfg.streamConfig} + } + ''} + ${cfg.appendConfig} ''; @@ -452,6 +458,21 @@ in "; }; + streamConfig = mkOption { + type = types.lines; + default = ""; + example = '' + server { + listen 127.0.0.1:53 udp reuseport; + proxy_timeout 20s; + proxy_pass 192.168.0.1:53535; + } + ''; + description = " + Configuration lines to be set inside the stream block. + "; + }; + eventsConfig = mkOption { type = types.lines; default = ""; diff --git a/nixos/modules/system/activation/switch-to-configuration.pl b/nixos/modules/system/activation/switch-to-configuration.pl index b82d69b3bb853..c774be2ec5427 100644 --- a/nixos/modules/system/activation/switch-to-configuration.pl +++ b/nixos/modules/system/activation/switch-to-configuration.pl @@ -346,10 +346,11 @@ sub filterUnits { return @res; } +my $startNscd = delete $unitsToStart{"nscd.service"}; + my @unitsToStopFiltered = filterUnits(\%unitsToStop); my @unitsToStartFiltered = filterUnits(\%unitsToStart); - # Show dry-run actions. if ($action eq "dry-activate") { print STDERR "would stop the following units: ", join(", ", @unitsToStopFiltered), "\n" @@ -359,6 +360,7 @@ if ($action eq "dry-activate") { print STDERR "would restart systemd\n" if $restartSystemd; print STDERR "would restart the following units: ", join(", ", sort(keys %unitsToRestart)), "\n" if scalar(keys %unitsToRestart) > 0; + print STDERR "would start nscd\n" if $startNscd; print STDERR "would start the following units: ", join(", ", @unitsToStartFiltered), "\n" if scalar @unitsToStartFiltered; print STDERR "would reload the following units: ", join(", ", sort(keys %unitsToReload)), "\n" @@ -418,6 +420,13 @@ close $listActiveUsers; print STDERR "setting up tmpfiles\n"; system("@systemd@/bin/systemd-tmpfiles", "--create", "--remove", "--exclude-prefix=/dev") == 0 or $res = 3; +# We need to start nscd before any other service, since they might need +# to resolve users/groups only exposed by nss modules (i.e. DynamicUser via nss_systemd) +if ($startNscd) { + print STDERR "starting nscd\n"; + system("@systemd@/bin/systemctl", "start", "nscd.service") == 0 or $res = 4; +} + # Reload units that need it. This includes remounting changed mount # units. if (scalar(keys %unitsToReload) > 0) { diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index 86bfde6349c3d..e133a357bb768 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -366,7 +366,7 @@ let } trap cleanup EXIT - tmp=$(mktemp -d initrd-secrets.XXXXXXXXXX) + tmp=$(mktemp -d ''${TMPDIR:-/tmp}/initrd-secrets.XXXXXXXXXX) ${lib.concatStringsSep "\n" (mapAttrsToList (dest: source: let source' = if source == null then dest else toString source; in diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix index a055072f9c967..5388fc738e315 100644 --- a/nixos/modules/tasks/filesystems.nix +++ b/nixos/modules/tasks/filesystems.nix @@ -7,8 +7,9 @@ let addCheckDesc = desc: elemType: check: types.addCheck elemType check // { description = "${elemType.description} (with check: ${desc})"; }; - nonEmptyStr = addCheckDesc "non-empty" types.str - (x: x != "" && ! (all (c: c == " " || c == "\t") (stringToCharacters x))); + + isNonEmpty = s: (builtins.match ".*[^ \t]+.*" s) != null; + nonEmptyStr = addCheckDesc "non-empty" types.str isNonEmpty; fileSystems' = toposort fsBefore (attrValues config.fileSystems); @@ -28,10 +29,10 @@ let coreFileSystemOpts = { name, config, ... }: { options = { - mountPoint = mkOption { example = "/mnt/usb"; - type = nonEmptyStr; + type = addCheckDesc "non-empty without trailing slash" types.str + (s: isNonEmpty s && (builtins.match "(/|/.*[^/])" s) != null); description = "Location of the mounted the file system."; }; diff --git a/nixos/modules/virtualisation/amazon-image.nix b/nixos/modules/virtualisation/amazon-image.nix index 26297a7d0f1f7..4f83d72901c24 100644 --- a/nixos/modules/virtualisation/amazon-image.nix +++ b/nixos/modules/virtualisation/amazon-image.nix @@ -137,7 +137,7 @@ in services.openssh.permitRootLogin = "prohibit-password"; # Creates symlinks for block device names. - services.udev.packages = [ pkgs.ec2-utils ]; + services.udev.packages = [ pkgs.amazon-ec2-utils ]; # Force getting the hostname from EC2. networking.hostName = mkDefault ""; diff --git a/nixos/tests/tor.nix b/nixos/tests/tor.nix index ad07231557c3c..c061f59226cfb 100644 --- a/nixos/tests/tor.nix +++ b/nixos/tests/tor.nix @@ -17,7 +17,7 @@ rec { environment.systemPackages = with pkgs; [ netcat ]; services.tor.enable = true; services.tor.client.enable = true; - services.tor.controlPort = 9051; + services.tor.settings.ControlPort = 9051; }; testScript = '' diff --git a/pkgs/applications/networking/irc/weechat/scripts/wee-slack/0001-hardcode-json-file-path.patch b/pkgs/applications/networking/irc/weechat/scripts/wee-slack/0001-hardcode-json-file-path.patch new file mode 100644 index 0000000000000..45e620db258de --- /dev/null +++ b/pkgs/applications/networking/irc/weechat/scripts/wee-slack/0001-hardcode-json-file-path.patch @@ -0,0 +1,35 @@ +From 5dd2593369645b11a9dc03e1930617d2f5dbd039 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= <joerg@thalheim.io> +Date: Wed, 11 Nov 2020 11:48:49 +0100 +Subject: [PATCH] hardcode json file path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jörg Thalheim <joerg@thalheim.io> +--- + wee_slack.py | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/wee_slack.py b/wee_slack.py +index a3d779c..5942289 100644 +--- a/wee_slack.py ++++ b/wee_slack.py +@@ -5136,13 +5136,7 @@ def create_slack_debug_buffer(): + + def load_emoji(): + try: +- weechat_dir = w.info_get('weechat_dir', '') +- weechat_sharedir = w.info_get('weechat_sharedir', '') +- local_weemoji, global_weemoji = ('{}/weemoji.json'.format(path) +- for path in (weechat_dir, weechat_sharedir)) +- path = (global_weemoji if os.path.exists(global_weemoji) and +- not os.path.exists(local_weemoji) else local_weemoji) +- with open(path, 'r') as ef: ++ with open('@out@/share/wee-slack/weemoji.json', 'r') as ef: + emojis = json.loads(ef.read()) + if 'emoji' in emojis: + print_error('The weemoji.json file is in an old format. Please update it.') +-- +2.29.0 + diff --git a/pkgs/applications/networking/irc/weechat/scripts/wee-slack/default.nix b/pkgs/applications/networking/irc/weechat/scripts/wee-slack/default.nix index 9650f903ed6b6..4be611eb71ffe 100644 --- a/pkgs/applications/networking/irc/weechat/scripts/wee-slack/default.nix +++ b/pkgs/applications/networking/irc/weechat/scripts/wee-slack/default.nix @@ -2,13 +2,13 @@ stdenv.mkDerivation rec { pname = "wee-slack"; - version = "2.6.0"; + version = "8bd734c8e9a6b133a65548672f8a11ee3b3ce677"; src = fetchFromGitHub { repo = "wee-slack"; owner = "wee-slack"; - rev = "v${version}"; - sha256 = "0s4qd1z40c1bczkvc840jwjmzbv7nyj06xqs1si9v54qmkh4gaq4"; + rev = version; + sha256 = "0p48cpaqfqja9i68dqyladwif7x8c19ii8v27p9cxz5y9impc9qk"; }; patches = [ @@ -19,7 +19,7 @@ stdenv.mkDerivation rec { paths = with python3Packages; [ websocket_client six ]; }}/${python3Packages.python.sitePackages}"; }) - ./hardcode-json-file-path.patch + ./0001-hardcode-json-file-path.patch ]; postPatch = '' diff --git a/pkgs/applications/networking/irc/weechat/scripts/wee-slack/hardcode-json-file-path.patch b/pkgs/applications/networking/irc/weechat/scripts/wee-slack/hardcode-json-file-path.patch deleted file mode 100644 index 7413a9229ce65..0000000000000 --- a/pkgs/applications/networking/irc/weechat/scripts/wee-slack/hardcode-json-file-path.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- a/wee_slack.py -+++ b/wee_slack.py -@@ -4560,8 +4560,7 @@ - - def load_emoji(): - try: -- DIR = w.info_get('weechat_dir', '') -- with open('{}/weemoji.json'.format(DIR), 'r') as ef: -+ with open('@out@/share/wee-slack/weemoji.json', 'r') as ef: - emojis = json.loads(ef.read()) - if 'emoji' in emojis: - print_error('The weemoji.json file is in an old format. Please update it.') diff --git a/pkgs/applications/video/iina/default.nix b/pkgs/applications/video/iina/default.nix new file mode 100644 index 0000000000000..f0abed2d93d6b --- /dev/null +++ b/pkgs/applications/video/iina/default.nix @@ -0,0 +1,26 @@ +{ stdenv, fetchurl, undmg }: + +stdenv.mkDerivation { + pname = "iina"; + version = "1.1.2"; + + src = fetchurl { + url = "https://github.com/iina/iina/releases/download/v1.0.7-beta2/IINA.v1.0.7-beta2.dmg"; + sha256 = "1w0l3b1kar9zglqkildcqhlwara6zy2p3x79kqa2d0b43nqka82n"; + }; + + buildInputs = [ undmg ]; + installPhase = '' + mkdir -p "$out/Applications/IINA.app" + cp -R . "$out/Applications/IINA.app" + chmod +x "$out/Applications/IINA.app/Contents/MacOS/IINA" + ''; + + meta = with stdenv.lib; { + description = "The modern video player for macOS."; + homepage = "http://https://iina.io/"; + license = licenses.gpl3; + platforms = platforms.darwin; + maintainers = with maintainers; [ mic92 ]; + }; +} diff --git a/pkgs/development/python-modules/keystone/default.nix b/pkgs/development/python-modules/keystone/default.nix new file mode 100644 index 0000000000000..c98af6ea4d7d7 --- /dev/null +++ b/pkgs/development/python-modules/keystone/default.nix @@ -0,0 +1,16 @@ +{ lib +, buildPythonPackage +, keystone +}: + +buildPythonPackage rec { + inherit (keystone) pname src version buildInputs nativeBuildInputs; + + dontUseCmakeConfigure = 1; + preBuild = "cd bindings/python"; + + meta = with lib; { + inherit (keystone.meta) description license homepage; + maintainers = [ maintainers.mic92 ]; + }; +} diff --git a/pkgs/development/python-modules/pyworld/default.nix b/pkgs/development/python-modules/pyworld/default.nix new file mode 100644 index 0000000000000..92a91f766be75 --- /dev/null +++ b/pkgs/development/python-modules/pyworld/default.nix @@ -0,0 +1,31 @@ +{ lib +, buildPythonPackage +, fetchPypi +, numpy +, cython +}: + +buildPythonPackage rec { + pname = "pyworld"; + version = "0.2.12"; + + src = fetchPypi { + inherit pname version; + sha256 = "896c910696975855578d855f490f94d7a57119e0a75f7f15e11fdf58ba891627"; + }; + + nativeBuildInputs = [ + cython + ]; + + propagatedBuildInputs = [ + numpy + ]; + + meta = with lib; { + description = "PyWorld is a Python wrapper for WORLD vocoder"; + homepage = https://github.com/JeremyCCHsu/Python-Wrapper-for-World-Vocoder; + license = licenses.mit; + maintainers = [ maintainers.mic92 ]; + }; +} diff --git a/pkgs/development/ruby-modules/with-packages/Gemfile b/pkgs/development/ruby-modules/with-packages/Gemfile index 3454ce3df74b9..dda0f69c35cc6 100644 --- a/pkgs/development/ruby-modules/with-packages/Gemfile +++ b/pkgs/development/ruby-modules/with-packages/Gemfile @@ -14,13 +14,9 @@ source 'https://rubygems.org' do gem 'cocoapods' gem 'cocoapods-acknowledgements' gem 'cocoapods-art' - gem 'cocoapods-bin' gem 'cocoapods-browser' - gem 'cocoapods-bugsnag' - gem 'cocoapods-check' gem 'cocoapods-clean' gem 'cocoapods-clean_build_phases_scripts' - gem 'cocoapods-core' gem 'cocoapods-coverage' gem 'cocoapods-deintegrate' gem 'cocoapods-dependencies' @@ -31,18 +27,9 @@ source 'https://rubygems.org' do gem 'cocoapods-generate' gem 'cocoapods-git_url_rewriter' gem 'cocoapods-keys' - gem 'cocoapods-no-dev-schemes' gem 'cocoapods-open' - gem 'cocoapods-packager' - gem 'cocoapods-playgrounds' gem 'cocoapods-plugins' - gem 'cocoapods-prune-localizations' - gem 'cocoapods-rome' gem 'cocoapods-search' - gem 'cocoapods-sorted-search' - gem 'cocoapods-static-swift-framework' - gem 'cocoapods-stats' - gem 'cocoapods-tdfire-binary' gem 'cocoapods-testing' gem 'cocoapods-trunk' gem 'cocoapods-try' diff --git a/pkgs/os-specific/linux/sysdig/default.nix b/pkgs/os-specific/linux/sysdig/default.nix index 0f8702eb6e01a..5f4d638dfece3 100644 --- a/pkgs/os-specific/linux/sysdig/default.nix +++ b/pkgs/os-specific/linux/sysdig/default.nix @@ -65,7 +65,7 @@ stdenv.mkDerivation rec { description = "A tracepoint-based system tracing tool for Linux (with clients for other OSes)"; license = with licenses; [ asl20 gpl2 mit ]; maintainers = [maintainers.raskin]; - platforms = ["x86_64-linux"] ++ platforms.darwin; + platforms = [ "x86_64-linux" "aarch64-linux" ] ++ platforms.darwin; broken = kernel != null && versionOlder kernel.version "4.14"; homepage = "https://sysdig.com/opensource/"; downloadPage = "https://github.com/draios/sysdig/releases"; diff --git a/pkgs/servers/home-assistant/component-packages.nix b/pkgs/servers/home-assistant/component-packages.nix index 9135ea549f34e..429f140f738f5 100644 --- a/pkgs/servers/home-assistant/component-packages.nix +++ b/pkgs/servers/home-assistant/component-packages.nix @@ -243,7 +243,7 @@ "familyhub" = ps: with ps; [ ]; # missing inputs: python-family-hub-local "fan" = ps: with ps; [ ]; "fastdotcom" = ps: with ps; [ ]; # missing inputs: fastdotcom - "feedreader" = ps: with ps; [ ]; # missing inputs: feedparser-homeassistant + "feedreader" = ps: with ps; [ feedparser]; "ffmpeg" = ps: with ps; [ ha-ffmpeg ]; "ffmpeg_motion" = ps: with ps; [ ha-ffmpeg ]; "ffmpeg_noise" = ps: with ps; [ ha-ffmpeg ]; diff --git a/pkgs/servers/home-assistant/parse-requirements.py b/pkgs/servers/home-assistant/parse-requirements.py index 4fa4b8a48ee43..3d25dfeaf8476 100755 --- a/pkgs/servers/home-assistant/parse-requirements.py +++ b/pkgs/servers/home-assistant/parse-requirements.py @@ -41,6 +41,10 @@ PKG_PREFERENCES = { "tensorflow-build_2": "tensorflow", } +# packages we have a different name for or we want to replace +PKG_SUBSTITUTES = { + "feedparser-homeassistant": "feedparser" +} def run_mypy() -> None: cmd = ["mypy", "--ignore-missing-imports", __file__] @@ -156,6 +160,8 @@ def main() -> None: # Therefore, if there's a "#" in the line, only take the part after it req = req[req.find("#") + 1 :] name = req.split("==")[0] + name = PKG_SUBSTITUTES.get(name, name) + attr_path = name_to_attr_path(name, packages) if attr_path is not None: # Add attribute path without "python3Packages." prefix diff --git a/pkgs/servers/openafs/1.8/default.nix b/pkgs/servers/openafs/1.8/default.nix index c26f8d3a23c50..1f475d7440fac 100644 --- a/pkgs/servers/openafs/1.8/default.nix +++ b/pkgs/servers/openafs/1.8/default.nix @@ -100,6 +100,7 @@ in stdenv.mkDerivation { homepage = "https://www.openafs.org"; license = licenses.ipl10; platforms = platforms.linux; + broken = with kernel; kernelOlder "3.18" || isHardened; maintainers = [ maintainers.maggesi maintainers.spacefrogg ]; }; } diff --git a/pkgs/tools/audio/tts/default.nix b/pkgs/tools/audio/tts/default.nix index 770e898f2eec5..1634bfa5b3071 100644 --- a/pkgs/tools/audio/tts/default.nix +++ b/pkgs/tools/audio/tts/default.nix @@ -61,6 +61,18 @@ python3Packages.buildPythonApplication rec { url = "https://github.com/mozilla/TTS/commit/36fee428b9f3f4ec1914b090a2ec9d785314d9aa.patch"; sha256 = "sha256-pP0NxiyrsvQ0A7GEleTdT87XO08o7WxPEpb6Bmj66dc="; }) + (fetchpatch { + url = "https://github.com/Mic92/TTS/commit/5bf62009e8c19e8c1627d1f7aa54e11bc5fa91d7.patch"; + sha256 = "sha256-ZxDytieD0zoP0/RXzG0bbVnl0oE+DF8iUVpHb8+2TqM="; + }) + (fetchpatch { + url = "https://github.com/mozilla/TTS/commit/3000647e542fce9773f4c5da082630befa5525f1.patch"; + sha256 = "sha256-dl8Zy0dEw9z4ZZFcuP1WHzCVh2+nn0jDKOncoCK+syM="; + }) + (fetchpatch { + url = "https://github.com/mozilla/TTS/commit/fe86a076bb1c7e18078718be0aa36da427f325bd.patch"; + sha256 = "sha256-cT5HYkLFzmSMwAHLOHgpG+v9HGKIbUxwS8Dt9SKHm+8="; + }) ]; preBuild = '' @@ -95,6 +107,7 @@ python3Packages.buildPythonApplication rec { inflect gdown pysbd + pyworld ]; postInstall = '' diff --git a/pkgs/tools/security/tor/default.nix b/pkgs/tools/security/tor/default.nix index 04bf598d132aa..e46fd4790a31f 100644 --- a/pkgs/tools/security/tor/default.nix +++ b/pkgs/tools/security/tor/default.nix @@ -1,5 +1,6 @@ { stdenv, fetchurl, pkgconfig, libevent, openssl, zlib, torsocks , libseccomp, systemd, libcap, lzma, zstd, scrypt, nixosTests +, writeShellScript # for update.nix , writeScript @@ -12,7 +13,21 @@ , gnused , nix }: - +let + tor-client-auth-gen = writeShellScript "tor-client-auth-gen" '' + PATH="${stdenv.lib.makeBinPath [coreutils gnugrep openssl]}" + pem="$(openssl genpkey -algorithm x25519)" + + printf private_key=descriptor:x25519: + echo "$pem" | grep -v " PRIVATE KEY" | + base64 -d | tail --bytes=32 | base32 | tr -d = + + printf public_key=descriptor:x25519: + echo "$pem" | openssl pkey -in /dev/stdin -pubout | + grep -v " PUBLIC KEY" | + base64 -d | tail --bytes=32 | base32 | tr -d = + ''; +in stdenv.mkDerivation rec { pname = "tor"; version = "0.4.4.6"; @@ -52,6 +67,7 @@ stdenv.mkDerivation rec { mkdir -p $geoip/share/tor mv $out/share/tor/geoip{,6} $geoip/share/tor rm -rf $out/share/tor + ln -s ${tor-client-auth-gen} $out/bin/tor-client-auth-gen ''; passthru = { diff --git a/pkgs/tools/typesetting/tex/texlive/bin.nix b/pkgs/tools/typesetting/tex/texlive/bin.nix index 030ac1b43aae7..4df486a251177 100644 --- a/pkgs/tools/typesetting/tex/texlive/bin.nix +++ b/pkgs/tools/typesetting/tex/texlive/bin.nix @@ -2,7 +2,7 @@ , texlive , zlib, libiconv, libpng, libX11 , freetype, gd, libXaw, icu, ghostscript, libXpm, libXmu, libXext -, perl, perlPackages, python2Packages, pkgconfig +, perl, perlPackages, python3Packages, pkgconfig , poppler, libpaper, graphite2, zziplib, harfbuzz, potrace, gmp, mpfr , brotli, cairo, pixman, xorg, clisp, biber, woff2, xxHash , makeWrapper, shortenPerlShebang @@ -321,13 +321,13 @@ latexindent = perlPackages.buildPerlPackage rec { }; -pygmentex = python2Packages.buildPythonApplication rec { +pygmentex = python3Packages.buildPythonApplication rec { pname = "pygmentex"; inherit (src) version; src = stdenv.lib.head (builtins.filter (p: p.tlType == "run") texlive.pygmentex.pkgs); - propagatedBuildInputs = with python2Packages; [ pygments chardet ]; + propagatedBuildInputs = with python3Packages; [ pygments chardet ]; dontBuild = true; diff --git a/pkgs/tools/typesetting/tex/texlive/combine.nix b/pkgs/tools/typesetting/tex/texlive/combine.nix index 0625fe16090a3..33633433575b1 100644 --- a/pkgs/tools/typesetting/tex/texlive/combine.nix +++ b/pkgs/tools/typesetting/tex/texlive/combine.nix @@ -27,7 +27,7 @@ let [ "de-macro" "pythontex" "dviasm" "texliveonfly" ]; pkgNeedsRuby = pkg: pkg.tlType == "run" && pkg.pname == "match-parens"; extraInputs = - lib.optional (lib.any pkgNeedsPython splitBin.wrong) python + lib.optional (lib.any pkgNeedsPython splitBin.wrong) python3 ++ lib.optional (lib.any pkgNeedsRuby splitBin.wrong) ruby; }; diff --git a/pkgs/tools/typesetting/tex/texlive/default.nix b/pkgs/tools/typesetting/tex/texlive/default.nix index c2e6399ab864e..0c7dadc150b02 100644 --- a/pkgs/tools/typesetting/tex/texlive/default.nix +++ b/pkgs/tools/typesetting/tex/texlive/default.nix @@ -4,7 +4,7 @@ */ { stdenv, lib, fetchurl, runCommand, writeText, buildEnv , callPackage, ghostscriptX, harfbuzz, poppler_min -, makeWrapper, python, ruby, perl +, makeWrapper, python3, ruby, perl , useFixedHashes ? true , recurseIntoAttrs }: @@ -25,7 +25,7 @@ let # function for creating a working environment from a set of TL packages combine = import ./combine.nix { inherit bin combinePkgs buildEnv lib makeWrapper writeText - stdenv python ruby perl; + stdenv python3 ruby perl; ghostscript = ghostscriptX; # could be without X, probably, but we use X above }; @@ -110,7 +110,7 @@ let #"ftp://tug.org/texlive/historic/2019/tlnet-final/archive" # Daily snapshots hosted by one of the texlive release managers - https://texlive.info/tlnet-archive/2020/10/09/tlnet/archive + "https://texlive.info/tlnet-archive/2020/10/09/tlnet/archive" ]; src = fetchurl { inherit urls sha512; }; diff --git a/pkgs/tools/virtualization/amazon-ec2-utils/default.nix b/pkgs/tools/virtualization/amazon-ec2-utils/default.nix new file mode 100644 index 0000000000000..d7dd6ad0b1e3a --- /dev/null +++ b/pkgs/tools/virtualization/amazon-ec2-utils/default.nix @@ -0,0 +1,42 @@ +{ stdenv, lib, fetchFromGitHub, python3, installShellFiles }: + +stdenv.mkDerivation rec { + pname = "amazon-ec2-utils"; + version = "1.3"; + + src = fetchFromGitHub { + owner = "aws"; + repo = "amazon-ec2-utils"; + rev = version; + sha256 = "sha256-uxKnbdKGhS32kY3mA7YYtDRwKcEjNZPJUYQExZTqtxE="; + }; + + buildInputs = [ python3 ]; + # TODO next version will have manpages + #nativeBuildInputs = [ installShellFiles ]; + + installPhase = '' + # https://github.com/aws/amazon-ec2-utils/blob/8eb2effb1aea2280264d66ae58b3e156e6d429f9/amazon-ec2-utils.spec#L74 + install -D --target $out/etc/udev/rules.d *.rules + install -D --target $out/bin ec2-metadata ebsnvme-id ec2udev-vbd ec2udev-vcpu + install -D --target $out/lib/udev/ ec2nvme-nsid + # TODO next version will have manpages + #installManPage doc/* + ''; + + postFixup = '' + for i in $out/etc/udev/rules.d/*.rules; do + substituteInPlace "$i" \ + --replace '/sbin' "$out/bin" + done + substituteInPlace "$out/etc/udev/rules.d/70-ec2-nvme-devices.rules" \ + --replace 'ec2nvme-nsid' "$out/lib/udev/ec2nvme-nsid" + ''; + + meta = { + description = "A set of tools for running in EC2"; + homepage = "https://aws.amazon.com/amazon-linux-ami/"; + license = lib.licenses.asl20; + maintainers = with lib.maintainers; [ thefloweringash ]; + }; +} diff --git a/pkgs/tools/virtualization/ec2-utils/default.nix b/pkgs/tools/virtualization/ec2-utils/default.nix deleted file mode 100644 index 1605bcfa43b67..0000000000000 --- a/pkgs/tools/virtualization/ec2-utils/default.nix +++ /dev/null @@ -1,47 +0,0 @@ -{ stdenv, lib, rpmextract, fetchurl, python2, tree }: - -stdenv.mkDerivation { - name = "ec2-utils"; - version = "0.5.1"; - - # The url can be determined by booting an "Amazon Linux 2" and running: - # > yumdownloader --urls ec2-utils - src = fetchurl { - url = "http://amazonlinux.ap-northeast-1.amazonaws.com/blobstore/a3b4d2c35c2300518fe10381a05b3bd7936ff5cdd3d351143a11bf84073d9e00/ec2-utils-0.5-1.amzn2.0.1.noarch.rpm"; - sha256 = "004y7l3q9gqi78a53lykrpsnz4yp7dds1083w67m2013bk1x5d53"; - }; - - nativeBuildInputs = [ rpmextract ]; - - buildInputs = [ python2 ]; - - unpackPhase = '' - mkdir source - cd source - rpmextract "$src" - ''; - - installPhase = '' - mkdir $out - - mv --target-directory $out \ - etc sbin usr/bin usr/lib - ''; - - postFixup = '' - for i in $out/etc/udev/rules.d/*.rules; do - substituteInPlace "$i" \ - --replace '/sbin' "$out/bin" - done - - substituteInPlace "$out/etc/udev/rules.d/70-ec2-nvme-devices.rules" \ - --replace 'ec2nvme-nsid' "$out/lib/udev/ec2nvme-nsid" - ''; - - meta = { - description = "A set of tools for running in EC2"; - homepage = "https://aws.amazon.com/amazon-linux-ami/"; - license = lib.licenses.asl20; - maintainers = with lib.maintainers; [ thefloweringash ]; - }; -} diff --git a/pkgs/top-level/aliases.nix b/pkgs/top-level/aliases.nix index 6e5da1bf34ec1..793b58ac46da8 100644 --- a/pkgs/top-level/aliases.nix +++ b/pkgs/top-level/aliases.nix @@ -138,6 +138,7 @@ mapAliases ({ draftsight = throw "draftsight has been removed, no longer available as freeware"; # added 2020-08-14 dvb_apps = throw "dvb_apps has been removed."; # added 2020-11-03 dwarf_fortress = dwarf-fortress; # added 2016-01-23 + ec2-utils = amazon-ec2-utils; # added 2020-12-06 emacsPackagesGen = emacsPackagesFor; # added 2018-08-18 emacsPackagesNgGen = emacsPackagesFor; # added 2018-08-18 emacsPackagesNgFor = emacsPackagesFor; # added 2019-08-07 diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index dd9a10067758a..9746863371802 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -1005,7 +1005,7 @@ in ec2_ami_tools = callPackage ../tools/virtualization/ec2-ami-tools { }; - ec2-utils = callPackage ../tools/virtualization/ec2-utils { }; + amazon-ec2-utils = callPackage ../tools/virtualization/amazon-ec2-utils { }; exoscale-cli = callPackage ../tools/admin/exoscale-cli { }; @@ -21305,6 +21305,8 @@ in icesl = callPackage ../applications/misc/icesl { }; + iina = callPackage ../applications/video/iina { }; + keepassx = callPackage ../applications/misc/keepassx { }; keepassx2 = callPackage ../applications/misc/keepassx/2.0.nix { }; keepassxc = libsForQt5.callPackage ../applications/misc/keepassx/community.nix { }; diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index 7ba80903ccd54..5a9a58d1b2605 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -3312,6 +3312,10 @@ in { keyrings-alt = callPackage ../development/python-modules/keyrings-alt { }; + keystone = callPackage ../development/python-modules/keystone { + inherit (pkgs) keystone; + }; + keyutils = callPackage ../development/python-modules/keyutils { inherit (pkgs) keyutils; }; kicad = disabledIf isPy27 (toPythonModule (pkgs.kicad.override { python3 = python; }).src); @@ -6216,6 +6220,8 @@ in { }); in if isPy3k then pyxattr' else pyxattr_2; + pyworld = callPackage ../development/python-modules/pyworld { }; + pyx = callPackage ../development/python-modules/pyx { }; pyxdg = callPackage ../development/python-modules/pyxdg { }; diff --git a/pkgs/top-level/ruby-packages.nix b/pkgs/top-level/ruby-packages.nix index ef82be30b620a..33a50e232d0ef 100644 --- a/pkgs/top-level/ruby-packages.nix +++ b/pkgs/top-level/ruby-packages.nix @@ -1,14 +1,36 @@ { + actioncable = { + dependencies = ["actionpack" "nio4r" "websocket-driver"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0y3aa0965cdsqamxk8ac6brcvijl1zv4pvqils6xy3pbcrv0ljid"; + type = "gem"; + }; + version = "6.0.3.4"; + }; + actionmailbox = { + dependencies = ["actionpack" "activejob" "activerecord" "activestorage" "activesupport" "mail"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "10vb9s4frq22h5j6gyw2598k1jc29lg2czm95hf284l3mi4qly6a"; + type = "gem"; + }; + version = "6.0.3.4"; + }; actionmailer = { dependencies = ["actionpack" "actionview" "activejob" "mail" "rails-dom-testing"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "18wwlj4f7jffv3vxm80d2z36nwza95l5xfcqc401hvvrls4xzhsy"; + sha256 = "1ykn5qkwdlcv5aa1gjhhmrxpjccwa7df6n4amvkmvxv5lggyma52"; type = "gem"; }; - version = "4.2.11.1"; + version = "6.0.3.4"; }; actionpack = { dependencies = ["actionview" "activesupport" "rack" "rack-test" "rails-dom-testing" "rails-html-sanitizer"]; @@ -16,107 +38,108 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0rmldsk3a4lwxk0lrp6x1nz1v1r2xmbm3300l4ghgfygv3grdwjh"; + sha256 = "0fbjpnh5hrihc9l35q9why6ip0hcdj42axzbp6b4j1xcy1v1bicj"; type = "gem"; }; - version = "4.2.11.1"; + version = "6.0.3.4"; }; - actionview = { - dependencies = ["activesupport" "builder" "erubis" "rails-dom-testing" "rails-html-sanitizer"]; + actiontext = { + dependencies = ["actionpack" "activerecord" "activestorage" "activesupport" "nokogiri"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0x7vjn8q6blzyf7j3kwg0ciy7vnfh28bjdkd1mp9k4ghp9jn0g9p"; + sha256 = "0r0j0m76ynjspmvj5qbzl06kl9i920v269iz62y62009xydv6rqz"; type = "gem"; }; - version = "4.2.11.1"; + version = "6.0.3.4"; }; - activejob = { - dependencies = ["activesupport" "globalid"]; + actionview = { + dependencies = ["activesupport" "builder" "erubi" "rails-dom-testing" "rails-html-sanitizer"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0jy1c1r6syjqpa0sh9f1p4iaxzvp6qg4n6zs774j9z27q7h407mj"; + sha256 = "0gdz31cq08nrqq6bxqim2qcbzv0fr34z6ycl73dmawpafj33wdkj"; type = "gem"; }; - version = "4.2.11.1"; + version = "6.0.3.4"; }; - activemodel = { - dependencies = ["activesupport" "builder"]; + activejob = { + dependencies = ["activesupport" "globalid"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1c1x0rd6wnk1f0gsmxs6x3gx7yf6fs9qqkdv7r4hlbcdd849in33"; + sha256 = "0d0p8gjplrgym38dmchyzhv7lrrxngz0yrxl6xyvwxfxm1hgdk2k"; type = "gem"; }; - version = "4.2.11.1"; + version = "6.0.3.4"; }; - activerecord = { - dependencies = ["activemodel" "activesupport" "arel"]; + activemodel = { + dependencies = ["activesupport"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "07ixiwi0zzs9skqarvpfamsnay7npfswymrn28ngxaf8hi279q5p"; + sha256 = "00jj8namy5niq7grl5lrsr4y351rxpj1b69k1i9gvb1hnpghl099"; type = "gem"; }; - version = "4.2.11.1"; + version = "6.0.3.4"; }; - activesupport = { - dependencies = ["i18n" "minitest" "thread_safe" "tzinfo"]; + activerecord = { + dependencies = ["activemodel" "activesupport"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1vbq7a805bfvyik2q3kl9s3r418f5qzvysqbz2cwy4hr7m2q4ir6"; + sha256 = "06qvvp73z8kq9sd2mhw6p9124q5pfkswjga2fidz4c73zbr79r3g"; type = "gem"; }; - version = "4.2.11.1"; + version = "6.0.3.4"; }; - addressable = { - dependencies = ["public_suffix"]; + activestorage = { + dependencies = ["actionpack" "activejob" "activerecord" "marcel"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1fvchp2rhp2rmigx7qglf69xvjqvzq7x0g49naliw29r2bz656sy"; + sha256 = "0q734331wb7cfsh4jahj3lphpxvglzb17yvibwss1ml4g01xxm52"; type = "gem"; }; - version = "2.7.0"; + version = "6.0.3.4"; }; - algoliasearch = { - dependencies = ["httpclient" "json"]; + activesupport = { + dependencies = ["concurrent-ruby" "i18n" "minitest" "tzinfo" "zeitwerk"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1ayg8j3819ay2d8618jv32ca16fh8qsgjsiq9j32yd016c170nkj"; + sha256 = "1axidc4mikgi4yxs0ynw2c54jyrs5lxprxmzv6m3aayi9rg6rk5j"; type = "gem"; }; - version = "1.27.1"; + version = "6.0.3.4"; }; - arel = { + addressable = { + dependencies = ["public_suffix"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0nfcrdiys6q6ylxiblky9jyssrw2xj96fmxmal7f4f0jj3417vj4"; + sha256 = "1fvchp2rhp2rmigx7qglf69xvjqvzq7x0g49naliw29r2bz656sy"; type = "gem"; }; - version = "6.0.4"; + version = "2.7.0"; }; ast = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "184ssy3w93nkajlz2c70ifm79jp3j737294kbc5fjw69v1w0n9x7"; + sha256 = "1l3468czzjmxl93ap40hp7z94yxp4nbag0bxqs789bm30md90m2a"; type = "gem"; }; - version = "2.4.0"; + version = "2.4.1"; }; atk = { dependencies = ["glib2"]; @@ -124,10 +147,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0a8q9a1f6x4gy55p8cf52a22bnpjgn18ad9n959x0f4gybbhs948"; + sha256 = "05brc25pfvak610mdwgjsc64di29yff9i9g72m6hyc21pdjwfy3n"; type = "gem"; }; - version = "3.4.1"; + version = "3.4.3"; }; atomos = { groups = ["default"]; @@ -174,10 +197,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1mmkls9n56l4gx2k0dnyianwz36z2zgpxli5bpsbr7jbw7hn2x6j"; + sha256 = "0nx3yjf4xzdgb8jkmk2344081gqr22pgjqnmjg2q64mj5d6r9194"; type = "gem"; }; - version = "11.0.1"; + version = "11.1.3"; }; cairo = { dependencies = ["native-package-installer" "pkg-config"]; @@ -185,10 +208,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0yvv2lcbsybzbw1nrmfivmln23da4rndrs3av6ymjh0x3ww5h7p8"; + sha256 = "00hiy6anibkjq9w77hg0lpgnkkbcxrfbz8wxv44jfzqbab8910wb"; type = "gem"; }; - version = "1.16.4"; + version = "1.16.6"; }; cairo-gobject = { dependencies = ["cairo" "glib2"]; @@ -196,10 +219,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0gkxdfslcvrwrs48giilji3bgxd5bwijwq33p9h00r10jzfg2028"; + sha256 = "136aa800dgq6bmr0lb59mfj5q72r712wwp5wy5qxnp48adjw1k2h"; type = "gem"; }; - version = "3.4.1"; + version = "3.4.3"; }; camping = { dependencies = ["mab" "rack"]; @@ -217,10 +240,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1825ll26p28swjiw8n3x2pnh5ygsmg83spf82fnzcjn2p87vc5lf"; + sha256 = "0ia09r8bj3bjhcfiyr3vlk9zx7vahfypbs2lyrxix9x1jx3lfzq4"; type = "gem"; }; - version = "3.0.2"; + version = "3.0.3"; }; charlock_holmes = { groups = ["default"]; @@ -247,10 +270,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0dka8f3hwzz7p558kiyyrdabljvwp71cbzk46akb3kvnvhcyjx89"; + sha256 = "08m0syh06bhx8dqn560ivjg96l5cs5s3l9jh2szsnlcdcyl9jsjg"; type = "gem"; }; - version = "1.3.1"; + version = "1.3.2"; }; cld3 = { dependencies = ["ffi"]; @@ -258,53 +281,42 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "06p4jgrr0zixqnflmg5dcrbmhlnmll85j7vxkrjmnng293cwvzgw"; + sha256 = "04hwr44m7x7vv55lc4vk5zcd6zq98c2asvzl3dh2adg1fhpk29nr"; type = "gem"; }; - version = "3.2.4"; + version = "3.3.0"; }; cocoapods = { - dependencies = ["activesupport" "claide" "cocoapods-core" "cocoapods-deintegrate" "cocoapods-downloader" "cocoapods-plugins" "cocoapods-search" "cocoapods-stats" "cocoapods-trunk" "cocoapods-try" "colored2" "escape" "fourflusher" "gh_inspector" "molinillo" "nap" "ruby-macho" "xcodeproj"]; + dependencies = ["activesupport" "claide" "cocoapods-core" "cocoapods-deintegrate" "cocoapods-downloader" "cocoapods-plugins" "cocoapods-search" "cocoapods-stats" "cocoapods-trunk" "cocoapods-try" "colored" "escape" "fourflusher" "molinillo" "nap" "xcodeproj"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "007ssx75588ji2d8l8s6c95dng1c7b6yacng8nngpy7maijzjgzc"; + sha256 = "0rnxjwrfk3yz34xx11hh61j7p57l6vwh8b86jvjivzlgrj4a025r"; type = "gem"; }; - version = "1.8.4"; + version = "1.0.1"; }; cocoapods-acknowledgements = { - dependencies = ["activesupport" "redcarpet"]; + dependencies = ["cocoapods" "redcarpet" "xcodeproj"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "07n638ijlc4y5vfzs5ykzhmwwsng7njb2nnwn4ravydqqxqgv13m"; + sha256 = "04gaijs4djjkynan06wyaxxz48db0czzfrhh95jn3r201k2ypa7k"; type = "gem"; }; - version = "1.1.3"; + version = "1.3.0"; }; cocoapods-art = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0vkcpwjp7hzby60hq0pxn9zdiz7snf7siq02bckkmd84n27hlz3w"; + sha256 = "0ljsx1inbbzj8njpk4sb40kdis6pjwpgcpy3677dm45bxw21dmkv"; type = "gem"; }; - version = "1.0.4"; - }; - cocoapods-bin = { - dependencies = ["cocoapods" "cocoapods-generate" "parallel"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0dzbv7bfyw8a0iyi4nqw8a74wrdhf3absnpdb3i46rpbkanxw7hy"; - type = "gem"; - }; - version = "0.1.24"; + version = "1.0.5"; }; cocoapods-browser = { dependencies = ["cocoapods"]; @@ -317,28 +329,6 @@ }; version = "0.1.5"; }; - cocoapods-bugsnag = { - dependencies = ["cocoapods"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1r34h66rqswsyhanx69qnhhr02xsqy2y1zp5265gl6m76nyqq5wa"; - type = "gem"; - }; - version = "2.0.1"; - }; - cocoapods-check = { - dependencies = ["cocoapods"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "17wb5xzhjvrqllsjqqbm00w8gnsrwcb6k7wsb36ykbcp0aiagvaf"; - type = "gem"; - }; - version = "1.1.0"; - }; cocoapods-clean = { groups = ["default"]; platforms = []; @@ -360,15 +350,15 @@ version = "0.0.2"; }; cocoapods-core = { - dependencies = ["activesupport" "algoliasearch" "concurrent-ruby" "fuzzy_match" "nap"]; + dependencies = ["activesupport" "fuzzy_match" "nap"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0zcisqb404828n5d3lbk9y2yyx8v2yr6rk1l8y9a4i1hp743fiad"; + sha256 = "1bh69sbljlf3hvg98y2zssx0ch51lllz1k1lc8xysn43dm3ahaa5"; type = "gem"; }; - version = "1.8.4"; + version = "1.0.1"; }; cocoapods-coverage = { dependencies = ["cocoapods-testing" "slather"]; @@ -427,10 +417,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "08vn0pgcyn6w6fq5xjd7szv2h9s5rzl17kyidnd7fl5qdmzc9c54"; + sha256 = "1j03hxvz3m82fwgx3jayw0y2iqm7zpacn88r6nfj2arkbjxmvjwz"; type = "gem"; }; - version = "1.3.0"; + version = "1.4.0"; }; cocoapods-expert-difficulty = { groups = ["default"]; @@ -458,10 +448,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "17nqdhdjjg3919h3sz7jkqqhxsi6nyqgfyd7y4ci6fvb7pz79pdh"; + sha256 = "0324y1fm93ri54c5015rh81zqakjmzh15v969ipg0p0xinfpv7ki"; type = "gem"; }; - version = "1.6.0"; + version = "2.0.1"; }; cocoapods-git_url_rewriter = { groups = ["default"]; @@ -479,20 +469,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "14jmfibzvhqxhvhphj3g83d70ya16p7s4i43wir48hnaxkaqrm85"; + sha256 = "153cxxsi77dygc4qrij6qs44dbvc7dw31jx06cmf0ajrhv9qjnxl"; type = "gem"; }; - version = "2.1.0"; - }; - cocoapods-no-dev-schemes = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "14w8yqs3r6pg06zpv58mc9vzfxhp3ka4mfhnc2p7vmyhy4nmcdza"; - type = "gem"; - }; - version = "1.0.1"; + version = "2.2.1"; }; cocoapods-open = { groups = ["default"]; @@ -504,39 +484,6 @@ }; version = "0.0.8"; }; - cocoapods-packager = { - dependencies = ["cocoapods"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1083zv9pyqyqal6dk3kvfxdmylbll6078z5zw03m4j5jcz3m8nbm"; - type = "gem"; - }; - version = "1.5.0"; - }; - cocoapods-packager-pro = { - dependencies = ["cocoapods"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1sjnlnqrc3fvc33c3lg3h6y8n969isjswxg2jdc1kfc3x0cakawl"; - type = "gem"; - }; - version = "1.5.4"; - }; - cocoapods-playgrounds = { - dependencies = ["cocoapods"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0jsc489j6dh3mczzs880vc6jvzd8yjqrszmbbnkz9azndak3mhln"; - type = "gem"; - }; - version = "1.2.2"; - }; cocoapods-plugins = { dependencies = ["nap"]; groups = ["default"]; @@ -548,27 +495,6 @@ }; version = "1.0.0"; }; - cocoapods-prune-localizations = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1hvpl56rnblmdbj40sysvk56j5hx5kdpqry00raw2p184sb5k4cf"; - type = "gem"; - }; - version = "0.3.1"; - }; - cocoapods-rome = { - dependencies = ["cocoapods" "fourflusher"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1z5z49m5aww7q301bn5dzb6fzq6lcj6fvqibpg5ys1r0c41lsj0l"; - type = "gem"; - }; - version = "1.0.1"; - }; cocoapods-search = { groups = ["default"]; platforms = []; @@ -579,28 +505,6 @@ }; version = "1.0.0"; }; - cocoapods-sorted-search = { - dependencies = ["cocoapods" "hashie" "osx_keychain" "ruby-progressbar" "typhoeus"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1da86mjq4spfsx6xjk7qylvj5423ai9y39g9xxfl9r6h8i54dmpp"; - type = "gem"; - }; - version = "0.2.4"; - }; - cocoapods-static-swift-framework = { - dependencies = ["cocoapods"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "12hhh25bj5dyz6rwc5jgarlld35vmgn43qk5lq9kfrpcli2ynhp2"; - type = "gem"; - }; - version = "0.5"; - }; cocoapods-stats = { groups = ["default"]; platforms = []; @@ -611,17 +515,6 @@ }; version = "1.1.0"; }; - cocoapods-tdfire-binary = { - dependencies = ["cocoapods" "cocoapods-bin" "cocoapods-packager-pro"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "10idp7yr2zni6zhpj1pqkj4wkk5g48f5iizjb20i8minj52l64m0"; - type = "gem"; - }; - version = "2.0.9"; - }; cocoapods-testing = { dependencies = ["xctasks"]; groups = ["default"]; @@ -639,20 +532,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0vrwsgaq3nf7v3pwksgqy0mhswrp3ipczrc96vl3ii2pcc9ilwkw"; + sha256 = "12c6028bmdwrbqcb49mr5qj1p3vcijnjqbsbzywfx1isp44j9mv5"; type = "gem"; }; - version = "1.4.1"; + version = "1.5.0"; }; cocoapods-try = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1gf2zjmcjhh9psq15yfy82wz5jnlihf5bcw79f8hlv4cnqyspncj"; + sha256 = "1znyp625rql37ivb5rk9fk9564cmax8icxfr041ysivpdrn98nql"; type = "gem"; }; - version = "1.1.0"; + version = "1.2.0"; }; cocoapods-try-release-fix = { groups = ["default"]; @@ -700,10 +593,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "15vav4bhcc2x3jmi3izb11l4d9f3xv8hp2fszb7iqmpsccv1pz4y"; + sha256 = "0jvxqxzply1lwp7ysn94zjhh57vc14mcshw1ygw14ib8lhc00lyw"; type = "gem"; }; - version = "1.1.2"; + version = "1.1.3"; }; colorator = { groups = ["default"]; @@ -715,6 +608,16 @@ }; version = "1.1.0"; }; + colored = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0b0x5jmsyi0z69bm6sij1k89z7h0laag3cb4mdn7zkl9qmxb90lx"; + type = "gem"; + }; + version = "1.2"; + }; colored2 = { groups = ["default"]; platforms = []; @@ -730,30 +633,30 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1x07r23s7836cpp5z9yrlbpljcxpax14yw4fy4bnp6crhr6x24an"; + sha256 = "1vnxrbhi7cq3p4y2v9iwd10v1c7l15is4var14hwnb2jip4fyjzz"; type = "gem"; }; - version = "1.1.5"; + version = "1.1.7"; }; crass = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "030sc98kjrb36rh7g21qsbdfxrj6knsjkx0mn3b7gig8zknwhp2f"; + sha256 = "0pfl5c0pyqaparxaqxi6s4gfl21bdldwiawrc0aknyvflli60lfw"; type = "gem"; }; - version = "1.0.5"; + version = "1.0.6"; }; curb = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0s27g4nkdf8wipzyxx87nnw43ps8xqg30sqz86ay7dvmmpkd786k"; + sha256 = "1q7kqswm780vx1fannnrprbfbsp166smgyszgip5q7b859mk89wp"; type = "gem"; }; - version = "0.9.10"; + version = "0.9.11"; }; curses = { groups = ["default"]; @@ -791,20 +694,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1nff0nai8h8786xix92f3k5wjb51gqd9gkibmah2bvrcwyn9qiw5"; + sha256 = "09frwp3np5c64y8g5rnbl46n7riknmdjprhndsh6zzajkjr9m3xj"; type = "gem"; }; - version = "1.3.1"; + version = "1.3.5"; }; diff-lcs = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "18w22bjz424gzafv6nzv98h0aqkwz3d9xhm7cbr1wfbyas8zayza"; + sha256 = "0m925b8xc6kbpnif9dldna24q1szg4mk0fvszrki837pfn46afmz"; type = "gem"; }; - version = "1.3"; + version = "1.4.4"; }; digest-sha3 = { groups = ["default"]; @@ -853,10 +756,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "17hkd62ig9b0czv192kqdfq7gw0a8hgq07yclri6myc8y5lmfin5"; + sha256 = "0iym172c5337sm1x2ykc2i3f961vj3wdclbyg1x6sxs3irgfsl94"; type = "gem"; }; - version = "2.7.5"; + version = "2.7.6"; }; em-websocket = { dependencies = ["eventmachine" "http_parser.rb"]; @@ -864,20 +767,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1bsw8vjz0z267j40nhbmrvfz7dvacq4p0pagvyp17jif6mj6v7n3"; + sha256 = "1mg1mx735a0k1l8y14ps2mxdwhi5r01ikydf34b0sp60v66nvbkb"; type = "gem"; }; - version = "0.5.1"; + version = "0.5.2"; }; - erubis = { + erubi = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1fj827xqjs91yqsydf0zmfyw9p4l2jz5yikg3mppz6d7fi8kyrb3"; + sha256 = "09l8lz3j00m898li0yfsnb6ihc63rdvhw3k5xczna5zrjk104f2l"; type = "gem"; }; - version = "2.7.0"; + version = "1.10.0"; }; escape = { groups = ["default"]; @@ -915,31 +818,31 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0nn8wk7j22ly4lzdp5pnm7qsrjxbgspiyxkw70g1qf9bn6pslmxr"; + sha256 = "16ij8617v3js03yj1zd32mmrf7kpi9l96bid5mpqk30c4mzai55r"; type = "gem"; }; - version = "0.71.1"; + version = "0.78.1"; }; faraday = { - dependencies = ["multipart-post"]; + dependencies = ["multipart-post" "ruby2_keywords"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1gggz3vvvkdrxil2fwpaaslv1z5bxzwra4wnybf20np58v1iv9w8"; + sha256 = "16dapwi5pivrl25r4lkr1mxjrzkznj4wlcb08fzkmxnj4g5c6y35"; type = "gem"; }; - version = "0.17.1"; + version = "1.1.0"; }; ffi = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0j8pzj8raxbir5w5k6s7a042sb5k02pg0f8s4na1r5lan901j00p"; + sha256 = "10ay35dm0lkcqprsiya6q2kwvyid884102ryipr4vrk790yfp8kd"; type = "gem"; }; - version = "1.10.0"; + version = "1.11.3"; }; ffi-compiler = { dependencies = ["ffi" "rake"]; @@ -969,10 +872,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1s1jxlrbq4jhwkiy5gq429v87m1l602b2gppw0ikbax7rnv30s9x"; + sha256 = "0bwqm9n69y5y0a5iickr358z7w4hml3flqwfz8b7cnj1ldabhnjn"; type = "gem"; }; - version = "2.2.0"; + version = "2.2.3"; }; fog-dnsimple = { dependencies = ["fog-core" "fog-json"]; @@ -1021,10 +924,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1afabh3g3gwj0ad53fs62waks815xcckf7pkci76l6vrghffcg8v"; + sha256 = "0yp0pxj6xsd84h2barwh3z5w289p1a6lqib309m7sbzh643qx3zz"; type = "gem"; }; - version = "2.3.1"; + version = "0.3.2"; }; fuzzy_match = { groups = ["default"]; @@ -1042,20 +945,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0194gzn0kialfh0j7crllvp808r64sg6dh297x69b0av21ar5pam"; - type = "gem"; - }; - version = "3.4.1"; - }; - gh_inspector = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0f8r9byajj3bi2c7c5sqrc7m0zrv3nblfcd4782lw5l73cbsgk04"; + sha256 = "0hslcfns2ysvjyj21hjvp4hghrafw1sdl627fm0nj0wsncs94m67"; type = "gem"; }; - version = "1.1.3"; + version = "3.4.3"; }; gio2 = { dependencies = ["gobject-introspection"]; @@ -1063,20 +956,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1l3jpgbdvb55xhcmpkcqgwx5068dfyi8kijfvzhbqh96ng0p1m7g"; + sha256 = "1l30xsr1dgnzqfmln17arnqi8iga97ldf6zgbqrfby6a94v3ammd"; type = "gem"; }; - version = "3.4.1"; + version = "3.4.3"; }; gitlab-markup = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0rqf3jmyn78r3ysy3bjyx7s4yv3xipxlmqlmbyrbksna19rrx08d"; + sha256 = "0xnlra517pfj3hx07kasbqlcw51ix4xajr6bsd3mwg8bc92dlwy7"; type = "gem"; }; - version = "1.7.0"; + version = "1.7.1"; }; glib2 = { dependencies = ["native-package-installer" "pkg-config"]; @@ -1084,10 +977,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "18clyn0fp0h5alnkf9i2bqd6wvl78h468pdbzs1csqnba8vw4q1c"; + sha256 = "0l46ymdf7azpd137xq4rarbaq54hxs9rgfry0r6b0ywj74rmw9ih"; type = "gem"; }; - version = "3.4.1"; + version = "3.4.3"; }; globalid = { dependencies = ["activesupport"]; @@ -1106,10 +999,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1a3x8qiisbax3x0izj8l5w66r53ba5ma53ax2jhdbhbvaxx3d02n"; + sha256 = "11gas9hzq36a2bwqi7h5c6p6jihanbhsarwhv5fw53dxap4iwj25"; type = "gem"; }; - version = "3.4.1"; + version = "3.4.3"; }; gpgme = { dependencies = ["mini_portile2"]; @@ -1117,10 +1010,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0jbqajngi5ndqfarw9dxkhbphva0j71jav5wfym3fsiisvk5gg6p"; + sha256 = "0xbgh9d8nbvsvyzqnd0mzhz0nr9hx4qn025kmz6d837lry4lc6gw"; type = "gem"; }; - version = "2.0.19"; + version = "2.0.20"; }; gtk2 = { dependencies = ["atk" "gdk_pixbuf2" "pango"]; @@ -1128,20 +1021,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "17az8g0n1yzz90kdbjg2hpabi04qccda7v6lin76bs637ivfg2md"; + sha256 = "0v1ag6irp52asm0yaxa7s533czy7yzhanhgn1v0cndqpzqk8icfz"; type = "gem"; }; - version = "3.4.1"; + version = "3.4.3"; }; hashie = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0drkv8a70akprcnbxvd08hzp2bgd5g4s5g752f8599ks1g6a7wj1"; + sha256 = "02bsx12ihl78x0vdm37byp78jjw2ff6035y7rrmbd90qxjwxr43q"; type = "gem"; }; - version = "4.0.0"; + version = "4.1.0"; }; highline = { groups = ["default"]; @@ -1230,10 +1123,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "038qvz7kd3cfxk8bvagqhakx68pfbnmghpdkx7573wbf0maqp9a3"; + sha256 = "153sx77p16vawrs4qpkv7qlzf9v5fks4g7xqcj1dwk40i6g7rfzk"; type = "gem"; }; - version = "0.9.5"; + version = "1.8.5"; }; iconv = { groups = ["default"]; @@ -1255,26 +1148,16 @@ }; version = "0.1.0"; }; - jaro_winkler = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1y8l6k34svmdyqxya3iahpwbpvmn3fswhwsvrz0nk1wyb8yfihsh"; - type = "gem"; - }; - version = "1.5.4"; - }; jbuilder = { dependencies = ["activesupport"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "03adzsc2hfd0lvprm45s52bkxpnpnw8r9prcx8zx1aw2a8lzp9r7"; + sha256 = "02llgsg30jz9kpxs8jzv6rvzaylw7948xj2grp4vsfg54z20cwbm"; type = "gem"; }; - version = "2.9.1"; + version = "2.10.1"; }; jekyll = { dependencies = ["addressable" "colorator" "em-websocket" "i18n" "jekyll-sass-converter" "jekyll-watch" "kramdown" "kramdown-parser-gfm" "liquid" "mercenary" "pathutil" "rouge" "safe_yaml" "terminal-table"]; @@ -1282,10 +1165,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0fpckw5nf4hfr5vhhdlmaxxp5lkdmc1vyqnmijwvy9fmjn4c87aa"; + sha256 = "192k1ggw99slpqpxb4xamcvcm2pdahgnmygl746hmkrar0i3xa5r"; type = "gem"; }; - version = "4.0.0"; + version = "4.1.1"; }; jekyll-sass-converter = { dependencies = ["sassc"]; @@ -1293,10 +1176,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0xjzqpp35qr2vnf2zpak0srn773mp21glcq81a0iqpnrva7h80m3"; + sha256 = "04ncr44wrilz26ayqwlg7379yjnkb29mvx4j04i62b7czmdrc9dv"; type = "gem"; }; - version = "2.0.1"; + version = "2.1.0"; }; jekyll-watch = { dependencies = ["listen"]; @@ -1324,30 +1207,31 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0nrmw2r4nfxlfgprfgki3hjifgrcrs3l5zvm3ca3gb4743yr25mn"; + sha256 = "158fawfwmv2sq4whqqaksfykkiad2xxrrj0nmpnc6vnlzi1bp7iz"; type = "gem"; }; - version = "2.3.0"; + version = "2.3.1"; }; jwt = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "01zg1vp3lyl3flyjdkrcc93ghf833qgfgh2p1biqfhkzz11r129c"; + sha256 = "14ynyq1q483spj20ffl4xayfqx1a8qr761mqjfxczf8lwlap392n"; type = "gem"; }; - version = "2.2.1"; + version = "2.2.2"; }; kramdown = { + dependencies = ["rexml"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1dl840bvx8d9nq6lg3mxqyvbiqnr6lk3jfsm6r8zhz7p5srmd688"; + sha256 = "1vmw752c26ny2jwl0npn0gbyqwgz4hdmlpxnsld9qi9xhk5b1qh7"; type = "gem"; }; - version = "2.1.0"; + version = "2.3.0"; }; kramdown-parser-gfm = { dependencies = ["kramdown"]; @@ -1365,20 +1249,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1jivcckillfvd4n2jnsnnlf93z3gpvqbwsczs0fvv9hc90zpj7yh"; + sha256 = "0317sr3nrl51sp844bps71smkrwim3fjn47wdfpbycixnbxspivm"; type = "gem"; }; - version = "7.3.492.27.1"; + version = "8.4.255.0"; }; libxml-ruby = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1r7m7zipkpam8ns4ys4qyh7yj3is3dy7ky6qwnw557pvpgx0aqrd"; + sha256 = "0w2pw08b6pc9pm51ix7413jcllaisc06dvwzq0191ag1jsysv220"; type = "gem"; }; - version = "3.1.0"; + version = "3.2.1"; }; liquid = { groups = ["default"]; @@ -1396,10 +1280,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1w923wmdi3gyiky0asqdw5dnh3gcjs2xyn82ajvjfjwh6sn0clgi"; + sha256 = "1zpcgha7g33wvy2xbbc663cbjyvg9l1325lg3gzgcn3baydr9rha"; type = "gem"; }; - version = "3.2.1"; + version = "3.3.3"; }; loofah = { dependencies = ["crass" "nokogiri"]; @@ -1407,10 +1291,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1g7ps9m3s14cajhxrfgbzahv9i3gy47s4hqrv3mpybpj5cyr0srn"; + sha256 = "0ndimir6k3kfrh8qrb7ir1j836l4r3qlwyclwjh88b86clblhszh"; type = "gem"; }; - version = "2.4.0"; + version = "2.8.0"; }; mab = { groups = ["default"]; @@ -1444,6 +1328,17 @@ }; version = "2.7.1"; }; + marcel = { + dependencies = ["mimemagic"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1nxbjmcyg8vlw6zwagf17l9y2mwkagmmkg95xybpn4bmf3rfnksx"; + type = "gem"; + }; + version = "0.3.3"; + }; markaby = { dependencies = ["builder"]; groups = ["default"]; @@ -1460,20 +1355,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "10la0xw82dh5mqab8bl0dk21zld63cqxb1g16fk8cb39ylc4n21a"; + sha256 = "0f2i827w4lmsizrxixsrv2ssa3gk1b7lmqh8brk8ijmdb551wnmj"; type = "gem"; }; - version = "0.3.6"; + version = "0.4.0"; }; method_source = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1pviwzvdqd90gn6y7illcdd9adapw8fczml933p5vl739dkvl3lq"; + sha256 = "1pnyh44qycnf9mzi1j6fywd5fkskv3x7nmsqrrws0rjn5dd4ayfp"; type = "gem"; }; - version = "0.9.2"; + version = "1.0.0"; }; mime-types = { dependencies = ["mime-types-data"]; @@ -1491,20 +1386,30 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "18x61fc36951vw7f74gq8cyybdpxvyg5d0azvqhrs82ddw3v16xh"; + sha256 = "0ipjyfwn9nlvpcl8knq3jk4g5f12cflwdbaiqxcq1s7vwfwfxcag"; type = "gem"; }; - version = "3.2019.1009"; + version = "3.2020.1104"; + }; + mimemagic = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1qfqb9w76kmpb48frbzbyvjc0dfxh5qiw1kxdbv2y2kp6fxpa1kf"; + type = "gem"; + }; + version = "0.3.5"; }; mini_magick = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0qy09qrd5bwh8mkbj514n5vcw9ni73218h9s3zmvbpmdwrnzi8j4"; + sha256 = "1aj604x11d9pksbljh0l38f70b558rhdgji1s9i763hiagvvx2hs"; type = "gem"; }; - version = "4.9.5"; + version = "4.11.0"; }; mini_mime = { groups = ["default"]; @@ -1531,40 +1436,40 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0w16p7cvslh3hxd3cia8jg4pd85z7rz7xqb16vh42gj4rijn8rmi"; + sha256 = "170y2cvx51gm3cm3nhdf7j36sxnkh6vv8ls36p90ric7w8w16h4v"; type = "gem"; }; - version = "5.13.0"; + version = "5.14.2"; }; molinillo = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1hh40z1adl4lw16dj4hxgabx4rr28mgqycih1y1d91bwww0jjdg6"; + sha256 = "0msabpxiyhlbgayrvr01316alaxrxwh6h8yzqz6p36v1zhqgddw4"; type = "gem"; }; - version = "0.6.6"; + version = "0.4.5"; }; msgpack = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1qr2mkm2i3m76zarvy7qgjl9596hmvjrg7x6w42vx8cfsbf5p0y1"; + sha256 = "1lva6bkvb4mfa0m3bqn4lm4s4gi81c40jvdcsrxr6vng49q9daih"; type = "gem"; }; - version = "1.3.1"; + version = "1.3.3"; }; multi_json = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0xy54mjf7xg41l8qrg1bqri75agdqmxap9z466fjismc1rn2jwfr"; + sha256 = "0pb1g1y3dsiahavspyzkdy39j4q377009f6ix0bh1ag4nqw43l0z"; type = "gem"; }; - version = "1.14.1"; + version = "1.15.0"; }; multipart-post = { groups = ["default"]; @@ -1576,6 +1481,17 @@ }; version = "2.1.1"; }; + mustermann = { + dependencies = ["ruby2_keywords"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0ccm54qgshr1lq3pr1dfh7gphkilc19dp63rw6fcx7460pjwy88a"; + type = "gem"; + }; + version = "1.1.1"; + }; mysql2 = { groups = ["default"]; platforms = []; @@ -1591,10 +1507,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0ajfyaqjw3dzykk612yw8sm21savfqy292hgps8h8l4lvxww1lz6"; + sha256 = "0xi36h3f7nm8bc2k0b6svpda1lyank2gf872lxjbhw3h95hdrbma"; type = "gem"; }; - version = "0.2.6"; + version = "0.3.0"; }; nap = { groups = ["default"]; @@ -1632,20 +1548,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0nkf3my587f0izqw0dl3zl24c3lnrw9y5xrq9vb0lhgymmgcav9g"; + sha256 = "0b4h3ip8d1gkrc0znnw54hbxillk73mdnaf5pz330lmrcl1wiilg"; type = "gem"; }; - version = "2.0.0"; + version = "3.0.0"; }; net-ssh = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "101wd2px9lady54aqmkibvy4j62zk32w0rjz4vnigyg974fsga40"; + sha256 = "0jp3jgcn8cij407xx9ldb5h9c6jv13jc4cf6kk2idclz43ww21c9"; type = "gem"; }; - version = "5.2.0"; + version = "6.1.0"; }; netrc = { groups = ["default"]; @@ -1662,10 +1578,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0gnmvbryr521r135yz5bv8354m7xn6miiapfgpg1bnwsvxz8xj6c"; + sha256 = "1cbwp1kbv6b2qfxv8sarv0d0ilb257jihlvdqj8f5pdm0ksq1sgk"; type = "gem"; }; - version = "2.5.2"; + version = "2.5.4"; }; nokogiri = { dependencies = ["mini_portile2"]; @@ -1673,10 +1589,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0r0qpgf80h764k176yr63gqbs2z0xbsp8vlvs2a79d5r9vs83kln"; + sha256 = "0xmf60nj5kg9vaj5bysy308687sgmkasgx06vbbnf94p52ih7si2"; type = "gem"; }; - version = "1.10.7"; + version = "1.10.10"; }; opus-ruby = { dependencies = ["ffi"]; @@ -1706,10 +1622,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "09lb0a9y4q7946jaf53li1v4cb6ksfb5bq5wb15yn8ja6wf9n427"; + sha256 = "1zlk3bksiwrdvb7j0r5av7w280kigl7947wa7w4kbwqz3snaxl3m"; type = "gem"; }; - version = "4.3.0"; + version = "4.4.0"; }; pango = { dependencies = ["cairo-gobject" "gobject-introspection"]; @@ -1717,20 +1633,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1d0cn50qgpifrcv8qx72wi6l9xalw3ryngbfmm9xpg9vx5rl1qbp"; + sha256 = "05smxn2jank7wqih59lhr30ab8f4qxdsdiiag5v7a0gjgzkmbi7f"; type = "gem"; }; - version = "3.4.1"; + version = "3.4.3"; }; parallel = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "12jijkap4akzdv11lm08dglsc8jmc87xcgq6947i1s3qb69f4zn2"; + sha256 = "0055br0mibnqz0j8wvy20zry548dhkakws681bhj3ycb972awkzd"; type = "gem"; }; - version = "1.19.1"; + version = "1.20.1"; }; parser = { dependencies = ["ast"]; @@ -1738,10 +1654,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "10siyp14d88jwcfj45kkk3nwl4wyr2r5ajb7vy4iwh1gxmhvi727"; + sha256 = "1f7gmm60yla325wlnd3qkxs59qm2y0aan8ljpg6k18rwzrrfil6z"; type = "gem"; }; - version = "2.7.0.0"; + version = "2.7.2.0"; }; pathutil = { dependencies = ["forwardable-extended"]; @@ -1779,20 +1695,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "15pa9qy7ngig21zgnvzwaxiy4rc7wbibna5050jjpgal9drgvpyy"; + sha256 = "13mfrysrdrh8cka1d96zm0lnfs59i5x2g6ps49r2kz5p3q81xrzj"; type = "gem"; }; - version = "1.2.0"; + version = "1.2.3"; }; pkg-config = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1cxdpr2wlz9b587avlq04a1da5fz1vdw8jvr6lx23mcq7mqh2xcx"; + sha256 = "068sf963n2zk47kqcckj624g5pxmk68mm76h02piphfyh9x4zmi3"; type = "gem"; }; - version = "1.4.0"; + version = "1.4.4"; }; polyglot = { groups = ["default"]; @@ -1810,10 +1726,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "00rm71x0r1jdycwbs83lf9l6p494m99asakbvqxh8rz7zwnlzg69"; + sha256 = "0iyw4q4an2wmk8v5rn2ghfy2jaz9vmw2nk8415nnpx2s866934qk"; type = "gem"; }; - version = "0.12.2"; + version = "0.13.1"; }; pry-byebug = { dependencies = ["byebug" "pry"]; @@ -1821,10 +1737,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1aqz4gz8z44k6svpvcsfrqbigcpjd2kwvfm77yq3v8yzkhjrx0zi"; + sha256 = "096y5vmzpyy4x9h4ky4cs4y7d19vdq9vbwwrqafbh5gagzwhifiv"; type = "gem"; }; - version = "3.7.0"; + version = "3.9.0"; }; pry-doc = { dependencies = ["pry" "yard"]; @@ -1832,20 +1748,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "14lwb5dxfibcqbjygzvnf8ry0mayx48fk20qhg06214sll0sp0kv"; + sha256 = "1xrf2whjycv4sd7qvf5m6zdpk0lhf1p63v66w9ha146fc7rcjkc1"; type = "gem"; }; - version = "1.0.0"; + version = "1.1.0"; }; public_suffix = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0ww6577yhgszvc0p33qg9nb7n03fyadvl14v2kbpm4rpf0q4i6gz"; + sha256 = "1xqcgkl7bwws1qrlnmxgh8g4g9m10vg60bhlw40fplninb3ng6d9"; type = "gem"; }; - version = "4.0.2"; + version = "4.0.6"; }; puma = { dependencies = ["nio4r"]; @@ -1853,20 +1769,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0v6zai6sinw5r1lchm278mm3dr8x5vi8pwmybwv9lz1kz02fk2g3"; + sha256 = "1fl2bgw1lh1712qpzl5m5vi4cc1bcw336bh1dbp28fkmss9yysma"; type = "gem"; }; - version = "4.3.1"; + version = "5.1.0"; }; rack = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1riq0z408dwvqcqrpq05bp2w879l4sjxzb4cbrbx55kpi6h2g1cj"; + sha256 = "0i5vs0dph9i5jn8dfc6aqd6njcafmb20rwqngrf759c9cvmyff16"; type = "gem"; }; - version = "1.6.12"; + version = "2.2.3"; }; rack-protection = { dependencies = ["rack"]; @@ -1874,10 +1790,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0my0wlw4a5l3hs79jkx2xzv7djhajgf8d28k8ai1ddlnxxb0v7ss"; + sha256 = "159a4j4kragqh0z0z8vrpilpmaisnlz3n7kgiyf16bxkwlb3qlhz"; type = "gem"; }; - version = "1.5.5"; + version = "2.1.0"; }; rack-test = { dependencies = ["rack"]; @@ -1885,43 +1801,32 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0h6x5jq24makgv2fq5qqgjlrk74dxfy62jif9blk43llw8ib2q7z"; + sha256 = "0rh8h376mx71ci5yklnpqqn118z3bl67nnv5k801qaqn1zs62h8m"; type = "gem"; }; - version = "0.6.3"; + version = "1.1.0"; }; rails = { - dependencies = ["actionmailer" "actionpack" "actionview" "activejob" "activemodel" "activerecord" "activesupport" "railties" "sprockets-rails"]; - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "1ywvis59dd3v8qapi9ix6743zgk07l21x1cd6nb1ddpahxhm7dml"; - type = "gem"; - }; - version = "4.2.11.1"; - }; - rails-deprecated_sanitizer = { - dependencies = ["activesupport"]; + dependencies = ["actioncable" "actionmailbox" "actionmailer" "actionpack" "actiontext" "actionview" "activejob" "activemodel" "activerecord" "activestorage" "activesupport" "railties" "sprockets-rails"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0qxymchzdxww8bjsxj05kbf86hsmrjx40r41ksj0xsixr2gmhbbj"; + sha256 = "0vs4kfgp5pr5032nnhdapq60ga6karann06ilq1yjx8qck87cfxg"; type = "gem"; }; - version = "1.0.3"; + version = "6.0.3.4"; }; rails-dom-testing = { - dependencies = ["activesupport" "nokogiri" "rails-deprecated_sanitizer"]; + dependencies = ["activesupport" "nokogiri"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0wssfqpn00byhvp2372p99mphkcj8qx6pf6646avwr9ifvq0q1x6"; + sha256 = "1lfq2a7kp2x64dzzi5p4cjcbiv62vxh9lyqk2f0rqq3fkzrw8h5i"; type = "gem"; }; - version = "1.0.9"; + version = "2.0.3"; }; rails-html-sanitizer = { dependencies = ["loofah"]; @@ -1935,15 +1840,15 @@ version = "1.3.0"; }; railties = { - dependencies = ["actionpack" "activesupport" "rake" "thor"]; + dependencies = ["actionpack" "activesupport" "method_source" "rake" "thor"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1bjf21z9maiiazc1if56nnh9xmgbkcqlpznv34f40a1hsvgk1d1m"; + sha256 = "0x28620cvfja8r06lk6f90pw5lvijz9qi4bjsa4z1d1rkr3v4r3w"; type = "gem"; }; - version = "4.2.11.1"; + version = "6.0.3.4"; }; rainbow = { groups = ["default"]; @@ -1970,10 +1875,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1lm1k7wpz69jx7jrc92w3ggczkjyjbfziq5mg62vjnxmzs383xx8"; + sha256 = "1k9bsj7ni0g2fd7scyyy1sk9dy2pg9akniahab0iznvjmhn54h87"; type = "gem"; }; - version = "0.10.3"; + version = "0.10.4"; }; rb-inotify = { dependencies = ["ffi"]; @@ -2002,20 +1907,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0lvz1vk2l3chnz6zdp4xmh6w2z75rndhgbravbxgvw8ff4snsxa7"; + sha256 = "0y8yzianlkc9w6sbqy8iy8l0yym0y6x7p5rjflkfixq76fqmhvzk"; type = "gem"; }; - version = "7.1.0"; + version = "7.1.1"; }; re2 = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "00wf9k1hkv3z3nfkrnfyyfq9ah0l7k14awqys3h2hqz4c21pqd2i"; + sha256 = "16q71cc9wx342c697q18pkz19ym4ncjd97hcw4v6f1mgflkdv400"; type = "gem"; }; - version = "1.1.1"; + version = "1.2.0"; }; redcarpet = { groups = ["default"]; @@ -2032,10 +1937,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "08v2y91q1pmv12g9zsvwj66w3s8j9d82yrmxgyv4y4gz380j3wyh"; + sha256 = "15x2sr6h094rjbvg8pkq6m3lcd5abpyx93aifvfdz3wv6x55xa48"; type = "gem"; }; - version = "4.1.3"; + version = "4.2.5"; }; redis-rack = { dependencies = ["rack" "redis-store"]; @@ -2043,10 +1948,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1pa19ydbk0l6wilwbxcjn6knfs4ffgj0rhaaldrlhf76pjgkaiqb"; + sha256 = "1nblbxg1f051dn83jp92lz3lc1wxm18nviglrabv2l0vz6rd0pkb"; type = "gem"; }; - version = "2.0.6"; + version = "2.1.3"; }; redis-store = { dependencies = ["redis"]; @@ -2054,10 +1959,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1isqzzds9kszc2nn8jiy8ikry01qspn7637ba9z2k6sk7vky46d9"; + sha256 = "0cpzbf2svnk4j5awb24ncl0mih45zkbdrd7q23jdg1r8k3q7mdg6"; type = "gem"; }; - version = "1.8.1"; + version = "1.9.0"; + }; + regexp_parser = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1racz3w9s4w0ls32bvjypfifk4a7qxngm2cv1rh16jyz0c1wjd70"; + type = "gem"; + }; + version = "2.0.0"; }; rest-client = { dependencies = ["http-accept" "http-cookie" "mime-types" "netrc"]; @@ -2070,25 +1985,35 @@ }; version = "2.1.0"; }; + rexml = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1mkvkcw9fhpaizrhca0pdgjcrbns48rlz4g6lavl5gjjq3rk2sq3"; + type = "gem"; + }; + version = "3.2.4"; + }; rmagick = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "06ya2zpz2g3g4c90bmd1z11qkajls3srq5b7cswrjq8ima568ja0"; + sha256 = "0ajn6aisf9hh3x5zrs7n02pg5xy3m8x38gh9cn7b3klzgp3djla5"; type = "gem"; }; - version = "4.0.0"; + version = "4.1.2"; }; rouge = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0k5jrp0qc9p61mfcwyn1a7dajmkw04z6y76wa8a0axh1v2wrw8ld"; + sha256 = "0yvcv901lrh5rfnk1h4h56hf2m6n9pd6w8n96vag74aakgz3gaxn"; type = "gem"; }; - version = "3.14.0"; + version = "3.25.0"; }; rpam2 = { groups = ["default"]; @@ -2106,10 +2031,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1hzsig4pi9ybr0xl5540m1swiyxa74c8h09225y5sdh2rjkkg84h"; + sha256 = "1dwai7jnwmdmd7ajbi2q0k0lx1dh88knv5wl7c34wjmf94yv8w5q"; type = "gem"; }; - version = "3.9.0"; + version = "3.10.0"; }; rspec-core = { dependencies = ["rspec-support"]; @@ -2117,10 +2042,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0gppalb2ynj0xk7vp8kk5pwzihmiqc8l4prpy4n9spclq7iqkspq"; + sha256 = "0n2rdv8f26yw8c6asymc0mgddyr5d2b5n6mfvpd3n6lnpf1jdyv2"; type = "gem"; }; - version = "3.9.0"; + version = "3.10.0"; }; rspec-expectations = { dependencies = ["diff-lcs" "rspec-support"]; @@ -2128,10 +2053,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1gjqfb39da6gywdcp4h77738r7khbrn2v4y45589z25bj4z9paf0"; + sha256 = "0j37dvnvfbjwj8dqx27yfvz0frl7f2jc1abqg99h0ppriz9za6dc"; type = "gem"; }; - version = "3.9.0"; + version = "3.10.0"; }; rspec-mocks = { dependencies = ["diff-lcs" "rspec-support"]; @@ -2139,52 +2064,64 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0q9f8nrxhs4k2vl3bnm3pi5s44v9pnvjwirjnwji3sxzf68c2xjf"; + sha256 = "1pz89y1522i6f8wzrg72ykmch3318ih87nlpl0y1ghsrs5hqymw3"; type = "gem"; }; - version = "3.9.0"; + version = "3.10.0"; }; rspec-support = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "18080h06kqayyr6dpw4c62l0wav09ihkd6skinsln13kmq0cv0mx"; + sha256 = "0j0n28i6zci5j7gg370bdy87dy43hlwx6dw428d9kamf5a0i2klz"; type = "gem"; }; - version = "3.9.0"; + version = "3.10.0"; }; rubocop = { - dependencies = ["jaro_winkler" "parallel" "parser" "rainbow" "ruby-progressbar" "unicode-display_width"]; + dependencies = ["parallel" "parser" "rainbow" "regexp_parser" "rexml" "rubocop-ast" "ruby-progressbar" "unicode-display_width"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1p1bhsfscasp57l5di9hsx8jl325kfjswhd2mlzq74hj3gdws4x0"; + sha256 = "0k246mahr4737rlvazll5vfvq1307b0z9pmhlnp5ynknl31fclp5"; type = "gem"; }; - version = "0.78.0"; + version = "1.5.2"; + }; + rubocop-ast = { + dependencies = ["parser"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1z9253d7hwdlqr3g7rwx6x6n0qwv8niq6r2ppgry2lbfvb4czypm"; + type = "gem"; + }; + version = "1.3.0"; }; rubocop-performance = { - dependencies = ["rubocop"]; + dependencies = ["rubocop" "rubocop-ast"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1fk9nd3b24avgsqp726hy2pl1iyfjrh6jni97wkky6kqy0lq6zq2"; + sha256 = "0zfc0wvx4jw0apn86jbz5za8pjmb7k0j58ndap3kwarkznxk2ad1"; type = "gem"; }; - version = "1.5.2"; + version = "1.9.1"; }; ruby-graphviz = { + dependencies = ["rexml"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1jzbs0jhaz77azsc30gsfg89fy44vsr565jcj4axhc65n1fmhs90"; + sha256 = "010m283gk4qgzxkgrldlnrglh8d5fn6zvrzm56wf5abd7x7b8aqw"; type = "gem"; }; - version = "1.2.4"; + version = "1.2.5"; }; ruby-libvirt = { groups = ["default"]; @@ -2206,16 +2143,6 @@ }; version = "1.2.3"; }; - ruby-macho = { - groups = ["default"]; - platforms = []; - source = { - remotes = ["https://rubygems.org"]; - sha256 = "0lhdjn91jkifsy2hzq2hgcm0pp8pbik87m58zmw1ifh6hkp9adjb"; - type = "gem"; - }; - version = "1.4.0"; - }; ruby-progressbar = { groups = ["default"]; platforms = []; @@ -2242,10 +2169,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "14hzfsbx7n0jsm6bxif99kbhlmxr4s7g6xvml6xbqphlqbmy5d43"; + sha256 = "0lk124dixshf8mmrjpsy9avnaygni3cwki25g8nm5py4d2f5fwwa"; type = "gem"; }; - version = "2.0.16"; + version = "2.0.17"; + }; + ruby2_keywords = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "17pcc0wgvh3ikrkr7bm3nx0qhyiqwidd13ij0fa50k7gsbnr2p0l"; + type = "gem"; + }; + version = "0.0.2"; }; RubyInline = { dependencies = ["ZenTest"]; @@ -2263,20 +2200,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1gz0ri0pa2xr7b6bf66yjc2wfvk51f4gi6yk7bklwl1nr65zc4gz"; + sha256 = "0590m2pr9i209pp5z4mx0nb1961ishdiqb28995hw1nln1d1b5ji"; type = "gem"; }; - version = "2.0.0"; + version = "2.3.0"; }; rugged = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0rdidxgpk1b6y1jq9v77lcx5khq0s9q0s253lr8x57d3hk43iskx"; + sha256 = "04aq913plcxjw71l5r62qgz3bx3466p0wvgyfqahg5n3nybmcwqy"; type = "gem"; }; - version = "0.28.4.1"; + version = "1.1.0"; }; safe_yaml = { groups = ["default"]; @@ -2294,10 +2231,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "09bnid7r5z5hcin5hykvpvv8xig27wbbckxwis60z2aaxq4j9siz"; + sha256 = "0gpqv48xhl8mb8qqhcifcp0pixn206a7imc07g48armklfqa4q2c"; type = "gem"; }; - version = "2.2.1"; + version = "2.4.0"; }; scrypt = { dependencies = ["ffi-compiler"]; @@ -2315,20 +2252,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0wxkmgjnb8nskvqqwxihhbc1x8dhbbrcq70zxwqbyy5hvf4dh88f"; + sha256 = "1yz6pqdr8p5dv5qkza5kqn6il6m4vcl5hvry6k108axc12zf6hrb"; type = "gem"; }; - version = "0.10.0"; + version = "0.10.6"; }; sequel = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0vrbwwxvmdb7q1sdc0jnhlf826l74n9880xy5li1qabr0hyrmf1j"; + sha256 = "0k4ybmzrf79j9hgcl4m0hiaibf6m8apll99hml9rdjxvkprw51in"; type = "gem"; }; - version = "5.27.0"; + version = "5.39.0"; }; sequel_pg = { dependencies = ["pg" "sequel"]; @@ -2336,42 +2273,52 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1y010rfdgpkw1yspqchjqdp7n8yahscyw98g3l2pw56nzbqipjb8"; + sha256 = "0mkbnc96bfpl5wqacblzwiwqywbx4vqrvkz57fj1h2f0bn635nk6"; type = "gem"; }; - version = "1.12.2"; + version = "1.14.0"; }; simplecov = { - dependencies = ["docile" "json" "simplecov-html"]; + dependencies = ["docile" "simplecov-html" "simplecov_json_formatter"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1135k46nik05sdab30yxb8264lqiz01c8v000g16cl9pjc4mxrdw"; + sha256 = "1mm20dvd64w46l5k11il9z5sjgdpp0bknml76glcngvl2w03k3cb"; type = "gem"; }; - version = "0.17.1"; + version = "0.20.0"; }; simplecov-html = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1lihraa4rgxk8wbfl77fy9sf0ypk31iivly8vl3w04srd7i0clzn"; + sha256 = "0yx01bxa8pbf9ip4hagqkp5m0mqfnwnw2xk8kjraiywz4lrss6jb"; + type = "gem"; + }; + version = "0.12.3"; + }; + simplecov_json_formatter = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0cl3j7p3b5q7sxsx1va63c8imc5x6g99xablz08qrmqhpi0d6g6j"; type = "gem"; }; - version = "0.10.2"; + version = "0.1.2"; }; sinatra = { - dependencies = ["rack" "rack-protection" "tilt"]; + dependencies = ["mustermann" "rack" "rack-protection" "tilt"]; groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0byxzl7rx3ki0xd7aiv1x8mbah7hzd8f81l65nq8857kmgzj1jqq"; + sha256 = "0dd53rzpkxgs697pycbhhgc9vcnxra4ly4xar8ni6aiydx2f88zk"; type = "gem"; }; - version = "1.4.8"; + version = "2.1.0"; }; slather = { dependencies = ["CFPropertyList" "activesupport" "clamp" "nokogiri" "xcodeproj"]; @@ -2379,30 +2326,30 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0v4wll10mwmynj2v2g71kgr1psck3qglhz2mnrw2n281v30jxyyn"; + sha256 = "0nqyam74izmbczwb406bsmgdzjz5r91d4lywlvdbxx5sl4g4256a"; type = "gem"; }; - version = "2.4.7"; + version = "2.6.0"; }; slop = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0hv64fpbdwyswqhnq8bia66vlsz72yjqm00lvlhh4dnjjivdjcy5"; + sha256 = "05d1xv8r9cmd0mmlqpa853yzd7xhcyha063w1g8dpf84scxbxmd3"; type = "gem"; }; - version = "4.7.0"; + version = "4.8.2"; }; snappy = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "00zzs25sm78zs3rifc02z54cp3f03r9dq5ilzykyq1ykvbv65vw4"; + sha256 = "1x0r1dnavg3skyp7b1nkiwd5qrrkvp9zwgfls3i2rzybq8ahx4lb"; type = "gem"; }; - version = "0.0.17"; + version = "0.1.0"; }; sprockets = { dependencies = ["concurrent-ruby" "rack"]; @@ -2410,10 +2357,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0jm37zpvvm1arxjwrd6am0wrdbfhrhc5y0l4p2i3p11z04bsvgap"; + sha256 = "0ikgwbl6jv3frfiy3xhg5yxw9d0064rgzghar1rg391xmrc4gm38"; type = "gem"; }; - version = "4.0.0"; + version = "4.0.2"; }; sprockets-rails = { dependencies = ["actionpack" "activesupport" "sprockets"]; @@ -2421,10 +2368,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0ab42pm8p5zxpv3sfraq45b9lj39cz9mrpdirm30vywzrwwkm5p1"; + sha256 = "0mwmz36265646xqfyczgr1mhkm1hfxgxxvgdgr4xfcbf2g72p1k2"; type = "gem"; }; - version = "3.2.1"; + version = "3.2.2"; }; sqlite3 = { groups = ["default"]; @@ -2441,10 +2388,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0r8g7zdncc6243d000jn0grc1n70rn9mx16vggy3q7c4wgsa37xi"; + sha256 = "1g7398sn8syybz3nbf3dqwa8q8v3s3s444i24xl5q9pzx4g4nkf1"; type = "gem"; }; - version = "0.7.1"; + version = "1.0.1"; }; terminal-table = { dependencies = ["unicode-display_width"]; @@ -2482,10 +2429,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "02p107kwx7jnkh6fpdgvaji0xdg6xkaarngkqjml6s4zny4m8slv"; + sha256 = "08076cmdx0g51yrkd7dlxlr45nflink3jhdiq7006ljc2pc3212q"; type = "gem"; }; - version = "0.11.0.0"; + version = "0.13.0"; }; tilt = { groups = ["default"]; @@ -2502,10 +2449,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0z2n1qwad86zkcmmq883bw8rgidjsqjphrbqf1mwyfi5y22jhxfp"; + sha256 = "0hy3kbcb6nwydy312rhjm4b30yavmayszzzyjpfdv6p0s8d9mfvb"; type = "gem"; }; - version = "2.1.2"; + version = "2.1.3"; }; treetop = { dependencies = ["polyglot"]; @@ -2513,10 +2460,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0g31pijhnv7z960sd09lckmw9h8rs3wmc8g4ihmppszxqm99zpv7"; + sha256 = "0697qz1akblf8r3wi0s2dsjh468hfsd57fb0mrp93z35y2ni6bhh"; type = "gem"; }; - version = "1.6.10"; + version = "1.6.11"; }; typhoeus = { dependencies = ["ethon"]; @@ -2524,10 +2471,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0cni8b1idcp0dk8kybmxydadhfpaj3lbs99w5kjibv8bsmip2zi5"; + sha256 = "1m22yrkmbj81rzhlny81j427qdvz57yk5wbcf3km0nf3bl6qiygz"; type = "gem"; }; - version = "1.3.1"; + version = "1.4.0"; }; tzinfo = { dependencies = ["thread_safe"]; @@ -2535,10 +2482,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "04f18jdv6z3zn3va50rqq35nj3izjpb72fnf21ixm7vanq6nc4fp"; + sha256 = "0skr6ih9cr3pwp8l84f0z7fy3q9kiq8hw0sg3zqw0hpbbyj05743"; type = "gem"; }; - version = "1.2.6"; + version = "1.2.8"; }; unf = { dependencies = ["unf_ext"]; @@ -2556,20 +2503,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1ll6w64ibh81qwvjx19h8nj7mngxgffg7aigjx11klvf5k2g4nxf"; + sha256 = "0wc47r23h063l8ysws8sy24gzh74mks81cak3lkzlrw4qkqb3sg4"; type = "gem"; }; - version = "0.0.7.6"; + version = "0.0.7.7"; }; unicode-display_width = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "08kfiniak1pvg3gn5k6snpigzvhvhyg7slmm0s2qx5zkj62c1z2w"; + sha256 = "06i3id27s60141x6fdnjn5rar1cywdwy64ilc59cz937303q3mna"; type = "gem"; }; - version = "1.6.0"; + version = "1.7.0"; }; uuid4r = { groups = ["default"]; @@ -2581,15 +2528,36 @@ }; version = "0.2.0"; }; + websocket-driver = { + dependencies = ["websocket-extensions"]; + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1i3rs4kcj0jba8idxla3s6xd1xfln3k8b4cb1dik2lda3ifnp3dh"; + type = "gem"; + }; + version = "0.7.3"; + }; + websocket-extensions = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "0hc2g9qps8lmhibl5baa91b4qx8wqw872rgwagml78ydj8qacsqw"; + type = "gem"; + }; + version = "0.1.5"; + }; whois = { groups = ["default"]; platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "177qbah62yhy2q7znlrs49jwabw7vpd9frv6hw6mm0bxj5fn7prg"; + sha256 = "0ch19amq0spj5dc240mv6s8hh245w7nis2h070qr3jm15r4jb21m"; type = "gem"; }; - version = "5.0.0"; + version = "5.0.1"; }; xcodeproj = { dependencies = ["CFPropertyList" "atomos" "claide" "colored2" "nanaimo"]; @@ -2597,10 +2565,10 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "1h9iba53mrb663qdqzpfbdwkwzqv7hndd0df71yr2kj2hzwjmkvb"; + sha256 = "1411j6sfnz0cx4fiw52f0yqx4bgcn8cmpgi3i5rwmmahayyjz2fn"; type = "gem"; }; - version = "1.14.0"; + version = "1.19.0"; }; xctasks = { dependencies = ["nokogiri" "rake"]; @@ -2618,10 +2586,20 @@ platforms = []; source = { remotes = ["https://rubygems.org"]; - sha256 = "0rxqwry3h2hjz069f0kfr140wgx1khgljnqf112dk5x9rm4l0xny"; + sha256 = "126m49mvh4lbvlvrprq7xj2vjixbq3xqr8dwr089vadvs0rkn4rd"; + type = "gem"; + }; + version = "0.9.25"; + }; + zeitwerk = { + groups = ["default"]; + platforms = []; + source = { + remotes = ["https://rubygems.org"]; + sha256 = "1746czsjarixq0x05f7p3hpzi38ldg6wxnxxw74kbjzh1sdjgmpl"; type = "gem"; }; - version = "0.9.20"; + version = "2.4.2"; }; ZenTest = { groups = ["default"]; |