diff options
Diffstat (limited to 'configs')
47 files changed, 2638 insertions, 0 deletions
diff --git a/configs/autotether.nix b/configs/autotether.nix new file mode 100644 index 0000000..43b5575 --- /dev/null +++ b/configs/autotether.nix @@ -0,0 +1,19 @@ +{ config, pkgs, ... }: let + cfg.serial = "17e064850405"; +in { + systemd.services.usb_tether.serviceConfig = { + SyslogIdentifier = "usb_tether"; + ExecStartPre = "${pkgs.android-tools}/bin/adb -s ${cfg.serial} wait-for-device"; + ExecStart = "${pkgs.android-tools}/bin/adb -s ${cfg.serial} shell svc usb setFunctions rndis"; + }; + services.udev.extraRules = /* sh */ '' + ACTION=="add", SUBSYSTEM=="net", KERNEL=="usb*", NAME="android" + + ACTION=="add", SUBSYSTEM=="usb", ATTR{serial}=="${cfg.serial}", \ + TAG+="systemd", ENV{SYSTEMD_WANTS}="usb_tether.service" + ''; + systemd.network.networks.android = { + matchConfig.Name = "android"; + DHCP = "yes"; + }; +} diff --git a/configs/backup.nix b/configs/backup.nix new file mode 100644 index 0000000..30d6011 --- /dev/null +++ b/configs/backup.nix @@ -0,0 +1,108 @@ +{ config, lib, mylib, pkgs, ... }: { + krebs.backup.plans = { + } // lib.mapAttrs (_: lib.recursiveUpdate { + snapshots = { + daily = { format = "%Y-%m-%d"; retain = 7; }; + weekly = { format = "%YW%W"; retain = 4; }; + monthly = { format = "%Y-%m"; retain = 12; }; + yearly = { format = "%Y"; }; + }; + }) { + bu-home-xu = { + method = "push"; + src = { host = config.krebs.hosts.bu; path = "/home"; }; + dst = { host = config.krebs.hosts.xu; path = "/bku/bu-home"; }; + startAt = "05:20"; + }; + bu-home-zu = { + method = "push"; + src = { host = config.krebs.hosts.bu; path = "/home"; }; + dst = { host = config.krebs.hosts.zu; path = "/bku/bu-home"; }; + startAt = "05:25"; + }; + nomic-home-xu = { + method = "push"; + src = { host = config.krebs.hosts.nomic; path = "/home"; }; + dst = { host = config.krebs.hosts.xu; path = "/bku/nomic-home"; }; + startAt = "05:00"; + }; + nomic-home-zu = { + method = "push"; + src = { host = config.krebs.hosts.nomic; path = "/home"; }; + dst = { host = config.krebs.hosts.zu; path = "/bku/nomic-home"; }; + startAt = "04:20"; + }; + nomic-pull-querel-home = { + method = "pull"; + src = { host = config.krebs.hosts.querel; path = "/home"; }; + dst = { host = config.krebs.hosts.nomic; path = "/fs/ponyhof/bku/querel-home"; }; + startAt = "22:00"; + }; + xu-home-bu = { + method = "push"; + src = { host = config.krebs.hosts.xu; path = "/home"; }; + dst = { host = config.krebs.hosts.bu; path = "/bku/xu-home"; }; + startAt = "04:50"; + }; + xu-home-nomic = { + method = "push"; + src = { host = config.krebs.hosts.xu; path = "/home"; }; + dst = { host = config.krebs.hosts.nomic; path = "/fs/cis3hG/bku/xu-home"; }; + startAt = "05:20"; + }; + xu-home-zu = { + method = "push"; + src = { host = config.krebs.hosts.xu; path = "/home"; }; + dst = { host = config.krebs.hosts.zu; path = "/bku/xu-home"; }; + startAt = "06:20"; + }; + xu-pull-ni-ejabberd = { + method = "pull"; + src = { host = config.krebs.hosts.ni; path = "/var/lib/ejabberd"; }; + dst = { host = config.krebs.hosts.xu; path = "/bku/ni-ejabberd"; }; + startAt = "07:00"; + }; + xu-pull-ni-home = { + method = "pull"; + src = { host = config.krebs.hosts.ni; path = "/home"; }; + dst = { host = config.krebs.hosts.xu; path = "/bku/ni-home"; }; + startAt = "07:00"; + }; + zu-home-xu = { + method = "push"; + src = { host = config.krebs.hosts.zu; path = "/home"; }; + dst = { host = config.krebs.hosts.xu; path = "/bku/zu-home"; }; + startAt = "05:00"; + }; + zu-pull-ni-ejabberd = { + method = "pull"; + src = { host = config.krebs.hosts.ni; path = "/var/lib/ejabberd"; }; + dst = { host = config.krebs.hosts.zu; path = "/bku/ni-ejabberd"; }; + startAt = "06:00"; + }; + zu-pull-ni-home = { + method = "pull"; + src = { host = config.krebs.hosts.ni; path = "/home"; }; + dst = { host = config.krebs.hosts.zu; path = "/bku/ni-home"; }; + startAt = "06:30"; + }; + } // lib.mapAttrs (_: lib.recursiveUpdate { + snapshots = { + minutely = { format = "%Y-%m-%dT%H:%M"; retain = 3; }; + hourly = { format = "%Y-%m-%dT%H"; retain = 3; }; + daily = { format = "%Y-%m-%d"; retain = 3; }; + }; + startAt = null; + }) { + xu-test-push-xu = { + method = "push"; + src = { host = config.krebs.hosts.xu; path = "/tmp/xu-bku-test-data"; }; + dst = { host = config.krebs.hosts.xu; path = "/bku/xu-test-push"; }; + }; + xu-test-pull-xu = { + method = "pull"; + src = { host = config.krebs.hosts.xu; path = "/tmp/xu-bku-test-data"; }; + dst = { host = config.krebs.hosts.xu; path = "/bku/xu-test-pull"; }; + }; + }; +} diff --git a/configs/bash/default.nix b/configs/bash/default.nix new file mode 100644 index 0000000..2e18d5b --- /dev/null +++ b/configs/bash/default.nix @@ -0,0 +1,66 @@ +{ config, mylib, pkgs, ... }: { + programs.bash = { + interactiveShellInit = /* sh */ '' + HISTCONTROL='erasedups:ignorespace' + HISTSIZE=900001 + HISTFILESIZE=$HISTSIZE + HISTTIMEFORMAT= + + shopt -s checkhash + shopt -s histappend histreedit histverify + shopt -s no_empty_cmd_completion + complete -d cd + + case $UID in + ${mylib.shell.escape (toString config.krebs.users.tv.uid)}) + if test ''${SHLVL-1} = 1 && test -n "''${DISPLAY-}"; then + _CURRENT_DESKTOP_NAME=''${_CURRENT_DESKTOP_NAME-$( + ${pkgs.xorg.xprop}/bin/xprop -notype -root \ + 32i _NET_CURRENT_DESKTOP \ + 8s _NET_DESKTOP_NAMES \ + | + ${pkgs.gnused}/bin/sed -r 's/.* = //;s/"//g;s/, /\a/g' | + { + read -r _NET_CURRENT_DESKTOP + IFS=$'\a' read -ra _NET_DESKTOP_NAMES + echo "''${_NET_DESKTOP_NAMES[$_NET_CURRENT_DESKTOP]}" + } + )} + case $_CURRENT_DESKTOP_NAME in + stockholm) + cd ~/stockholm + ;; + esac + fi + + export NIX_PATH="stockholm=$HOME/stockholm:$NIX_PATH" + ;; + esac + + ${pkgs.bash-fzf-history.bind} + + if test -n "''${BASH_EXTRA_INIT-}"; then + . "$BASH_EXTRA_INIT" + fi + ''; + promptInit = /* sh */ '' + case $UID in + 0) + PS1='\[\e[1;31m\]\w\[\e[0m\] ' + ;; + ${toString config.krebs.build.user.uid}) + PS1='\[\e[1;32m\]\w\[\e[0m\] ' + ;; + *) + PS1='\[\e[1;35m\]\u \[\e[1;32m\]\w\[\e[0m\] ' + ;; + esac + if test -n "$SSH_CLIENT"; then + PS1='\[\e[35m\]\h'" $PS1" + fi + if test -n "$SSH_AGENT_PID"; then + PS1="ssh-agent[$SSH_AGENT_PID] $PS1" + fi + ''; + }; +} diff --git a/configs/binary-cache/default.nix b/configs/binary-cache/default.nix new file mode 100644 index 0000000..d9e87c7 --- /dev/null +++ b/configs/binary-cache/default.nix @@ -0,0 +1,28 @@ +{ config, pkgs, ... }: { + environment.etc."binary-cache.pubkey".text = + config.krebs.build.host.binary-cache.pubkey; + + nixpkgs.overlays = [ + (self: super: { + nix-serve = self.haskellPackages.nix-serve-ng; + }) + ]; + + services.nix-serve = { + enable = true; + secretKeyFile = "${config.krebs.secret.directory}/nix-serve.key"; + }; + + services.nginx = { + enable = true; + virtualHosts.nix-serve = { + serverAliases = [ + "cache.${config.krebs.build.host.name}.hkw" + "cache.${config.krebs.build.host.name}.r" + ]; + locations."/".extraConfig = '' + proxy_pass http://localhost:${toString config.services.nix-serve.port}; + ''; + }; + }; +} diff --git a/configs/br.nix b/configs/br.nix new file mode 100644 index 0000000..b9bc70b --- /dev/null +++ b/configs/br.nix @@ -0,0 +1,49 @@ +{ config, lib, modulesPath, mylib, pkgs, ... }: { + + imports = [ + (modulesPath + "/services/hardware/sane_extra_backends/brscan4.nix") + ]; + + krebs.nixpkgs.allowUnfreePredicate = + pkg: lib.any (mylib.eq (mylib.packageName pkg)) [ + "brother-udev-rule-type1" + "brscan4" + "brscan4-etc-files" + "mfcl2700dnlpr" + ]; + + hardware.sane = { + enable = true; + brscan4 = { + enable = true; + netDevices = { + bra = { + model = "MFCL2700DN"; + ip = "10.23.1.214"; + }; + }; + }; + }; + + services.saned.enable = true; + + # usage: scanimage -d "$(find-scanner bra)" --batch --format=tiff --resolution 150 -x 211 -y 298 + environment.systemPackages = [ + (pkgs.writeDashBin "find-scanner" '' + set -efu + name=$1 + ${pkgs.sane-backends}/bin/scanimage -f '%m %d + ' \ + | ${pkgs.gawk}/bin/awk -v dev="*$name" '$1 == dev { print $2; exit }' \ + | ${pkgs.gnugrep}/bin/grep . + '') + ]; + + services.printing = { + enable = true; + drivers = [ + pkgs.mfcl2700dncupswrapper + ]; + }; + +} diff --git a/configs/default.nix b/configs/default.nix new file mode 100644 index 0000000..5d74d96 --- /dev/null +++ b/configs/default.nix @@ -0,0 +1,131 @@ +{ config, inputs, lib, mylib, pkgs, ... }: { + boot.tmpOnTmpfs = true; + + krebs.enable = true; + + krebs.build.user = config.krebs.users.tv; + + networking.hostId = lib.mkDefault (mylib.hashToLength 8 config.networking.hostName); + networking.hostName = config.krebs.build.host.name; + + imports = [ + ./backup.nix + ./bash + ./htop.nix + ./nets/hkw.nix + ./networkd.nix + ./nginx + ./nix.nix + ./pki + ./ssh.nix + ./sshd.nix + ./vim.nix + ./xdg.nix + { + users = { + defaultUserShell = "/run/current-system/sw/bin/bash"; + mutableUsers = false; + users = { + tv = { + inherit (config.krebs.users.tv) home uid; + isNormalUser = true; + extraGroups = [ "tv" ]; + }; + }; + }; + } + { + i18n.defaultLocale = lib.mkDefault "C.UTF-8"; + security.sudo.extraConfig = '' + Defaults env_keep+="SSH_CLIENT _CURRENT_DESKTOP_NAME" + Defaults mailto="${config.krebs.users.tv.mail}" + Defaults !lecture + ''; + time.timeZone = "Europe/Berlin"; + } + + { + nixpkgs.config.allowUnfree = false; + } + { + environment.homeBinInPath = true; + + environment.profileRelativeEnvVars.PATH = lib.mkForce [ "/bin" ]; + + environment.systemPackages = with pkgs; [ + rxvt_unicode.terminfo + ]; + + environment.shellAliases = lib.mkForce { + gp = "${pkgs.pari}/bin/gp -q"; + df = "df -h"; + du = "du -h"; + + # TODO alias cannot contain #\' + # "ps?" = "ps ax | head -n 1;ps ax | fgrep -v ' grep --color=auto ' | grep"; + + ls = "ls -h --color=auto --group-directories-first"; + dmesg = "dmesg -L --reltime"; + view = "vim -R"; + }; + + environment.variables = { + NIX_PATH = lib.mkForce (lib.concatStringsSep ":" [ + "secrets=/var/src/stockholm/null" + "/var/src" + ]); + }; + } + + { + services.cron.enable = false; + services.ntp.enable = false; + services.timesyncd.enable = true; + } + + { + boot.kernel.sysctl = { + # Enable IPv6 Privacy Extensions + # + # XXX use mkForce here because since NixOS 21.11 there's a collision in + # net.ipv6.conf.default.use_tempaddr, and boot.kernel.sysctl incapable + # of merging. + # + # XXX net.ipv6.conf.all.use_tempaddr is set because it was mentioned in + # https://tldp.org/HOWTO/Linux+IPv6-HOWTO/ch06s05.html + # TODO check if that is really necessary, otherwise we can rely solely + # on networking.tempAddresses in the future (when nothing is <21.11) + "net.ipv6.conf.all.use_tempaddr" = lib.mkForce 2; + "net.ipv6.conf.default.use_tempaddr" = lib.mkForce 2; + }; + } + + { + tv.iptables.enable = true; + tv.iptables.accept-echo-request = "internet"; + } + + { + services.journald.extraConfig = '' + SystemMaxUse=1G + RuntimeMaxUse=128M + ''; + } + + { + environment.systemPackages = [ + pkgs.field + pkgs.get + pkgs.git + pkgs.git-crypt + pkgs.git-preview + pkgs.hashPassword + pkgs.htop + pkgs.kpaste + pkgs.nix-prefetch-scripts + pkgs.ovh-zone + pkgs.push + ]; + } + ]; +} diff --git a/configs/elm-packages-proxy.nix b/configs/elm-packages-proxy.nix new file mode 100644 index 0000000..caea188 --- /dev/null +++ b/configs/elm-packages-proxy.nix @@ -0,0 +1,359 @@ +{ config, lib, pkgs, ... }: let + + cfg.nameserver = "1.1.1.1"; + cfg.packageDir = "/var/lib/elm-packages"; + cfg.port = 7782; + + # TODO secret files + cfg.htpasswd = "/var/lib/certs/package.elm-lang.org/htpasswd"; + cfg.sslCertificate = "/var/lib/certs/package.elm-lang.org/fullchain.pem"; + cfg.sslCertificateKey = "/var/lib/certs/package.elm-lang.org/key.pem"; + + semverRegex = + "(?<major>0|[1-9]\\d*)\\.(?<minor>0|[1-9]\\d*)\\.(?<patch>0|[1-9]\\d*)(?:-(?<prerelease>(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?"; + +in { + services.nginx.virtualHosts."package.elm-lang.org" = { + addSSL = true; + + sslCertificate = cfg.sslCertificate; + sslCertificateKey = cfg.sslCertificateKey; + + locations."/all-packages".extraConfig = '' + proxy_pass http://127.0.0.1:${toString config.krebs.htgen.elm-packages-proxy.port}; + proxy_pass_header Server; + ''; + + locations."/all-packages/since/".extraConfig = '' + proxy_pass http://127.0.0.1:${toString config.krebs.htgen.elm-packages-proxy.port}; + proxy_pass_header Server; + ''; + + locations."~ ^/packages/(?<author>[A-Za-z0-9-]+)/(?<pname>[A-Za-z0-9-]+)/(?<version>${semverRegex})\$".extraConfig = '' + auth_basic "Restricted Area"; + auth_basic_user_file ${cfg.htpasswd}; + + proxy_set_header X-User $remote_user; + proxy_set_header X-Author $author; + proxy_set_header X-Package $pname; + proxy_set_header X-Version $version; + proxy_pass_header Server; + + proxy_pass http://127.0.0.1:${toString config.krebs.htgen.elm-packages-proxy.port}; + ''; + + locations."~ ^/packages/(?<author>[A-Za-z0-9-]+)/(?<pname>[A-Za-z0-9-]+)/(?<version>${semverRegex})/(?:zipball|elm.json|endpoint.json)\$".extraConfig = '' + set $zipball "${cfg.packageDir}/$author/$pname/$version/zipball"; + proxy_set_header X-Author $author; + proxy_set_header X-Package $pname; + proxy_set_header X-Version $version; + proxy_set_header X-Zipball $zipball; + proxy_pass_header Server; + resolver ${cfg.nameserver}; + + if (-f $zipball) { + set $new_uri http://127.0.0.1:${toString config.krebs.htgen.elm-packages-proxy.port}; + } + if (!-f $zipball) { + set $new_uri https://package.elm-lang.org$request_uri; + } + + proxy_pass $new_uri; + ''; + + locations."/search.json".extraConfig = '' + proxy_pass http://127.0.0.1:${toString config.krebs.htgen.elm-packages-proxy.port}; + proxy_pass_header Server; + ''; + }; + + krebs.htgen.elm-packages-proxy = { + port = cfg.port; + script = /* sh */ ''. ${pkgs.writeDash "elm-packages-proxy.sh" '' + PATH=${lib.makeBinPath [ + pkgs.attr + pkgs.coreutils + pkgs.curl + pkgs.findutils + pkgs.gnugrep + pkgs.jq + pkgs.p7zip + ]} + export PATH + file_response() {( + status_code=$1 + status_reason=$2 + file=$3 + content_type=$4 + + content_length=$(wc -c "$file" | cut -d\ -f1) + + printf "HTTP/1.1 $status_code $status_reason\r\n" + printf 'Connection: close\r\n' + printf 'Content-Length: %d\r\n' "$content_length" + printf 'Content-Type: %s\r\n' "$content_type" + printf 'Server: %s\r\n' "$Server" + printf '\r\n' + cat "$file" + )} + string_response() {( + status_code=$1 + status_reason=$2 + response_body=$3 + content_type=$4 + + printf "HTTP/1.1 $status_code $status_reason\r\n" + printf 'Connection: close\r\n' + printf 'Content-Length: %d\r\n' "$(expr ''${#response_body} + 1)" + printf 'Content-Type: %s\r\n' "$content_type" + printf 'Server: %s\r\n' "$Server" + printf '\r\n' + printf '%s\n' "$response_body" + )} + + case "$Method $Request_URI" in + 'GET /packages/'*) + + author=$req_x_author + pname=$req_x_package + version=$req_x_version + + zipball=${cfg.packageDir}/$author/$pname/$version/zipball + elmjson=$HOME/cache/$author%2F$pname%2F$version%2Felm.json + endpointjson=$HOME/cache/$author%2F$pname%2F$version%2Fendpoint.json + mkdir -p "$HOME/cache" + + case $(basename $Request_URI) in + zipball) + file_response 200 OK "$zipball" application/zip + exit + ;; + elm.json) + if ! test -f "$elmjson"; then + 7z x -so "$zipball" \*/elm.json > "$elmjson" + fi + file_response 200 OK "$elmjson" 'application/json; charset=UTF-8' + exit + ;; + endpoint.json) + if ! test -f "$endpointjson"; then + hash=$(sha1sum "$zipball" | cut -d\ -f1) + url=https://package.elm-lang.org/packages/$author/$pname/$version/zipball + jq -n \ + --arg hash "$hash" \ + --arg url "$url" \ + '{ $hash, $url }' \ + > "$endpointjson" + fi + file_response 200 OK "$endpointjson" 'application/json; charset=UTF-8' + exit + ;; + esac + ;; + 'POST /packages/'*) + + author=$req_x_author + pname=$req_x_package + user=$req_x_user + version=$req_x_version + + action=uploading + force=''${req_x_force-false} + zipball=${cfg.packageDir}/$author/$pname/$version/zipball + elmjson=$HOME/cache/$author%2F$pname%2F$version%2Felm.json + endpointjson=$HOME/cache/$author%2F$pname%2F$version%2Fendpoint.json + + if test -e "$zipball"; then + if test "$force" = true; then + zipball_owner=$(attr -q -g X-User "$zipball" || :) + if test "$zipball_owner" = "$req_x_user"; then + action=replacing + rm -f "$elmjson" + rm -f "$endpointjson" + else + string_response 403 Forbidden \ + "package already exists: $author/$pname@$version" \ + text/plain + exit + fi + else + string_response 409 Conflict \ + "package already exists: $author/$pname@$version" \ + text/plain + exit + fi + fi + + echo "user $user is $action package $author/$pname@$version" >&2 + # TODO check package + mkdir -p "$(dirname "$zipball")" + head -c $req_content_length > "$zipball" + + attr -q -s X-User -V "$user" "$zipball" || : + + string_response 200 OK \ + "package created: $author/$pname@$version" \ + text/plain + + exit + ;; + 'DELETE /packages/'*) + + author=$req_x_author + pname=$req_x_package + user=$req_x_user + version=$req_x_version + + zipball=${cfg.packageDir}/$author/$pname/$version/zipball + elmjson=$HOME/cache/$author%2F$pname%2F$version%2Felm.json + endpointjson=$HOME/cache/$author%2F$pname%2F$version%2Fendpoint.json + + if test -e "$zipball"; then + zipball_owner=$(attr -q -g X-User "$zipball" || :) + if test "$zipball_owner" = "$req_x_user"; then + echo "user $user is deleting package $author/$pname@$version" >&2 + rm -f "$elmjson" + rm -f "$endpointjson" + rm "$zipball" + string_response 200 OK \ + "package deleted: $author/$pname@$version" \ + text/plain + exit + else + string_response 403 Forbidden \ + "package already exists: $author/$pname@$version" \ + text/plain + exit + fi + fi + ;; + 'GET /all-packages'|'POST /all-packages') + + response=$(mktemp -t htgen.$$.elm-packages-proxy.all-packages.XXXXXXXX) + trap "rm $response >&2" EXIT + + { + # upstream packages + curl -fsS https://package.elm-lang.org"$Request_URI" + + # private packages + (cd ${cfg.packageDir}; find -mindepth 3 -maxdepth 3) | + jq -Rs ' + split("\n") | + map( + select(.!="") | + match("^\\./(?<author>[^/]+)/(?<pname>[^/]+)/(?<version>[^/]+)$").captures | + map({key:.name,value:.string}) | + from_entries + ) | + reduce .[] as $item ({}; + ($item|"\(.author)/\(.pname)") as $name | + . + { "\($name)": ((.[$name] // []) + [$item.version]) } + ) + ' + } | + jq -cs add > $response + + file_response 200 OK "$response" 'application/json; charset=UTF-8' + exit + ;; + 'GET /all-packages/since/'*|'POST /all-packages/since/'*) + + response=$(mktemp -t htgen.$$.elm-packages-proxy.all-packages.XXXXXXXX) + trap "rm $response >&2" EXIT + + { + # upstream packages + curl -fsS https://package.elm-lang.org"$Request_URI" + + # private packages + (cd ${cfg.packageDir}; find -mindepth 3 -maxdepth 3) | + jq -Rs ' + split("\n") | + map( + select(.!="") | + sub("^\\./(?<author>[^/]+)/(?<pname>[^/]+)/(?<version>[^/]+)$";"\(.author)/\(.pname)@\(.version)") + ) | + sort_by(split("@") | [.[0]]+(.[1]|split(".")|map(tonumber))) | + reverse + ' + } | + jq -cs add > $response + + file_response 200 OK "$response" 'application/json; charset=UTF-8' + exit + ;; + 'GET /search.json') + + searchjson=$HOME/cache/search.json + mkdir -p "$HOME/cache" + + # update cached search.json + ( + last_modified=$( + if test -f "$searchjson"; then + date -Rr "$searchjson" + else + date -R -d @0 + fi + ) + tempsearchjson=$(mktemp "$searchjson.XXXXXXXX") + trap 'rm "$tempsearchjson" >&2' EXIT + curl -fsS --compressed https://package.elm-lang.org/search.json \ + -H "If-Modified-Since: $last_modified" \ + -o "$tempsearchjson" + if test -s "$tempsearchjson"; then + mv "$tempsearchjson" "$searchjson" + trap - EXIT + fi + ) + + response=$(mktemp -t htgen.$$.elm-packages-proxy.search.XXXXXXXX) + trap 'rm "$response" >&2' EXIT + + { + printf '{"upstream":'; cat "$searchjson" + printf ',"private":'; (cd ${cfg.packageDir}; find -mindepth 3 -maxdepth 3) | + jq -Rs ' + split("\n") | + map( + select(.!="") | + match("^\\./(?<author>[^/]+)/(?<pname>[^/]+)/(?<version>[^/]+)$").captures | + map({key:.name,value:.string}) | + from_entries + ) | + map({ + key: "\(.author)/\(.pname)", + value: .version, + }) | + from_entries + ' + printf '}' + } | + jq -c ' + reduce .upstream[] as $upstreamItem ({ private, output: [] }; + .private[$upstreamItem.name] as $privateItem | + if $privateItem then + .output += [$upstreamItem * { version: $privateItem.version }] | + .private |= del(.[$upstreamItem.name]) + else + .output += [$upstreamItem] + end + ) | + + .output + (.private | to_entries | sort_by(.key) | map({ + name: .key, + version: .value, + summary: "dummy summary", + license: "dummy license", + })) + ' \ + > $response + + file_response 200 OK "$response" 'application/json; charset=UTF-8' + exit + ;; + esac + ''}''; + }; +} diff --git a/configs/exim-retiolum.nix b/configs/exim-retiolum.nix new file mode 100644 index 0000000..7903ac3 --- /dev/null +++ b/configs/exim-retiolum.nix @@ -0,0 +1,8 @@ +{ config, pkgs, ... }: { + environment.systemPackages = [ + pkgs.eximlog + ]; + krebs.exim-retiolum.enable = true; + krebs.exim-retiolum.rspamd.enable = config.krebs.build.host.name == "nomic"; + tv.iptables.input-retiolum-accept-tcp = [ "smtp" ]; +} diff --git a/configs/exim-smarthost.nix b/configs/exim-smarthost.nix new file mode 100644 index 0000000..d983165 --- /dev/null +++ b/configs/exim-smarthost.nix @@ -0,0 +1,45 @@ +{ config, lib, pkgs, ... }: { + environment.systemPackages = [ + pkgs.eximlog + ]; + krebs.exim-smarthost = { + enable = true; + dkim = [ + { domain = "viljetic.de"; } + ]; + sender_domains = [ + "krebsco.de" + "shackspace.de" + "viljetic.de" + ]; + relay_from_hosts = lib.concatMap (host: host.nets.retiolum.addrs) [ + config.krebs.hosts.nomic + config.krebs.hosts.xu + ]; + internet-aliases = with config.krebs.users; [ + { from = "bku-eppler@viljetic.de"; to = tv.mail; } + { from = "postmaster@viljetic.de"; to = tv.mail; } # RFC 822 + { from = "mirko@viljetic.de"; to = mv-ni.mail; } + { from = "tomislav@viljetic.de"; to = tv.mail; } + { from = "tv@viljetic.de"; to = tv.mail; } + { from = "tv@shackspace.de"; to = tv.mail; } + ]; + system-aliases = [ + { from = "mailer-daemon"; to = "postmaster"; } + { from = "postmaster"; to = "root"; } + { from = "nobody"; to = "root"; } + { from = "hostmaster"; to = "root"; } + { from = "usenet"; to = "root"; } + { from = "news"; to = "root"; } + { from = "webmaster"; to = "root"; } + { from = "www"; to = "root"; } + { from = "ftp"; to = "root"; } + { from = "abuse"; to = "root"; } + { from = "noc"; to = "root"; } + { from = "security"; to = "root"; } + { from = "root"; to = "tv"; } + { from = "mirko"; to = "mv"; } + ]; + }; + tv.iptables.input-internet-accept-tcp = lib.singleton "smtp"; +} diff --git a/configs/fs/CAC-CentOS-7-64bit.nix b/configs/fs/CAC-CentOS-7-64bit.nix new file mode 100644 index 0000000..c9eb97f --- /dev/null +++ b/configs/fs/CAC-CentOS-7-64bit.nix @@ -0,0 +1,20 @@ +_: + +{ + boot.loader.grub = { + device = "/dev/sda"; + }; + fileSystems = { + "/" = { + device = "/dev/centos/root"; + fsType = "xfs"; + }; + "/boot" = { + device = "/dev/sda1"; + fsType = "xfs"; + }; + }; + swapDevices = [ + { device = "/dev/centos/swap"; } + ]; +} diff --git a/configs/gitconfig.nix b/configs/gitconfig.nix new file mode 100644 index 0000000..c4111ed --- /dev/null +++ b/configs/gitconfig.nix @@ -0,0 +1,15 @@ +{ pkgs, ... }: { + environment.etc.gitconfig.text = '' + [alias] + patch = !${pkgs.git}/bin/git --no-pager diff --no-color + [diff-so-fancy] + markEmptyLines = false + stripLeadingSymbols = false + [pager] + diff = ${pkgs.gitAndTools.diff-so-fancy}/bin/diff-so-fancy \ + | ${pkgs.less}/bin/less -FRX + [user] + email = tv@krebsco.de + name = tv + ''; +} diff --git a/configs/gitrepos.nix b/configs/gitrepos.nix new file mode 100644 index 0000000..c69ffa4 --- /dev/null +++ b/configs/gitrepos.nix @@ -0,0 +1,237 @@ +{ config, lib, mylib, pkgs, ... }: let { + + body = { + + nixpkgs.config.packageOverrides = super: { + cgit = pkgs.symlinkJoin { + name = "${super.cgit.name}-tv"; + paths = [ + (pkgs.runCommand "${super.cgit.name}-tv-overrides" { + } /* sh */ '' + mkdir -p $out/lib/cgit/filters + cd $out/lib/cgit/filters + cp \ + ${super.cgit}/lib/cgit/filters/syntax-highlighting.py \ + ${super.cgit}/lib/cgit/filters/.syntax-highlighting.py-wrapped \ + . + sed -i "s:${super.cgit}:$out:" syntax-highlighting.py + sed -i ' + s:^\(formatter =\).*:\1 HtmlFormatter(style="algol_nu"): + ' .syntax-highlighting.py-wrapped + '') + super.cgit + ]; + }; + }; + + krebs.git = { + enable = true; + cgit = { + settings = { + about-filter = pkgs.exec "krebs.cgit.about-filter" rec { + filename = "${pkgs.python3Packages.markdown2}/bin/markdown2"; + argv = [ + filename + "--extras=fenced-code-blocks" + ]; + envp = {}; + }; + readme = [ + ":README.md" + ]; + root-desc = "mostly krebs"; + root-title = "repositories at ${config.krebs.build.host.name}"; + source-filter = "${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py"; + }; + }; + repos = repos; + rules = rules; + }; + }; + + cgit-clear-cache = pkgs.cgit-clear-cache.override { + inherit (config.krebs.git.cgit.settings) cache-root; + }; + + repos = + public-repos // + lib.optionalAttrs config.krebs.build.host.secure restricted-repos; + + rules = lib.concatMap make-rules (builtins.attrValues repos); + + public-repos = lib.mapAttrs make-public-repo ({ + } // lib.mapAttrs (_: lib.recursiveUpdate { cgit.section = "1. miscellaneous"; }) { + couchfs = { + cgit.desc = "filesystem (in userspace) on top of CouchDB"; + }; + crx = { + cgit.desc = "utilities for working with Chrome extensions"; + }; + dic = { + cgit.desc = "dict.leo.org command line interface"; + }; + disko = { + cgit.desc = "declarative partitioning and formatting tool"; + }; + fswm = { + cgit.desc = "simple full screen window manager"; + }; + htgen = { + cgit.desc = "toy HTTP server"; + }; + ircaids = { + cgit.desc = "Assortment of aids for working with Internet relay chat"; + }; + krops = { + cgit.desc = "deployment tools"; + }; + mailaids = { + cgit.desc = "Assortment of aids for working with electronic mail"; + }; + much = {}; + netcup = { + cgit.desc = "netcup command line interface"; + }; + nix-writers = { + cgit.desc = "collection of package builders"; + }; + nixpkgs = { + cgit.desc = "Nix Packages collection"; + }; + pager = { + }; + populate = { + cgit.desc = "source code installer"; + }; + q = {}; + reaktor2 = {}; + stockholm = { + cgit.desc = "NixOS configuration"; + }; + TabFS = { + cgit.desc = "mount browser tabs & co. as a filesystem"; + }; + texnix = { + cgit.desc = "TeX live environment generator"; + }; + with-ssh = {}; + } // lib.mapAttrs (_: lib.recursiveUpdate { cgit.section = "2. Host configurations"; }) { + ni = { + }; + } // lib.mapAttrs (_: lib.recursiveUpdate { cgit.section = "3. Haskell libraries"; }) { + X11-aeson = {}; + blessings = {}; + hack = {}; + hc = {}; + mime = {}; + quipper = {}; + scanner = {}; + wai-middleware-time = {}; + web-routes-wai-custom = {}; + xintmap = {}; + xmonad-aeson = {}; + xmonad-web = {}; + } // lib.mapAttrs (_: lib.recursiveUpdate { cgit.section = "4. museum"; }) { + cac-api = { + cgit.desc = "CloudAtCost API command line interface"; + }; + cgserver = {}; + crude-mail-setup = {}; + dot-xmonad = {}; + flameshot-once = { + cgit.desc = "flameshot runner that automatically starts/stops the daemon"; + }; + hirc = {}; + hstool = { + cgit.desc = "Haskell Development Environment ^_^"; + }; + kirk = { + cgit.desc = "IRC tools"; + }; + make-snapshot = {}; + nixos-infest = {}; + painload = {}; + push = {}; + Reaktor = {}; + regfish = {}; + with-tmpdir = {}; + get = {}; + load-env = {}; + loldns = { + cgit.desc = "toy DNS server"; + }; + soundcloud = { + cgit.desc = "SoundCloud command line interface"; + }; + xmonad-stockholm = {}; + }); + + restricted-repos = lib.mapAttrs make-restricted-repo ( + { + brain = { + collaborators = with config.krebs.users; [ lass makefu ]; + hooks = { + post-receive = /* sh */ '' + (${irc-announce { cgit_endpoint = null; }}) + ${cgit-clear-cache}/bin/cgit-clear-cache + ''; + }; + }; + } // + # TODO don't put secrets/repos.nix into the store + mylib.importSecret "repos.nix" { inherit config lib pkgs; } + ); + + irc-announce = args: pkgs.git-hooks.irc-announce (lib.recursiveUpdate { + channel = "#xxx"; + # TODO make nick = config.krebs.build.host.name the default + nick = config.krebs.build.host.name; + server = "irc.r"; + verbose = { + exclude = [ + "refs/heads/head" + ]; + }; + } args); + + make-public-repo = name: { cgit ? {}, ... }: { + inherit cgit name; + public = true; + hooks = { + post-receive = /* sh */ '' + (${lib.optionalString (config.krebs.build.host.name == "ni") + (irc-announce {})}) + ${cgit-clear-cache}/bin/cgit-clear-cache + ''; + }; + }; + + make-restricted-repo = name: { collaborators ? [], hooks ? {}, ... }: { + inherit collaborators name; + public = false; + hooks = hooks // { + post-receive = /* sh */ '' + (${hooks.post-receive or ":"}) + ${cgit-clear-cache}/bin/cgit-clear-cache + ''; + }; + }; + + make-rules = + with mylib.git // config.krebs.users; + repo: + [ + { + user = [ tv tv-xu ]; + repo = [ repo ]; + perm = push "refs/*" [ non-fast-forward create delete merge ]; + } + ] + ++ + lib.optional (repo.collaborators or [] != []) { + user = repo.collaborators; + repo = [ repo ]; + perm = fetch; + }; + +} diff --git a/configs/htop.nix b/configs/htop.nix new file mode 100644 index 0000000..e60cc51 --- /dev/null +++ b/configs/htop.nix @@ -0,0 +1,39 @@ +{ pkgs, ... }: { + nixpkgs.config.packageOverrides = super: { + htop = pkgs.symlinkJoin { + name = "htop"; + paths = [ + (pkgs.writeDashBin "htop" '' + export HTOPRC=${pkgs.writeText "htoprc" '' + fields=0 48 17 18 38 39 40 2 46 47 49 1 + sort_key=46 + sort_direction=1 + hide_threads=0 + hide_kernel_threads=1 + hide_userland_threads=0 + shadow_other_users=1 + show_thread_names=1 + show_program_path=1 + highlight_base_name=1 + highlight_megabytes=1 + highlight_threads=1 + tree_view=1 + header_margin=0 + detailed_cpu_time=0 + cpu_count_from_zero=0 + update_process_names=0 + account_guest_in_cpu_meter=1 + color_scheme=0 + delay=15 + left_meters=LeftCPUs2 RightCPUs2 Memory Swap + left_meter_modes=1 1 1 1 + right_meters=Uptime Tasks LoadAverage Battery + right_meter_modes=2 2 2 2 + ''} + exec ${super.htop}/bin/htop "$@" + '') + super.htop + ]; + }; + }; +} diff --git a/configs/hw/AO753.nix b/configs/hw/AO753.nix new file mode 100644 index 0000000..ea58c01 --- /dev/null +++ b/configs/hw/AO753.nix @@ -0,0 +1,47 @@ +{ config, ... }: { + imports = [ + ../smartd.nix + + { + nix.settings.cores = 2; + nix.settings.max-jobs = 2; + } + (if lib.versionAtLeast (lib.versions.majorMinor lib.version) "21.11" then { + nix.daemonCPUSchedPolicy = "batch"; + nix.daemonIOSchedPriority = 1; + } else { + nix.daemonIONiceLevel = 1; + nix.daemonNiceLevel = 1; + }) + ]; + + boot.loader.grub = { + device = "/dev/sda"; + splashImage = null; + }; + + boot.initrd.availableKernelModules = [ + "ahci" + ]; + + boot.kernelModules = [ + "kvm-intel" + "wl" + ]; + + boot.extraModulePackages = [ + config.boot.kernelPackages.broadcom_sta + ]; + + services.logind.extraConfig = '' + HandleHibernateKey=ignore + HandleLidSwitch=ignore + HandlePowerKey=ignore + HandleSuspendKey=ignore + ''; + + krebs.nixpkgs.allowUnfreePredicate = pkg: packageName pkg == "broadcom-sta"; + + tv.hw.screens.primary.width = 1366; + tv.hw.screens.primary.height = 768; +} diff --git a/configs/hw/winmax2.nix b/configs/hw/winmax2.nix new file mode 100644 index 0000000..7b28466 --- /dev/null +++ b/configs/hw/winmax2.nix @@ -0,0 +1,48 @@ +{ pkgs, ... }: { + + imports = [ + ../smartd.nix + ]; + + boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "thunderbolt" "usbhid" ]; + boot.initrd.kernelModules = [ "amdgpu" ]; + boot.kernelModules = [ + "amd-pstate" + "kvm-amd" + ]; + boot.kernelPackages = pkgs.linuxPackages_latest; + boot.kernelParams = [ + "amd_pstate=passive" + ]; + + hardware.bluetooth.enable = true; + + hardware.cpu.amd.updateMicrocode = true; + hardware.enableRedistributableFirmware = true; + + hardware.opengl.enable = true; + hardware.opengl.extraPackages = [ + pkgs.amdvlk + pkgs.rocm-opencl-icd + pkgs.rocm-opencl-runtime + ]; + + networking.wireless.enable = true; + networking.wireless.interfaces = [ + "wlp1s0" + ]; + networking.interfaces.wlp1s0.useDHCP = true; + + nixpkgs.hostPlatform = "x86_64-linux"; + + services.illum.enable = true; + + services.logind.extraConfig = /* ini */ '' + HandlePowerKey=ignore + ''; + + tv.lidControl.enable = true; + + tv.hw.screens.primary.width = 2560; + tv.hw.screens.primary.height = 1600; +} diff --git a/configs/hw/x220.nix b/configs/hw/x220.nix new file mode 100644 index 0000000..6993413 --- /dev/null +++ b/configs/hw/x220.nix @@ -0,0 +1,88 @@ +{ config, lib, pkgs, ... }: { + imports = [ + ../smartd.nix + { + boot.extraModulePackages = [ + config.boot.kernelPackages.acpi_call + ]; + + boot.kernelModules = [ + "acpi_call" + ]; + + environment.systemPackages = [ + pkgs.tpacpi-bat + ]; + } + + # fix jumpy touchpad + # https://wiki.archlinux.org/index.php/Lenovo_ThinkPad_X220#X220_Touchpad_cursor_jump/imprecise + { + services.udev.extraHwdb = /* sh */ '' + touchpad:i8042:* + LIBINPUT_MODEL_LENOVO_X220_TOUCHPAD_FW81=1 + ''; + } + + { + nix.settings.cores = 2; + nix.settings.max-jobs = 2; + } + (if lib.versionAtLeast (lib.versions.majorMinor lib.version) "21.11" then { + nix.daemonCPUSchedPolicy = "batch"; + nix.daemonIOSchedPriority = 1; + } else { + nix.daemonIONiceLevel = 1; + nix.daemonNiceLevel = 1; + }) + ]; + + boot.extraModulePackages = [ + config.boot.kernelPackages.tp_smapi + ]; + + boot.kernelModules = [ "tp_smapi" ]; + + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + + # Required for Centrino. + hardware.enableRedistributableFirmware = true; + + hardware.opengl.extraPackages = [ pkgs.vaapiIntel pkgs.vaapiVdpau ]; + + hardware.trackpoint = { + enable = true; + sensitivity = 220; + speed = 0; + emulateWheel = true; + }; + + # Conflicts with TLP, but gets enabled by DEs. + services.power-profiles-daemon.enable = false; + + services.tlp.enable = true; + services.tlp.settings = { + START_CHARGE_THRESH_BAT0 = 80; + }; + + + services.logind.extraConfig = '' + HandleHibernateKey=ignore + HandleLidSwitch=ignore + HandlePowerKey=ignore + HandleSuspendKey=ignore + ''; + + # because extraConfig is not extra enough: + services.logind.lidSwitch = "ignore"; + services.logind.lidSwitchDocked = "ignore"; + services.logind.lidSwitchExternalPower = "ignore"; + + services.xserver = { + videoDriver = "intel"; + }; + + tv.hw.screens.primary.width = lib.mkDefault 1366; + tv.hw.screens.primary.height = lib.mkDefault 768; +} diff --git a/configs/imgur.nix b/configs/imgur.nix new file mode 100644 index 0000000..ece4749 --- /dev/null +++ b/configs/imgur.nix @@ -0,0 +1,21 @@ +{ config, pkgs, ... }: { + services.nginx.virtualHosts."ni.r" = { + locations."/image" = { + extraConfig = /* nginx */ '' + client_max_body_size 20M; + + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_pass http://127.0.0.1:${toString config.krebs.htgen.imgur.port}; + proxy_pass_header Server; + ''; + }; + }; + + krebs.htgen.imgur = { + port = 7771; + scriptFile = "${pkgs.htgen-imgur}/bin/htgen-imgur"; + }; +} diff --git a/configs/initrd/sshd.nix b/configs/initrd/sshd.nix new file mode 100644 index 0000000..eff8480 --- /dev/null +++ b/configs/initrd/sshd.nix @@ -0,0 +1,17 @@ +{ config, ... }: { + boot.initrd.availableKernelModules = [ + "e1000e" + ]; + boot.initrd.network.enable = true; + boot.initrd.network.ssh = { + enable = true; + port = 11423; + authorizedKeys = [ + config.krebs.users.tv.pubkey + ]; + ignoreEmptyHostKeys = true; + }; + boot.initrd.secrets = { + "/etc/ssh/ssh_host_rsa_key" = <secrets/initrd/ssh_host_rsa_key>; + }; +} diff --git a/configs/mail-client.nix b/configs/mail-client.nix new file mode 100644 index 0000000..fc8fc81 --- /dev/null +++ b/configs/mail-client.nix @@ -0,0 +1,9 @@ +{ pkgs, ... }: { + environment.systemPackages = [ + pkgs.haskellPackages.much + pkgs.msmtp + pkgs.notmuch + pkgs.qprint + pkgs.w3m + ]; +} diff --git a/configs/man.nix b/configs/man.nix new file mode 100644 index 0000000..c723138 --- /dev/null +++ b/configs/man.nix @@ -0,0 +1,13 @@ +{ config, lib, pkgs, ... }: +{ + #environment.etc."man.conf".source = pkgs.runCommand "man.conf" {} '' + # ${pkgs.gnused}/bin/sed <${pkgs.man}/lib/man.conf >$out ' + # s:^NROFF\t.*:& -Wbreak: + # ' + #''; + environment.systemPackages = [ + pkgs.man-pages + pkgs.posix_man_pages + pkgs.xorg.xorgdocs + ]; +} diff --git a/configs/nets/hkw.nix b/configs/nets/hkw.nix new file mode 100644 index 0000000..51a8a73 --- /dev/null +++ b/configs/nets/hkw.nix @@ -0,0 +1,68 @@ +{ + krebs = { + dns.providers.hkw = "hosts"; + hosts = { + au = { + nets.hkw = { + ip4 = { + addr = "10.23.1.39"; + prefix = "10.23.1.0/24"; + }; + aliases = [ + "au.hkw" + ]; + ssh.port = 11423; + }; + }; + nomic = { + nets.hkw = { + ip4 = { + addr = "10.23.1.110"; + prefix = "10.23.1.0/24"; + }; + aliases = [ + "nomic.hkw" + ]; + ssh.port = 11423; + }; + }; + ok = { + external = true; + nets.hkw = { + ip4 = { + addr = "10.23.1.1"; + prefix = "10.23.1.0/24"; + }; + aliases = [ + "ok.hkw" + ]; + }; + }; + xu = { + nets.hkw = { + ip4 = { + addr = "10.23.1.38"; + prefix = "10.23.1.0/24"; + }; + aliases = [ + "xu.hkw" + "cache.xu.hkw" + ]; + ssh.port = 11423; + }; + }; + zu = { + nets.hkw = { + ip4 = { + addr = "10.23.1.40"; + prefix = "10.23.1.0/24"; + }; + aliases = [ + "zu.hkw" + ]; + ssh.port = 11423; + }; + }; + }; + }; +} diff --git a/configs/networkd.nix b/configs/networkd.nix new file mode 100644 index 0000000..da0d9ce --- /dev/null +++ b/configs/networkd.nix @@ -0,0 +1,4 @@ +{ + # often hangs + systemd.services.systemd-networkd-wait-online.enable = false; +} diff --git a/configs/nginx/default.nix b/configs/nginx/default.nix new file mode 100644 index 0000000..e288c52 --- /dev/null +++ b/configs/nginx/default.nix @@ -0,0 +1,21 @@ +{ config, ... }: { + services.nginx = { + enableReload = true; + + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedTlsSettings = true; + + virtualHosts.${builtins.toJSON ""} = { + default = true; + extraConfig = '' + error_page 400 =444 /; + return 444; + ''; + rejectSSL = true; + }; + }; + tv.iptables = { + input-retiolum-accept-tcp = [ "http" ]; + }; +} diff --git a/configs/nginx/public_html.nix b/configs/nginx/public_html.nix new file mode 100644 index 0000000..cd8e3c4 --- /dev/null +++ b/configs/nginx/public_html.nix @@ -0,0 +1,17 @@ +{ config, ... }: { + services.nginx = { + enable = true; + virtualHosts.default = { + serverAliases = [ + "localhost" + "${config.krebs.build.host.name}" + "${config.krebs.build.host.name}.hkw" + "${config.krebs.build.host.name}.r" + ]; + locations."~ ^/~([a-z]+)(?:/(.*))?\$" = { + alias = "/srv/$1/public_html/$2"; + }; + }; + }; + tv.iptables.input-internet-accept-tcp = [ "http" ]; +} diff --git a/configs/nix.nix b/configs/nix.nix new file mode 100644 index 0000000..fa96d45 --- /dev/null +++ b/configs/nix.nix @@ -0,0 +1,9 @@ +{ pkgs, ... }: { + nix.settings.auto-optimise-store = true; + + # TODO check if both are required: + nix.settings.extra-sandbox-paths = [ + "/etc/protocols" + pkgs.iana-etc.outPath + ]; +} diff --git a/configs/pki/certs/tv.crt b/configs/pki/certs/tv.crt new file mode 100644 index 0000000..ccb2623 --- /dev/null +++ b/configs/pki/certs/tv.crt @@ -0,0 +1,31 @@ +tv Root CA +-----BEGIN CERTIFICATE----- +MIIFGzCCAwOgAwIBAgIUbLFkDA1OgKbej/FQiJZ4gpGPg/4wDQYJKoZIhvcNAQEL +BQAwFTETMBEGA1UEAwwKdHYgUm9vdCBDQTAeFw0xOTA0MjEwNzI1MTdaFw0yOTA0 +MTgwNzI1MTdaMBUxEzARBgNVBAMMCnR2IFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDEVpZo1PLayK2AULwNtRY/2RIs/h+Uz1k/I7AY5o7H +HTD6pxNH3DZS82Y89nAHDVEnotK26TW6N1O2fBHUxH2GXVD+MaA/D9ngbNTJa7DW +2EThezOyesAbXk7dkoHh4Bouj5L7Ronka5+IREFmb3mHmcXLuR/sot9Pwr9A7Lwm +55Avv+VwMFnqVMXiCYQsDL7Mxf7Vm79+kXShpfDhNmHhyZc/xPjVk7lttSEp0LCq +hhJjte3xDGbk7OThTSxoqP+K4Ek7NGatCcm4AUZlDl1kLN2QKudYqj0VRQpfE+4Q +jMAAtttc/10MV0e08pRK0FvJsDsi70YZrHnDP6hIBrRNjC8iB/8rz2pjnYzgriUt +HHEDr26234VB5Zqhsi8pmXA16FVkoKlucADXXKEcR/3VreTvZLdSsP3OrDdSCwhi +H2W/7tshDPp+I9Q9fGNixry7PODbud1h/wLsq3Geg/U6VkDdl7uDNMB/O7LvlFaC +7jkHv/xFLqV1Xx9+yFMdJTKLf9jnIIjeINfV4VcJZDrtgGpnC6cYD5DNLA4j7Mny +EnBV9IRhmKiZLvUZP62dPhqIfSSPNxXV2+rT5ZfaXCuVe79R5npgJzF7/qslvnZ6 +0mjZfQdJiXY+/oT9zPUxTroFx7Qtda15aIVwXR+1cMRY/Hg/uBQyp7yWsvwhPYwH +awIDAQABo2MwYTAdBgNVHQ4EFgQUWYjGpR7J/UqggxQV87hBQ8ZT0qkwHwYDVR0j +BBgwFoAUWYjGpR7J/UqggxQV87hBQ8ZT0qkwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAA++eAA7KLEd4n05n8w95sJ7 +cxqQSkVxV3ASnEUQRwVGo3CqEKcNufbCTG7KKGQFUi2Xd3/SWgnEiSZZWo06azbV +vlquG+9ilwnrnqfjlbUEjLMHDzukrEeIiRuFY7gZv6S2o4WkW/M9IPkP34+PRjip +AJ8kFcy7wLPaeH7OagslAVUcf68lMm+8W4U1g0HZaY2zXFgdRrIO1dXKlJ22Wh4X +fcblHjkASAGi+BK+xRJ9G7s3sie2wPyk+WKKv0Z+WheKf+L+TPBg2sJ+d25gW+gG +XNJSQOzCqSfHrCtcW1xkGgifog28/ymN03ggn8oMBUebOp+ayLkbPQDaj6te3y1v +YE0cfkzQ0T6sSzPzoOrwBEuSX8cLWTpzO2Zgqbf36UtHjgxi58vY46p7MjAInxAf +j+k67rF7qWH38drg4nfGjNgiEdeJw9dtDFdmso+ZiWipUyGF4VYh+Q6JnXDMF0+A +wXcYWa7ckXvVOLVpHJfrLDYTXznGnk2u4ToVNEk1j/klMRn96lxfFg04iv8fz8m6 +/Y8g0G1uIT5Mq9l68oZUoEkUHZabPNhYOiYtg4t5v/T3AIV8nm2A5jZYj0am26xT +iqF/tqL3alWXs9OHP7FNdrVWtwO8vcspYcd4mOHdAC/dmhq+77BowR5Lldx9T+mR +QT8jW9PXL0IH0wKMBXxf +-----END CERTIFICATE----- diff --git a/configs/pki/default.nix b/configs/pki/default.nix new file mode 100644 index 0000000..05a608d --- /dev/null +++ b/configs/pki/default.nix @@ -0,0 +1,67 @@ +{ config, lib, mylib, pkgs, ... }: let + + certFile = config.environment.etc."ssl/certs/ca-certificates.crt".source; + +in { + + environment.etc."pki/nssdb".source = + pkgs.runCommand "system-wide-nssdb" { + inherit certFile; + buildInputs = [ + pkgs.jq + pkgs.nssTools + ]; + parseInfoScript = /* jq */ '' + ${builtins.toJSON certFile} as $certFile | + + split("\t-----END CERTIFICATE-----\n")[] | + select(test("\t-----BEGIN CERTIFICATE-----\n")) | + . + "\t-----END CERTIFICATE-----\n" | + + sub("^([0-9]+\t\n)*";"") | + + (match("^([0-9]+)\t").captures[0].string | tonumber) as $lineNumber | + + gsub("(?m)^[0-9]+\t";"") | + + match("^([^\n]+)\n(.*)";"m").captures | map(.string) | + + # Line numbers are added to the names to ensure uniqueness. + "\(.[0]) (\($certFile):\($lineNumber))" as $name | + .[1] as $cert | + + { $name, $cert } + ''; + passAsFile = [ + "parseInfoScript" + ]; + } /* sh */ '' + mkdir nssdb + + nl -ba -w1 "$certFile" | + jq -ceRs -f "$parseInfoScriptPath" > certinfo.ndjson + + exec < certinfo.ndjson + while read -r certinfo; do + name=$(printf %s "$certinfo" | jq -er .name) + cert=$(printf %s "$certinfo" | jq -er .cert) + + printf %s "$cert" | certutil -A -d nssdb -n "$name" -t C,C,C + done + + mv nssdb "$out" + ''; + + environment.variables = lib.flip lib.genAttrs (_: toString certFile) [ + "CURL_CA_BUNDLE" + "GIT_SSL_CAINFO" + "SSL_CERT_FILE" + ]; + + security.pki.certificateFiles = + lib.mapAttrsToList + (name: _: (./certs + "/${name}")) + (lib.filterAttrs (_: (mylib.eq "regular")) + (builtins.readDir ./certs)); + +} diff --git a/configs/ppp.nix b/configs/ppp.nix new file mode 100644 index 0000000..63e75af --- /dev/null +++ b/configs/ppp.nix @@ -0,0 +1,85 @@ +{ config, mylib, pkgs, ... }: let + cfg = { + pin = "@${config.krebs.secret.directory}/o2.pin"; + ttys.ppp = "/dev/ttyACM0"; + ttys.com = "/dev/ttyACM1"; + }; +in { + assertions = [ + { + assertion = + config.networking.resolvconf.enable || + config.networking.useNetworkd; + message = "ppp configuration needs resolvconf or networkd"; + } + ]; + environment.etc."ppp/ip-up".source = pkgs.writeDash "ppp.ip-up" '' + ${pkgs.openresolv}/bin/resolvconf -a "$IFNAME" < /etc/ppp/resolv.conf + ''; + environment.etc."ppp/ip-down".source = pkgs.writeDash "ppp.ip-down" '' + ${pkgs.openresolv}/bin/resolvconf -fd "$IFNAME" + ''; + environment.etc."ppp/peers/o2".text = /* sh */ '' + ${cfg.ttys.ppp} + 921600 + crtscts + defaultroute + holdoff 10 + lock + maxfail 0 + noauth + nodetach + noipdefault + passive + persist + usepeerdns + connect "${pkgs.ppp}/bin/chat ''${DEBUG+-v} -Ss -f ${pkgs.writeText "o2.chat" /* sh */ '' + ABORT "BUSY" + ABORT "NO CARRIER" + REPORT CONNECT + "*EMRDY: 1" + ATZ OK + AT+CFUN=1 OK + ${cfg.pin} TIMEOUT 2 ERROR-AT-OK + AT+CGDCONT=1,\042IP\042,\042internet\042 OK + ATDT*99***1# CONNECT + ''}" + ''; + users.users.root.packages = [ + (pkgs.writeDashBin "connect" '' + # usage: + # connect wlan + # connect wwan [PEERNAME] + set -efu + rfkill_wlan=/sys/class/rfkill/rfkill2 + rfkill_wwan=/sys/class/rfkill/rfkill1 + case $1 in + wlan) + ${pkgs.procps}/bin/pkill pppd || : + echo 0 > "$rfkill_wwan"/state + echo 1 > "$rfkill_wlan"/state + ;; + wwan) + name=''${2-o2} + echo 0 > "$rfkill_wlan"/state + echo 1 > "$rfkill_wwan"/state + ${pkgs.ppp}/bin/pppd call "$name" updetach + ;; + *) + echo "$0: error: bad arguments: $*" >&2 + exit 1 + esac + '') + (pkgs.writeDashBin "modem-send" '' + # usage: modem-send ATCOMMAND + set -efu + tty=${mylib.shell.escape cfg.ttys.com} + exec <"$tty" + printf '%s\r\n' "$1" >"$tty" + ${pkgs.gnused}/bin/sed -E ' + /^OK\r?$/q + /^ERROR\r?$/q + ' + '') + ]; +} diff --git a/configs/pulse.nix b/configs/pulse.nix new file mode 100644 index 0000000..17c203c --- /dev/null +++ b/configs/pulse.nix @@ -0,0 +1,119 @@ +{ config, lib, mylib, pkgs, ... }: let + pkg = pkgs.pulseaudio; + runDir = "/run/pulse"; + + pkgs_i686 = pkgs.pkgsi686Linux; + + support32Bit = + pkgs.stdenv.isx86_64 && + pkgs_i686.alsaLib != null && + pkgs_i686.libpulseaudio != null; + + alsaConf = pkgs.writeText "asound.conf" '' + ctl_type.pulse { + libs.native = ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so; + ${lib.optionalString support32Bit + "libs.32Bit = ${pkgs_i686.alsaPlugins}/lib/alsa-lib/libasound_module_ctl_pulse.so;"} + } + pcm_type.pulse { + libs.native = ${pkgs.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_pulse.so; + ${lib.optionalString support32Bit + "libs.32Bit = ${pkgs_i686.alsaPlugins}/lib/alsa-lib/libasound_module_pcm_pulse.so;"} + } + ctl.!default { + type pulse + } + pcm.!default { + type pulse + } + ''; + + clientConf = pkgs.writeText "client.conf" '' + autospawn=no + default-server = unix:${runDir}/socket + ''; + + configFile = pkgs.writeText "default.pa" '' + .include ${pkg}/etc/pulse/default.pa + load-module ${toString [ + "module-native-protocol-unix" + "auth-anonymous=1" + "socket=${runDir}/socket" + ]} + ${lib.optionalString (config.krebs.build.host.name == "au") '' + load-module ${toString [ + "module-native-protocol-tcp" + "auth-ip-acl=127.0.0.1;10.23.1.0/24" + ]} + ''} + ${lib.optionalString (config.krebs.build.host.name != "au") '' + load-module ${toString [ + "module-tunnel-sink-new" + "server=au.hkw" + "sink_name=au" + "channels=2" + "rate=44100" + ]} + ''} + ''; +in + +{ + environment = { + etc = { + "asound.conf".source = alsaConf; + # XXX mkForce is not strong enough (and neither is mkOverride) to create + # /etc/pulse/client.conf, see pulseaudio-hack below for a solution. + #"pulse/client.conf" = mkForce { source = clientConf; }; + #"pulse/client.conf".source = mkForce clientConf; + "pulse/default.pa".source = configFile; + }; + systemPackages = [ + pkg + ] ++ lib.optionals config.services.xserver.enable [ + pkgs.pavucontrol + ]; + }; + + hardware.pulseaudio = { + inherit support32Bit; + }; + + # Allow PulseAudio to get realtime priority using rtkit. + security.rtkit.enable = true; + + system.activationScripts.pulseaudio-hack = '' + ln -fns ${clientConf} /etc/pulse/client.conf + ''; + + systemd.services.pulse = { + wantedBy = [ "sound.target" ]; + before = [ "sound.target" ]; + environment = { + PULSE_RUNTIME_PATH = "${runDir}/home"; + }; + serviceConfig = { + ExecStart = "${pkg}/bin/pulseaudio --exit-idle-time=-1"; + ExecStartPre = pkgs.writeDash "pulse-start" '' + install -o pulse -g pulse -m 0750 -d ${runDir} + install -o pulse -g pulse -m 0700 -d ${runDir}/home + ''; + PermissionsStartOnly = "true"; + User = "pulse"; + }; + }; + + # TODO assert that pulse is the only user with "audio" in group/extraGroups + # otherwise the audio device can be hijacked while the pulse service restarts + # (e.g. when mpv is running) and then the service will fail. + users = { + groups.pulse.gid = config.users.users.pulse.uid; + users.pulse = { + uid = mylib.genid_uint31 "pulse"; + group = "pulse"; + extraGroups = [ "audio" ]; + home = "${runDir}/home"; + isSystemUser = true; + }; + }; +} diff --git a/configs/repo-sync/wiki.nix b/configs/repo-sync/wiki.nix new file mode 100644 index 0000000..94f7e80 --- /dev/null +++ b/configs/repo-sync/wiki.nix @@ -0,0 +1,39 @@ +{ config, lib, mylib, pkgs, ... }: { + krebs.repo-sync.enable = true; + krebs.repo-sync.repos.wiki.branches.hotdog = { + origin.url = "http://cgit.hotdog.r/wiki"; + mirror.url = "git@${config.krebs.build.host.name}.r:wiki"; + }; + krebs.git.repos.wiki = { + public = true; + name = "wiki"; + cgit.desc = toString [ + "mirror of" + config.krebs.repo-sync.repos.wiki.branches.hotdog.origin.url + ]; + cgit.section = "7. mirrors"; + hooks.post-receive = /* sh */ '' + ${pkgs.git-hooks.irc-announce { + channel = "#xxx"; + nick = config.krebs.build.host.name; + server = "irc.r"; + }} + ${pkgs.cgit-clear-cache.override { + inherit (config.krebs.git.cgit.settings) cache-root; + }}/bin/cgit-clear-cache + ''; + }; + krebs.git.rules = lib.singleton { + user = lib.singleton config.krebs.users.repo-sync; + repo = lib.singleton config.krebs.git.repos.wiki; + perm = mylib.git.push "refs/*" [ + mylib.git.create + mylib.git.delete + mylib.git.merge + mylib.git.non-fast-forward + ]; + }; + krebs.users.${config.krebs.repo-sync.user.name}.pubkey = { + ni = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINK9U0Ob9/O0kxg3trhZY/vDnbqfN+R5cASGiClRr4IM"; + }.${config.krebs.build.host.name}; +} diff --git a/configs/retiolum.nix b/configs/retiolum.nix new file mode 100644 index 0000000..632cc97 --- /dev/null +++ b/configs/retiolum.nix @@ -0,0 +1,26 @@ +{ config, lib, mylib, pkgs, ... }: { + krebs.tinc.retiolum = { + enable = true; + connectTo = builtins.filter (mylib.ne config.krebs.build.host.name) [ + "ni" + "prism" + "eve" + ]; + extraConfig = '' + LocalDiscovery = yes + ''; + tincPackage = pkgs.tinc_pre; + tincUp = lib.mkIf config.systemd.network.enable ""; + }; + systemd.network.networks.retiolum = { + matchConfig.Name = "retiolum"; + address = let + inherit (config.krebs.build.host.nets.retiolum) ip4 ip6; + in [ + "${ip4.addr}/${toString ip4.prefixLength}" + "${ip6.addr}/${toString ip6.prefixLength}" + ]; + }; + tv.iptables.input-internet-accept-tcp = [ "tinc" ]; + tv.iptables.input-internet-accept-udp = [ "tinc" ]; +} diff --git a/configs/smartd.nix b/configs/smartd.nix new file mode 100644 index 0000000..9c4d8b2 --- /dev/null +++ b/configs/smartd.nix @@ -0,0 +1,17 @@ +{ config, pkgs, ... }: + +{ + services.smartd = { + enable = true; + devices = [ + { + device = "DEVICESCAN"; + options = toString [ + "-a" + "-m ${config.krebs.users.tv.mail}" + "-s (O/../.././09|S/../.././04|L/../../6/05)" + ]; + } + ]; + }; +} diff --git a/configs/ssh.nix b/configs/ssh.nix new file mode 100644 index 0000000..0dda6e5 --- /dev/null +++ b/configs/ssh.nix @@ -0,0 +1,21 @@ +{ config, lib, pkgs, ... }: { + # Override NixOS's "Allow DSA keys for now." + environment.etc."ssh/ssh_config".text = lib.mkForce '' + AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"} + + ${lib.optionalString config.programs.ssh.setXAuthLocation '' + XAuthLocation ${pkgs.xorg.xauth}/bin/xauth + ''} + + ForwardX11 ${if config.programs.ssh.forwardX11 then "yes" else "no"} + + ${config.programs.ssh.extraConfig} + ''; + + programs.ssh = { + extraConfig = '' + UseRoaming no + ''; + startAgent = false; + }; +} diff --git a/configs/sshd.nix b/configs/sshd.nix new file mode 100644 index 0000000..281d498 --- /dev/null +++ b/configs/sshd.nix @@ -0,0 +1,26 @@ +{ config, lib, ... }: let + cfg.host = config.krebs.build.host; + nets = + lib.optional (cfg.host.nets?retiolum) cfg.host.nets.retiolum ++ + lib.optional (cfg.host.nets?wiregrill) cfg.host.nets.wiregrill; +in { + services.openssh = { + enable = true; + }; + tv.iptables.input-internet-accept-tcp = [ "ssh" ]; + tv.iptables.extra.nat.OUTPUT = [ + "-o lo -p tcp --dport 11423 -j REDIRECT --to-ports 22" + ]; + tv.iptables.extra4.nat.PREROUTING = + map + (net: "-d ${net.ip4.addr} -p tcp --dport 22 -j ACCEPT") + (builtins.filter (net: net.ip4 != null) nets); + tv.iptables.extra6.nat.PREROUTING = + map + (net: "-d ${net.ip6.addr} -p tcp --dport 22 -j ACCEPT") + (builtins.filter (net: net.ip6 != null) nets); + tv.iptables.extra.nat.PREROUTING = [ + "-p tcp --dport 22 -j REDIRECT --to-ports 0" + "-p tcp --dport 11423 -j REDIRECT --to-ports 22" + ]; +} diff --git a/configs/urlwatch.nix b/configs/urlwatch.nix new file mode 100644 index 0000000..19f28b1 --- /dev/null +++ b/configs/urlwatch.nix @@ -0,0 +1,118 @@ +{ config, lib, mylib, pkgs, ... }: let + exec = filename: args: url: { + inherit url; + filter = [ + { + system = + lib.concatMapStringsSep " " mylib.shell.escape ([filename] ++ lib.toList args); + } + ]; + }; + json = json' ["."]; + json' = exec "${pkgs.jq}/bin/jq"; + urigrep' = exec (pkgs.writeDash "urigrep" '' + ${pkgs.urix}/bin/urix | ${pkgs.gnugrep}/bin/grep -E "$1" + ''); + xml = xml' ["--format" "-"]; + xml' = exec "${pkgs.libxml2}/bin/xmllint"; +in { + krebs.urlwatch = { + enable = true; + mailto = config.krebs.users.tv.mail; + onCalendar = "*-*-* 05:00:00"; + urls = [ + ## nixpkgs maintenance + + # 2014-07-29 when one of the following urls change + # then we have to update the package + + http://www.exim.org/ + + # ref src/nixpkgs/pkgs/tools/networking/urlwatch/default.nix + { + url = https://thp.io/2008/urlwatch/; + # workaround: ('Received response with content-encoding: gzip, but + # failed to decode it.', error('Error -3 while decompressing data: + # incorrect header check',)) + ignore_cached = true; + } + + # 2015-02-18 + # ref ~/src/nixpkgs/pkgs/tools/text/qprint/default.nix + http://www.fourmilab.ch/webtools/qprint/ + + # 2014-09-24 ref https://github.com/4z3/xintmap + http://www.mathstat.dal.ca/~selinger/quipper/ + + ## 2014-10-17 + ## TODO update ~/src/login/default.nix + #http://hackage.haskell.org/package/bcrypt + #http://hackage.haskell.org/package/cron + #http://hackage.haskell.org/package/hyphenation + #http://hackage.haskell.org/package/iso8601-time + #http://hackage.haskell.org/package/ixset-typed + #http://hackage.haskell.org/package/system-command + #http://hackage.haskell.org/package/transformers + #http://hackage.haskell.org/package/web-routes-wai + #http://hackage.haskell.org/package/web-page + + # ref <stockholm/krebs/3modules>, services.openssh.knownHosts.github* + (json https://api.github.com/meta) + + # ref <nixpkgs/pkgs/tools/security/ssh-audit> + (json https://api.github.com/repos/arthepsy/ssh-audit/tags) + + # 2014-12-20 ref src/nixpkgs/pkgs/tools/networking/tlsdate/default.nix + (json https://api.github.com/repos/ioerror/tlsdate/tags) + + # ref src/nixpkgs/pkgs/tools/admin/sec/default.nix + (json https://api.github.com/repos/simple-evcorr/sec/tags) + + # <stockholm/tv/2configs/xserver/xserver.conf.nix> + # is derived from `configFile` in: + https://raw.githubusercontent.com/NixOS/nixpkgs/master/nixos/modules/services/x11/xserver.nix + + https://www.rabbitmq.com/changelog.html + + (urigrep' ["software-resources"] https://semiconductor.samsung.com/consumer-storage/support/tools/) + ]; + hooksFile = builtins.toFile "hooks.py" '' + import subprocess + import urlwatch + + class SystemFilter(urlwatch.filters.FilterBase): + """Filter for piping data through an external process""" + + __kind__ = 'system' + + __supported_subfilters__ = { + 'command': 'shell command line to tranform data', + } + + __default_subfilter__ = 'command' + + def filter(self, data, subfilter=None): + if 'command' not in subfilter: + raise ValueError('{} filter needs a command'.format(self.__kind__)) + + proc = subprocess.Popen( + subfilter['command'], + shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + + (stdout, stderr) = proc.communicate(data.encode()) + + if proc.returncode != 0: + raise RuntimeError( + "system filter returned non-zero exit status %d; stderr:\n" + % proc.returncode + + stderr.decode() + ) + + return stdout.decode() + ''; + }; +} diff --git a/configs/vim.nix b/configs/vim.nix new file mode 100644 index 0000000..b06b196 --- /dev/null +++ b/configs/vim.nix @@ -0,0 +1,184 @@ +{ config, lib, mylib, pkgs, ... }: let { + body = { + environment.systemPackages = [ + vim-wrapper + ]; + + environment.etc.vimrc.source = vimrc; + + environment.variables.EDITOR = lib.mkForce "vim"; + environment.variables.VIMINIT = ":so /etc/vimrc"; + }; + + base-plugins = [ + pkgs.tv.vimPlugins.file-line + pkgs.tv.vimPlugins.hack + pkgs.vimPlugins.undotree + (pkgs.tv.vim.makePlugin (pkgs.write "vim-tv-base" { + "/ftplugin/haskell.vim".text = '' + if exists("g:vim_tv_ftplugin_haskell_loaded") + finish + endif + let g:vim_tv_ftplugin_haskell_loaded = 1 + + setlocal iskeyword+=' + ''; + })) + ]; + + extra-plugins = [ + pkgs.tv.vimPlugins.elixir + pkgs.tv.vimPlugins.fzf + pkgs.tv.vimPlugins.jq + pkgs.tv.vimPlugins.nix + pkgs.tv.vimPlugins.showsyntax + pkgs.tv.vimPlugins.tv + pkgs.tv.vimPlugins.vim + pkgs.vimPlugins.fzfWrapper + pkgs.vimPlugins.vim-nftables + ]; + + dirs = { + backupdir = "$HOME/.cache/vim/backup"; + swapdir = "$HOME/.cache/vim/swap"; + undodir = "$HOME/.cache/vim/undo"; + }; + files = { + viminfo = "$HOME/.cache/vim/info"; + }; + + need-dirs = let + dirOf = s: + let + out = lib.concatStringsSep "/" (lib.init (lib.splitString "/" s)); + in assert out != ""; out; + alldirs = builtins.attrValues dirs ++ map dirOf (builtins.attrValues files); + in lib.unique (builtins.sort builtins.lessThan alldirs); + + vim-wrapper = pkgs.symlinkJoin { + name = "vim"; + paths = [ + (pkgs.writeDashBin "vim" '' + set -efu + export FZF_DEFAULT_COMMAND='${pkgs.ripgrep}/bin/rg --files' + export PATH=$PATH:${lib.makeBinPath [ + pkgs.fzf + pkgs.ripgrep + ]} + (umask 0077; exec ${pkgs.coreutils}/bin/mkdir -p ${toString need-dirs}) + exec ${pkgs.vim}/bin/vim "$@" + '') + pkgs.vim + ]; + }; + + vimrc = pkgs.writeText "vimrc" /* vim */ '' + vim9script + + set nocompatible + + set autoindent + set backspace=indent,eol,start + set backup + set backupdir=${dirs.backupdir}/ + set directory=${dirs.swapdir}// + set hlsearch + set incsearch + set mouse=a + set noruler + set pastetoggle=<INS> + set runtimepath=${pkgs.tv.vim.makeRuntimePath base-plugins},$VIMRUNTIME + set shortmess+=I + set showcmd + set showmatch + set timeoutlen=0 + set ttimeoutlen=0 + set ttymouse=sgr + set undodir=${dirs.undodir} + set undofile + set undolevels=1000000 + set undoreload=1000000 + set viminfo='20,<1000,s100,h,n${files.viminfo} + set visualbell + set wildignore+=*.o,*.class,*.hi,*.dyn_hi,*.dyn_o + set wildmenu + set wildmode=longest,full + + set runtimepath^=${pkgs.tv.vim.makeRuntimePath extra-plugins} + syntax on + + set et ts=2 sts=2 sw=2 + + filetype plugin indent on + + set t_Co=256 + colorscheme hack + + au Syntax * syn match Garbage containedin=ALL /\s\+$/ + \ | syn match TabStop containedin=ALL /\t\+/ + \ | syn keyword Todo containedin=ALL TODO + + au BufRead,BufNewFile *.nix set ft=nix + + au BufRead,BufNewFile /dev/shm/* set nobackup nowritebackup noswapfile + + cnoremap <C-A> <Home> + + noremap <C-c> :q<cr> + + nnoremap <esc>[5^ :tabp<cr> + nnoremap <esc>[6^ :tabn<cr> + nnoremap <esc>[5@ :tabm -1<cr> + nnoremap <esc>[6@ :tabm +1<cr> + + nnoremap <f1> :tabp<cr> + nnoremap <f2> :tabn<cr> + imap <f1> <esc><f1> + imap <f2> <esc><f2> + + nnoremap <S-f1> :tabm -1<cr> + nnoremap <S-f2> :tabm +1<cr> + imap <S-f1> <esc><S-f1> + imap <S-f2> <esc><S-f2> + + noremap <f3> :ShowSyntax<cr> + + # <C-{Up,Down,Right,Left}> + noremap <esc>Oa <nop> | noremap! <esc>Oa <nop> + noremap <esc>Ob <nop> | noremap! <esc>Ob <nop> + noremap <esc>Oc <nop> | noremap! <esc>Oc <nop> + noremap <esc>Od <nop> | noremap! <esc>Od <nop> + # <[C]S-{Up,Down,Right,Left}> + noremap <esc>[a <nop> | noremap! <esc>[a <nop> + noremap <esc>[b <nop> | noremap! <esc>[b <nop> + noremap <esc>[c <nop> | noremap! <esc>[c <nop> + noremap <esc>[d <nop> | noremap! <esc>[d <nop> + vnoremap u <nop> + + # fzf + nnoremap <esc>q :Buffers<cr> + nnoremap <esc>f :Files<cr> + nnoremap <esc>w :Rg<cr> + + # edit alternate buffer + # For some reason neither putting <ctrl>6 nor <ctrl>^ works here... + nnoremap <esc>a + + if $TOUCHSCREEN == "1" + nnoremap <ScrollWheelUp> <C-y> + nnoremap <ScrollWheelDown> <C-e> + nnoremap <C-ScrollWheelUp> 3<C-y> + nnoremap <C-ScrollWheelDown> 3<C-e> + nnoremap <S-ScrollWheelUp> 3<C-y> + nnoremap <S-ScrollWheelDown> 3<C-e> + nnoremap <C-S-ScrollWheelUp> <PageUp> + nnoremap <C-S-ScrollWheelDown> <PageDown> + endif + + # remember last position + autocmd BufReadPost * + \ if line("'\"") > 0 && line("'\"") <= line("$") | + \ exe "normal! g`\"" | + \ endif + ''; +} diff --git a/configs/weechat-server.nix b/configs/weechat-server.nix new file mode 100644 index 0000000..41f157c --- /dev/null +++ b/configs/weechat-server.nix @@ -0,0 +1,24 @@ +{ config, pkgs, ... }: { + users.users.tv.packages = [ + (pkgs.writers.writeDashBin "weechat-client" '' + set -efu + exec ${pkgs.tmux}/bin/tmux attach -t weechat + '') + ]; + systemd.services.weechat = { + wantedBy = [ "multi-user.target" ]; + environment = { + TERM = "rxvt-unicode-256color"; + }; + serviceConfig = { + ExecStart = "${pkgs.tmux}/bin/tmux new -d -s weechat ${pkgs.weechat}/bin/weechat"; + OOMScoreAdjust = -1000; + Restart = "always"; + RestartSec = "100ms"; + Type = "forking"; + StartLimitBurst = 0; + User = "tv"; + WorkingDirectory = "/home/tv"; + }; + }; +} diff --git a/configs/wiregrill.nix b/configs/wiregrill.nix new file mode 100644 index 0000000..55bb6f5 --- /dev/null +++ b/configs/wiregrill.nix @@ -0,0 +1,36 @@ +{ config, lib, pkgs, ... }: let + cfg = { + enable = cfg.net != null; + net = config.krebs.build.host.nets.wiregrill or null; + }; + toCidrNotation = ip: "${ip.addr}/${toString ip.prefixLength}"; +in + lib.mkIf cfg.enable { + networking.wireguard.interfaces.wiregrill = { + ips = + lib.optional (cfg.net.ip4 != null) cfg.net.ip4.addr ++ + lib.optional (cfg.net.ip6 != null) cfg.net.ip6.addr; + listenPort = 51820; + privateKeyFile = "${config.krebs.secret.directory}/wiregrill.key"; + allowedIPsAsRoutes = true; + peers = lib.mapAttrsToList + (_: host: { + allowedIPs = host.nets.wiregrill.wireguard.subnets; + endpoint = + lib.mkIf (host.nets.wiregrill.via != null) (host.nets.wiregrill.via.ip4.addr + ":${toString host.nets.wiregrill.wireguard.port}"); + persistentKeepalive = lib.mkIf (host.nets.wiregrill.via != null) 61; + publicKey = + lib.replaceStrings ["\n"] [""] host.nets.wiregrill.wireguard.pubkey; + }) + (lib.filterAttrs (_: h: lib.hasAttr "wiregrill" h.nets) config.krebs.hosts); + }; + systemd.network.networks.wiregrill = { + matchConfig.Name = "wiregrill"; + address = + lib.optional (cfg.net.ip4 != null) (toCidrNotation cfg.net.ip4) ++ + lib.optional (cfg.net.ip6 != null) (toCidrNotation cfg.net.ip6); + }; + tv.iptables.extra.filter.INPUT = [ + "-p udp --dport ${toString cfg.net.wireguard.port} -j ACCEPT" + ]; + } diff --git a/configs/xdg.nix b/configs/xdg.nix new file mode 100644 index 0000000..33f35f0 --- /dev/null +++ b/configs/xdg.nix @@ -0,0 +1,10 @@ +{ config, lib, ... }: { + environment.variables.XDG_RUNTIME_DIR = "/run/xdg/$LOGNAME"; + + systemd.tmpfiles.rules = let + forUsers = lib.flip map users; + isUser = { name, group, ... }: + name == "root" || lib.hasSuffix "users" group; + users = builtins.filter isUser (builtins.attrValues config.users.users); + in forUsers (u: "d /run/xdg/${u.name} 0700 ${u.name} ${u.group} -"); +} diff --git a/configs/xserver/Xmodmap.nix b/configs/xserver/Xmodmap.nix new file mode 100644 index 0000000..8e555e9 --- /dev/null +++ b/configs/xserver/Xmodmap.nix @@ -0,0 +1,28 @@ +{ config, pkgs, ... }: + +with import ./lib; + +pkgs.writeText "Xmodmap" '' + !keycode 66 = Caps_Lock + !remove Lock = Caps_Lock + clear Lock + + ! caps lock + keycode 66 = Mode_switch + + keycode 13 = 4 dollar EuroSign cent + keycode 30 = u U udiaeresis Udiaeresis + keycode 32 = o O odiaeresis Odiaeresis + keycode 38 = a A adiaeresis Adiaeresis + keycode 39 = s S ssharp + + keycode 33 = p P Greek_pi Greek_PI + keycode 40 = d D Greek_delta Greek_DELTA + keycode 46 = l L Greek_lambda Greek_LAMBDA + + keycode 54 = c C cacute Cacute + + ! BULLET OPERATOR + keycode 17 = 8 asterisk U2219 + keycode 27 = r R r U211D +'' diff --git a/configs/xserver/default.nix b/configs/xserver/default.nix new file mode 100644 index 0000000..df83ba5 --- /dev/null +++ b/configs/xserver/default.nix @@ -0,0 +1,166 @@ +{ config, pkgs, ... }@args: let + cfg = { + cacheDir = cfg.dataDir; + configDir = "/var/empty"; + dataDir = "/run/xdg/${cfg.user.name}/xmonad"; + user = config.krebs.build.user; + xmonad.pkg = pkgs.haskellPackages.xmonad-tv.overrideAttrs (_: { + au = { + XMONAD_BUILD_SCREEN_WIDTH = 1920; + XMONAD_BUILD_TERM_FONT_WIDTH = 10; + XMONAD_BUILD_TERM_FONT = "xft:Input Mono:size=12:style=Regular"; + XMONAD_BUILD_TERM_PADDING = 2; + }; + }.${config.krebs.build.host.name} or { + XMONAD_BUILD_SCREEN_WIDTH = 1366; + XMONAD_BUILD_TERM_FONT_WIDTH = 6; + XMONAD_BUILD_TERM_FONT = "-*-clean-*-*-*-*-*-*-*-*-*-*-iso10646-1"; + XMONAD_BUILD_TERM_PADDING = 2; + }); + }; +in { + + imports = [ + ./sxiv.nix + ./urxvt.nix + ]; + + environment.systemPackages = [ + pkgs.ff + pkgs.font-size + pkgs.gitAndTools.qgit + pkgs.mpv + pkgs.xdotool + pkgs.xsel + pkgs.zathura + ]; + + fonts.fonts = [ + pkgs.xorg.fontschumachermisc + ]; + + services.xserver = { + + # Don't install feh into systemPackages + # refs <nixpkgs/nixos/modules/services/x11/desktop-managers> + desktopManager.session = mkForce []; + + displayManager.lightdm.enable = mkForce false; + displayManager.job.execCmd = mkForce "derp"; + + enable = true; + display = mkForce 11; + tty = mkForce 11; + }; + + systemd.services.display-manager.enable = false; + + systemd.services.xmonad = let + xmonad = "${cfg.xmonad.pkg}/bin/xmonad"; + xmonad-start = pkgs.writeDash "xmonad-start" '' + ${pkgs.coreutils}/bin/mkdir -p "$XMONAD_CACHE_DIR" + ${pkgs.coreutils}/bin/mkdir -p "$XMONAD_CONFIG_DIR" + ${pkgs.coreutils}/bin/mkdir -p "$XMONAD_DATA_DIR" + + f=$HOME/.dbus/session-bus/$(${pkgs.coreutils}/bin/cat /etc/machine-id)-${ + toString config.services.xserver.display + } + if test -e "$f" && + . "$f" && + ${pkgs.coreutils}/bin/kill -0 "$DBUS_SESSION_BUS_PID" + then + export DBUS_SESSION_BUS_ADDRESS + else + eval "$(${pkgs.dbus.lib}/bin/dbus-launch --sh-syntax)" + fi + + exec ${xmonad} + ''; + xmonad-ready = pkgs.writeDash "xmonad-ready" '' + ${pkgs.systemd}/bin/systemd-notify --ready + { + ${pkgs.xorg.xhost}/bin/xhost +SI:localuser:${cfg.user.name} + ${pkgs.xorg.xhost}/bin/xhost -LOCAL: + } & + ${pkgs.xorg.xmodmap}/bin/xmodmap ${import ./Xmodmap.nix args} & + ${pkgs.xorg.xsetroot}/bin/xsetroot -solid '#1c1c1c' & + wait + ''; + in { + wantedBy = [ "graphical.target" ]; + requires = [ "xserver.service" ]; + environment = { + DISPLAY = ":${toString config.services.xserver.display}"; + FZMENU_FZF_DEFAULT_OPTS = toString [ + "--color=dark,border:126,bg+:090" + "--inline-info" + ]; + XMONAD_CACHE_DIR = cfg.cacheDir; + XMONAD_CONFIG_DIR = cfg.configDir; + XMONAD_DATA_DIR = cfg.dataDir; + XMONAD_STARTUP_HOOK = xmonad-ready; + XMONAD_WORKSPACES0_FILE = pkgs.writeJSON "xmonad-workspaces0.json" [ + "Dashboard" # we start here + "23" + "cr" + "ff" + "hack" + "im" + "mail" + "stockholm" + "za" "zh" "zj" "zs" + ]; + }; + path = [ + config.tv.slock.package + pkgs.flameshot-once-tv + pkgs.pulseaudio.out + pkgs.rxvt_unicode + pkgs.xcalib + "/run/wrappers" # for su + ]; + serviceConfig = { + ExecStart = "@${xmonad-start} xmonad-${currentSystem}"; + ExecStop = "@${xmonad} xmonad-${currentSystem} --shutdown"; + SyslogIdentifier = "xmonad"; + User = cfg.user.name; + WorkingDirectory = cfg.user.home; + + NotifyAccess = "all"; + Type = "notify"; + }; + }; + + systemd.services.xserver = { + after = [ + "acpid.service" + "local-fs.target" + "systemd-udev-settle.service" + ]; + wants = [ + "systemd-udev-settle.service" + ]; + restartIfChanged = false; + environment = { + LD_LIBRARY_PATH = concatStringsSep ":" ([ "/run/opengl-driver/lib" ] + ++ concatLists (catAttrs "libPath" config.services.xserver.drivers)); + }; + serviceConfig = { + SyslogIdentifier = "xserver"; + ExecStart = toString [ + "${pkgs.xorg.xorgserver}/bin/X" + ":${toString config.services.xserver.display}" + "vt${toString config.services.xserver.tty}" + "-config ${import ./xserver.conf.nix args}" + "-logfile /dev/null -logverbose 0 -verbose 3" + "-nolisten tcp" + "-xkbdir ${config.services.xserver.xkbDir}" + ]; + }; + }; + + tv.slock = { + enable = true; + user = cfg.user; + }; +} diff --git a/configs/xserver/sxiv.nix b/configs/xserver/sxiv.nix new file mode 100644 index 0000000..13cfd65 --- /dev/null +++ b/configs/xserver/sxiv.nix @@ -0,0 +1,11 @@ +{ config, pkgs, ... }: let + cfg.user = config.krebs.build.user; +in { + tv.Xresources = { + "Sxiv.foreground" = "#232323"; + "Sxiv.background" = "#424242"; + }; + users.users.${cfg.user.name}.packages = [ + pkgs.sxiv + ]; +} diff --git a/configs/xserver/urxvt.nix b/configs/xserver/urxvt.nix new file mode 100644 index 0000000..c4e619d --- /dev/null +++ b/configs/xserver/urxvt.nix @@ -0,0 +1,72 @@ +{ config, pkgs, ... }: let + cfg.user = config.krebs.build.user; +in { + systemd.services.urxvtd = { + wantedBy = [ "graphical.target" ]; + restartIfChanged = false; + serviceConfig = { + SyslogIdentifier = "urxvtd"; + ExecStart = "${pkgs.rxvt_unicode}/bin/urxvtd"; + Restart = "always"; + RestartSec = "2s"; + StartLimitBurst = 0; + User = cfg.user.name; + }; + }; + tv.Xresources = { + "URxvt*cutchars" = ''"\\`\"'&()*,;<=>?@[]^{|}‘’"''; + "URxvt*eightBitInput" = "false"; + "URxvt*font" = "-*-clean-*-*-*-*-*-*-*-*-*-*-iso10646-1"; + "URxvt*boldFont" = "-*-clean-*-*-*-*-*-*-*-*-*-*-iso10646-1"; + "URxvt*scrollBar" = "false"; + "URxvt*background" = "#050505"; + "URxvt*foreground" = "#d0d7d0"; + "URxvt*cursorColor" = "#f042b0"; + "URxvt*cursorColor2" = "#f0b000"; + "URxvt*cursorBlink" = "off"; + "URxvt*jumpScroll" = "true"; + "URxvt*allowSendEvents" = "false"; + "URxvt*charClass" = "33:48,37-38:48,45-47:48,61:48,63-64:48"; + "URxvt*cutNewline" = "False"; + "URxvt*cutToBeginningOfLine" = "False"; + + "URxvt*color0" = "#232342"; + "URxvt*color3" = "#c07000"; + "URxvt*color4" = "#4040c0"; + "URxvt*color7" = "#c0c0c0"; + "URxvt*color8" = "#707070"; + "URxvt*color9" = "#ff6060"; + "URxvt*color10" = "#70ff70"; + "URxvt*color11" = "#ffff70"; + "URxvt*color12" = "#7070ff"; + "URxvt*color13" = "#ff50ff"; + "URxvt*color14" = "#70ffff"; + "URxvt*color15" = "#ffffff"; + + "URxvt*iso14755" = "False"; + + "URxvt*urgentOnBell" = "True"; + "URxvt*visualBell" = "True"; + + # ref https://github.com/muennich/urxvt-perls + "URxvt*perl-ext" = "default,url-select"; + "URxvt*keysym.M-u" = "perl:url-select:select_next"; + "URxvt*url-select.launcher" = + "/etc/profiles/per-user/${cfg.user.name}/bin/ff -new-tab"; + "URxvt*url-select.underline" = "true"; + "URxvt*colorUL" = "#4682B4"; + "URxvt.perl-lib" = "${pkgs.urxvt_perls}/lib/urxvt/perl"; + "URxvt*saveLines" = "10000"; + "URxvt*modifier" = "mod1"; + + "root-urxvt*background" = "#230000"; + "root-urxvt*foreground" = "#e0c0c0"; + "root-urxvt*BorderColor" = "#400000"; + "root-urxvt*color0" = "#800000"; + + "fzmenu-urxvt*background" = "rgb:42/23/42"; + "fzmenu-urxvt*externalBorder" = "1"; + "fzmenu-urxvt*geometry" = "70x9"; + "fzmenu-urxvt*internalBorder" = "1"; + }; +} diff --git a/configs/xserver/xkiller.nix b/configs/xserver/xkiller.nix new file mode 100644 index 0000000..2f97630 --- /dev/null +++ b/configs/xserver/xkiller.nix @@ -0,0 +1,14 @@ +{ pkgs, ... }: { + + services.acpid.enable = true; + services.acpid.handlers.xkiller = { + action = /* sh */ '' + event=($1) + if test "''${event[2]}" = 00000080; then + ${pkgs.systemd}/bin/systemd-cat -t xkiller ${pkgs.xkiller} + fi + ''; + event = "button/prog1"; + }; + +} diff --git a/configs/xserver/xserver.conf.nix b/configs/xserver/xserver.conf.nix new file mode 100644 index 0000000..3a80567 --- /dev/null +++ b/configs/xserver/xserver.conf.nix @@ -0,0 +1,38 @@ +{ config, pkgs, ... }: + +let + cfg = config.services.xserver; +in + +pkgs.stdenv.mkDerivation { + name = "xserver.conf"; + + fontPath = optionalString (cfg.fontPath != null) + ''FontPath "${toString cfg.fontPath}"''; + + inherit (cfg) config; + + buildCommand = + '' + echo 'Section "Files"' >> $out + echo $fontPath >> $out + + for i in ${toString config.fonts.fonts}; do + if test "''${i:0:''${#NIX_STORE}}" == "$NIX_STORE"; then + for j in $(find $i -name fonts.dir); do + echo " FontPath \"$(dirname $j)\"" >> $out + done + fi + done + + for i in $(find ${toString cfg.modules} -type d); do + if test $(echo $i/*.so* | wc -w) -ne 0; then + echo " ModulePath \"$i\"" >> $out + fi + done + + echo 'EndSection' >> $out + + echo "$config" >> $out + ''; +} diff --git a/configs/xsessions/default.nix b/configs/xsessions/default.nix new file mode 100644 index 0000000..384c9c5 --- /dev/null +++ b/configs/xsessions/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./urxvtd.nix + ]; +} diff --git a/configs/xsessions/urxvtd.nix b/configs/xsessions/urxvtd.nix new file mode 100644 index 0000000..de16a63 --- /dev/null +++ b/configs/xsessions/urxvtd.nix @@ -0,0 +1,15 @@ +{ pkgs, ... }: { + systemd.user.sockets.urxvtd = { + wantedBy = [ "sockets.target" ]; + socketConfig.ListenStream = "%t/urxvtd"; + }; + systemd.user.services.urxvtd = { + restartIfChanged = false; + environment = { + RXVT_SOCKET = "%t/urxvtd"; + }; + serviceConfig = { + ExecStart = "${pkgs.rxvt_unicode}/bin/urxvtd"; + }; + }; +} |
