{ lib, pkgs, config, ... }: with lib; let cfg = config.common; dynamicForwardModule = types.submodule { options = bindOptions; }; forwardModule = types.submodule { options = { bind = bindOptions; host = { address = mkOption { type = types.nullOr types.str; default = null; example = "example.org"; description = "The address where to forward the traffic to."; }; port = mkOption { type = types.nullOr types.port; default = null; example = 80; description = "Specifies port number to forward the traffic to."; }; }; }; }; matchBlockModule = types.submodule ( { dagName, ... }: { options = { host = mkOption { type = types.nullOr types.str; default = null; example = "*.example.org"; description = '' `Host` pattern used by this conditional block. See {manpage}`ssh_config(5)` for `Host` block details. This option is ignored if {option}`ssh.matchBlocks.*.match` if defined. ''; }; match = mkOption { type = types.nullOr types.str; default = null; example = '' host canonical host exec "ping -c1 -q 192.168.17.1"''; description = '' `Match` block conditions used by this block. See {manpage}`ssh_config(5)` for `Match` block details. This option takes precedence over {option}`ssh.matchBlocks.*.host` if defined. ''; }; port = mkOption { type = types.nullOr types.port; default = null; description = "Specifies port number to connect on remote host."; }; forwardAgent = mkOption { default = null; type = types.nullOr types.bool; description = '' Whether the connection to the authentication agent (if any) will be forwarded to the remote machine. ''; }; forwardX11 = mkOption { type = types.bool; default = false; description = '' Specifies whether X11 connections will be automatically redirected over the secure channel and {env}`DISPLAY` set. ''; }; forwardX11Trusted = mkOption { type = types.bool; default = false; description = '' Specifies whether remote X11 clients will have full access to the original X11 display. ''; }; identitiesOnly = mkOption { type = types.bool; default = false; description = '' Specifies that ssh should only use the authentication identity explicitly configured in the {file}`~/.ssh/config` files or passed on the ssh command-line, even if {command}`ssh-agent` offers more identities. ''; }; identityFile = mkOption { type = with types; either (listOf str) (nullOr str); default = [ ]; apply = p: if p == null then [ ] else if isString p then [ p ] else p; description = '' Specifies files from which the user identity is read. Identities will be tried in the given order. ''; }; user = mkOption { type = types.nullOr types.str; default = null; description = "Specifies the user to log in as."; }; hostname = mkOption { type = types.nullOr types.str; default = null; description = "Specifies the real host name to log into."; }; serverAliveInterval = mkOption { type = types.int; default = 0; description = "Set timeout in seconds after which response will be requested."; }; serverAliveCountMax = mkOption { type = types.ints.positive; default = 3; description = '' Sets the number of server alive messages which may be sent without SSH receiving any messages back from the server. ''; }; sendEnv = mkOption { type = types.listOf types.str; default = [ ]; description = '' Environment variables to send from the local host to the server. ''; }; setEnv = mkOption { type = with types; attrsOf (oneOf [ str path int float ]); default = { }; description = '' Environment variables and their value to send to the server. ''; }; compression = mkOption { type = types.nullOr types.bool; default = null; description = '' Specifies whether to use compression. Omitted from the host block when `null`. ''; }; checkHostIP = mkOption { type = types.bool; default = true; description = '' Check the host IP address in the {file}`known_hosts` file. ''; }; proxyCommand = mkOption { type = types.nullOr types.str; default = null; description = "The command to use to connect to the server."; }; proxyJump = mkOption { type = types.nullOr types.str; default = null; description = "The proxy host to use to connect to the server."; }; certificateFile = mkOption { type = with types; either (listOf str) (nullOr str); default = [ ]; apply = p: if p == null then [ ] else if isString p then [ p ] else p; description = '' Specifies files from which the user certificate is read. ''; }; addressFamily = mkOption { default = null; type = types.nullOr ( types.enum [ "any" "inet" "inet6" ] ); description = '' Specifies which address family to use when connecting. ''; }; localForwards = mkOption { type = types.listOf forwardModule; default = [ ]; example = literalExpression '' [ { bind.port = 8080; host.address = "10.0.0.13"; host.port = 80; } ]; ''; description = '' Specify local port forwardings. See {manpage}`ssh_config(5)` for `LocalForward`. ''; }; remoteForwards = mkOption { type = types.listOf forwardModule; default = [ ]; example = literalExpression '' [ { bind.port = 8080; host.address = "10.0.0.13"; host.port = 80; } ]; ''; description = '' Specify remote port forwardings. See {manpage}`ssh_config(5)` for `RemoteForward`. ''; }; dynamicForwards = mkOption { type = types.listOf dynamicForwardModule; default = [ ]; example = literalExpression '' [ { port = 8080; } ]; ''; description = '' Specify dynamic port forwardings. See {manpage}`ssh_config(5)` for `DynamicForward`. ''; }; extraOptions = mkOption { type = types.attrsOf types.str; default = { }; description = "Extra configuration options for the host."; }; }; } ); in { options.programs.ssh = { customMatchBlocks = mkOption { type = hm.types.dagOf matchBlockModule; default = { }; example = literalExpression '' { "john.example.com" = { hostname = "example.com"; user = "john"; }; foo = lib.hm.dag.entryBefore ["john.example.com"] { hostname = "example.com"; identityFile = "/home/john/.ssh/foo_rsa"; }; }; ''; description = '' Specify per-host settings. Note, if the order of rules matter then use the DAG functions to express the dependencies as shown in the example. See {manpage}`ssh_config(5)` for more information. ''; }; }; options.common = { userHome = mkOption { type = types.str; default = null; example = "/home/user"; description = "Sets the user's home path."; }; }; config = { home.sessionVariables = { PAGER = "less -RFX --tabs=4"; MANPAGER = "nvim +'setl filetype=terminal' +'Man!'"; SSH_AUTH_SOCK = "$XDG_RUNTIME_DIR/keyring/ssh"; NIXOS_OZONE_WL = "1"; }; xdg.mimeApps = { enable = true; defaultApplications = { "text/html" = "firefox.desktop"; "x-scheme-handler/http" = "firefox.desktop"; "x-scheme-handler/https" = "firefox.desktop"; "x-scheme-handler/about" = "firefox.desktop"; "x-scheme-handler/unknown" = "firefox.desktop"; "application/pdf" = "org.pwmt.zathura-ps.desktop"; "x-scheme-handler/mailto" = "userapp-Thunderbird-3NBJQ2.desktop"; "x-scheme-handler/mid" = "userapp-Thunderbird-3NBJQ2.desktop"; "x-scheme-handler/news" = "userapp-Thunderbird-QJOCQ2.desktop"; "x-scheme-handler/snews" = "userapp-Thunderbird-QJOCQ2.desktop"; "x-scheme-handler/nntp" = "userapp-Thunderbird-QJOCQ2.desktop"; "x-scheme-handler/feed" = "userapp-Thunderbird-EIXEQ2.desktop"; "application/rss+xml" = "userapp-Thunderbird-EIXEQ2.desktop"; "application/x-extension-rss" = "userapp-Thunderbird-EIXEQ2.desktop"; "x-scheme-handler/webcal" = "userapp-Thunderbird-LBFEQ2.desktop"; "x-scheme-handler/webcals" = "userapp-Thunderbird-LBFEQ2.desktop"; "message/rfc822" = "userapp-Thunderbird-3NBJQ2.desktop"; "text/calendar" = "userapp-Thunderbird-LBFEQ2.desktop"; "application/x-extension-ics" = "userapp-Thunderbird-LBFEQ2.desktop"; "application/x-bittorrent;x-scheme-handler/magnet" = "transmission-remote-gtk.desktop"; }; }; xdg.portal = { enable = true; configPackages = with pkgs; [ hyprland ]; extraPortals = with pkgs; [ hyprland ]; }; # Allow unfree packages (crying FSF noises) nixpkgs.config.allowUnfree = true; nixpkgs.config.packageOverrides = pkgs: { nur = import (builtins.fetchTarball "https://github.com/nix-community/NUR/archive/master.tar.gz") { inherit pkgs; }; }; # Packages that should be installed to the user profile. home.packages = with pkgs; [ prismlauncher # Minecraft element-desktop # Matrix Desktop Client tidal-hifi # Tidal Web Client helvum # pipewire patchbay bitwarden-cli # password and secret manager ansible # declarative server managment packwiz # Minecraft mod pack managment just # A handy way to save and run project-specific commands ydotool # wayland automation tool lunarvim # IDE layer for Neovim cloudflared # cloudflare things sbctl # For debugging and troubleshooting Secure Boot killall # killall dmenu # (program) picker for Xorg xorg.xauth # Dependency of startx (??) wl-clipboard # Wayland clipboard functionality bottom # htop, but in Rust and better tree # tree fzf # Fuzzy Find pwvucontrol # pipewire volume control brave # Chromium based fallback browser qalculate-gtk # Best calculator ever wofi # dmenu, but for wlroots wayland kitty # kitty terminal emulator waybar # Status bar for wayland compositors grim # screenshot tool playerctl # Media control slurp # selection tool mako # Notification Daemon nmap # port scanning tool libreoffice-qt # Office Suite hunspell # Spellchecking hunspellDicts.de_DE # German Spellcheck hunspellDicts.en_US # English Spellcheck shellcheck # Shell linter jq # JSON utility texlive.combined.scheme-full # LaTeX zathura # minimal PDF Viewer gimp # gnu image manipulation program p7zip # (7)zip tool zip # standard unix zip tool signal-desktop # Signal Desktop Client lazygit # Terminal git frontend mpv # Video Playback vlc # media playback imv # minimal image viewer celluloid # mpv frontend mumble # FOSS Steam Speak easyeffects # some audio effects hypridle # idle daemon for hyprland hyprpaper # Hyprpland backgrounds brightnessctl # brightness control cli rustc # rust compiler rust-analyzer # Rust LSP cargo # rust build tool gcc # GNU Compiler Collections clang-tools # LSP Server + formatter nodePackages.vscode-json-languageserver # ZED Json LSP ddcutil # Screen controls wireguard-tools # Wireguard man-pages # dev man pages man-pages-posix # dev man pages steamcmd # steamcmd wget # downloader xclip # Clipboard wine # win translator protontricks # Managment of proton enabled games lutris # Linux Game Manager vesktop # !delete voip/messenger brasero # Disc-Burner cdrtools # CD tools cdrdao # CD tools dvdplusrwtools # DVD + Blu-ray tools tidal-dl # Tidal ripper vscodium-fhs # VS Code niv # Nix dependency managment bottles # WINE Prefix manager transmission-remote-gtk # Torrent Client qemu # Virtualization/Emulation bash # Compat jetbrains.idea-ultimate # IntelliJ Ultimate maven # Java Build tool jdk # Java development kit nixfmt-rfc-style # official nix formatter ripgrep # some nice grep alternative netcat-openbsd # socket debugging #libsForQt5.qtstyleplugin-kvantum # qt theme #libsForQt5.qt5ct # qt theme virtiofsd # virtiofs drivers filezilla # FTP client ]; catppuccin = { accent = "blue"; enable = true; zed.enable = false; cursors = { enable = true; accent = "dark"; }; }; fonts.fontconfig = { enable = true; defaultFonts = { monospace = [ "Fira Code" ]; sansSerif = [ "Fira Sans" ]; }; }; home.pointerCursor = { gtk.enable = true; hyprcursor.enable = true; x11.enable = true; size = 16; }; programs = { zsh = { enable = true; enableCompletion = true; autosuggestion.enable = true; syntaxHighlighting.enable = true; autocd = true; shellAliases = { g = "git"; git-list-untracked = ''git fetch --prune && git branch -r | awk "{print \$1}" | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk "{print \$1}"''; git-remove-untracked = ''git fetch --prune && git branch -r | awk "{print \$1}" | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk "{print \$1}" | xargs git branch -d''; }; }; nix-your-shell.enable = true; bash.enable = true; kitty = { enable = true; #themeFile = "Catppuccin-Mocha"; font = { name = "Fira Code"; package = pkgs.fira-code; }; settings = { enable_audio_bell = false; background_opacity = 0.85; }; }; git = { enable = true; userName = "Leon Wilzer"; aliases = { ci = "commit"; ca = "commit --amend"; ri = "rebase -i"; co = "checkout"; s = "status"; undo = "reset --soft 'HEAD^'"; a = "add -A"; p = "push"; fp = "push --force-with-lease"; c = "clone"; cc = ''clone "$(wl-paste)"''; d = "diff"; dh = "diff HEAD"; }; diff-so-fancy = { enable = true; }; extraConfig = { push = { autoSetupRemote = true; }; merge.tool = "nvimdiff2"; commit = { gpgsign = true; }; tag = { gpgSign = true; }; }; }; gpg = { enable = true; }; ssh = let sshDir = "${cfg.userHome}/.ssh"; startAgent = false; in { enable = true; package = pkgs.opensshWithKerberos; addKeysToAgent = "yes"; matchBlocks = { "libre.moe *.libre.moe" = { user = "leon"; identityFile = "${sshDir}/libremoe"; }; "komu.boo *.komu.boo" = { user = "root"; identityFile = "${sshDir}/komuboo"; }; "github.com" = { user = "git"; identityFile = "${sshDir}/github"; }; "git.cs.uni-paderborn.de git.cs.upb.de" = lib.hm.dag.entryBefore [ "*.cs.upb.de *.cs.uni-paderborn.de" ] { user = "git"; identityFile = "${sshDir}/upb"; }; "*.cs.upb.de *.cs.uni-paderborn.de" = { extraOptions = { GSSAPIAuthentication = "yes"; GSSAPIDelegateCredentials = "yes"; }; user = "lwilzer"; }; "*.cs.upb.de *.cs.uni-paderborn.de,!sshgate.*,!git.*" = lib.hm.dag.entryAfter [ "*.cs.upb.de *.cs.uni-paderborn.de" ] { proxyJump = "sshgate.cs.uni-paderborn.de"; }; } // config.programs.ssh.customMatchBlocks; }; neovim = { enable = true; defaultEditor = true; vimAlias = true; viAlias = true; vimdiffAlias = true; extraConfig = '' " General set number set relativenumber set cc=120 set tabstop=4 set softtabstop=0 noexpandtab set shiftwidth=4 hi Normal guibg=NONE ctermbg=NONE " VimTex filetype plugin indent on syntax enable let g:vimtex_view_method = 'zathura' " Vim-LaTeX-live-preview let g:livepreview_previewer = 'zathura' lua require'terminal'.setup() ''; plugins = with pkgs.vimPlugins; [ vimtex vim-latex-live-preview nvim-terminal-lua ]; }; tealdeer = { enable = true; settings = { display = { use_pager = true; }; updates = { auto_update = true; auto_update_interval_hours = 24; }; }; }; man = { enable = true; generateCaches = true; }; thunderbird = { enable = true; profiles.default = { isDefault = true; withExternalGnupg = true; }; }; zed-editor = { enable = true; userSettings = { vim_mode = true; auto_install_extensions = { }; theme = { mode = "system"; light = "Catppuccin Latte (Blue Blur+)"; dark = "Catppuccin Mocha (Blue Blur+)"; }; features = { copilot = false; }; telemetry = { metrics = false; }; }; }; hyprlock = { enable = true; settings = { # General general = { disable_loading_bar = true; hide_cursor = true; }; # Background background = { monitor = ""; path = "$XDG_PICTURES_DIR/Wallpapers/current"; blur_passes = 4; blur_size = 8; color = "rgba($baseAlphaff)"; }; # Time label = { monitor = ""; text = ''cmd[update:30000] echo "$(date +"%R")"''; color = "$text"; font_size = 90; font_family = "$font"; position = "-30, 0"; halign = "right"; valign = "top"; }; # Use Avatar image = { monitor = ""; path = "~/.face"; size = 100; border_color = "$accent"; position = "0, 75"; halign = "center"; valign = "center"; }; # Input Field input-field = { monitor = ""; size = "300, 60"; outline_thickness = 4; dots_size = 0.2; dots_spacing = 0.2; dots_center = true; outer_color = "$accent"; inner_color = "$surface0"; font_color = "$text"; fade_on_empty = false; placeholder_text = ''󰌾 Logged in as $USER''; hide_input = false; check_color = "$accent"; fail_color = "$red"; fail_text = "$FAIL ($ATTEMPTS)"; capslock_color = "$yellow"; position = "0, -35"; halign = "center"; valign = "center"; }; }; }; # Let Home Manager install and manage itself. home-manager.enable = true; }; # X11 xsession.enable = true; xsession.windowManager.command = "dwm"; wayland.windowManager.hyprland.systemd.enable = false; gtk = { enable = true; font = { package = pkgs.fira; name = "Fira Sans"; }; cursorTheme = { size = 16; name = "catppuccin-dark-blue-cursors"; }; iconTheme = { name = "catppuccin-papirus-folders"; package = pkgs.catppuccin-papirus-folders; }; }; qt = { enable = true; platformTheme.name = "kvantum"; style = { name = "kvantum"; # package = pkgs.catppuccin; }; }; services = { mako = { enable = true; defaultTimeout = 8000; }; gpg-agent = { enable = true; enableSshSupport = false; pinentryPackage = pkgs.pinentry-all; }; gnome-keyring = { enable = true; components = [ "pkcs11" "secrets" "ssh" ]; }; ssh-agent.enable = false; }; dconf = { enable = true; settings = { "org/virt-manager/virt-manager/connections" = { autoconnect = [ "qemu:///system" ]; uris = [ "qemu:///system" ]; }; "org/gnome/desktop/interface".color-scheme = "prefer-dark"; }; }; systemd.user.services = { hyprpolkitagent = { Unit = { Description = "hyprpolkit agent"; After = "graphical-session.target"; WantedBy = [ "graphical-session.target" ]; Wants = [ "graphical-session.target" ]; }; Service = { Type = "simple"; ExecStart = "${pkgs.hyprpolkitagent}/libexec/hyprpolkitagent"; Restart = "on-failure"; RestartSec = 1; TimeoutStopSec = 10; }; }; }; # This value determines the Home Manager release that your # configuration is compatible with. This helps avoid breakage # when a new Home Manager release introduces backwards # incompatible changes. # # You can update Home Manager without changing this value. See # the Home Manager release notes for a list of state version # changes in each release. home.stateVersion = "24.05"; }; }