diff --git a/flake.lock b/flake.lock index 65b8f04..080c212 100644 --- a/flake.lock +++ b/flake.lock @@ -14,11 +14,11 @@ ] }, "locked": { - "lastModified": 1736955230, - "narHash": "sha256-uenf8fv2eG5bKM8C/UvFaiJMZ4IpUFaQxk9OH5t/1gA=", + "lastModified": 1754337839, + "narHash": "sha256-fEc2/4YsJwtnLU7HCFMRckb0u9UNnDZmwGhXT5U5NTw=", "owner": "ryantm", "repo": "agenix", - "rev": "e600439ec4c273cf11e06fe4d9d906fb98fa097c", + "rev": "856df6f6922845abd4fd958ce21febc07ca2fa45", "type": "github" }, "original": { @@ -36,11 +36,11 @@ ] }, "locked": { - "lastModified": 1700795494, - "narHash": "sha256-gzGLZSiOhf155FW7262kdHo2YDeugp3VuIFb4/GGng0=", + "lastModified": 1744478979, + "narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=", "owner": "lnl7", "repo": "nix-darwin", - "rev": "4b9b83d5a92e8c1fbfd8eb27eda375908c11ec4d", + "rev": "43975d782b418ebf4969e9ccba82466728c2851b", "type": "github" }, "original": { @@ -73,11 +73,11 @@ ] }, "locked": { - "lastModified": 1743550720, - "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=", + "lastModified": 1754091436, + "narHash": "sha256-XKqDMN1/Qj1DKivQvscI4vmHfDfvYR2pfuFOJiCeewM=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "c621e8422220273271f52058f618c94e405bb0f5", + "rev": "67df8c627c2c39c41dbec76a1f201929929ab0bd", "type": "github" }, "original": { @@ -117,11 +117,11 @@ ] }, "locked": { - "lastModified": 1742649964, - "narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=", + "lastModified": 1750779888, + "narHash": "sha256-wibppH3g/E2lxU43ZQHC5yA/7kIKLGxVEnsnVK1BtRg=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82", + "rev": "16ec914f6fb6f599ce988427d9d94efddf25fe6d", "type": "github" }, "original": { @@ -159,11 +159,11 @@ ] }, "locked": { - "lastModified": 1743869639, - "narHash": "sha256-Xhe3whfRW/Ay05z9m1EZ1/AkbV1yo0tm1CbgjtCi4rQ=", + "lastModified": 1754365350, + "narHash": "sha256-NLWIkn1qM0wxtZu/2NXRaujWJ4Y1PSZlc7h0y6pOzOQ=", "owner": "nix-community", "repo": "home-manager", - "rev": "d094c6763c6ddb860580e7d3b4201f8f496a6836", + "rev": "c5d7e957397ecb7d48b99c928611c6e780db1b56", "type": "github" }, "original": { @@ -175,11 +175,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1744777043, - "narHash": "sha256-O6jgTxz9BKUiaJl03JsVHvSjtCOC8gHfDvC2UCfcLMc=", + "lastModified": 1754372978, + "narHash": "sha256-ByII9p9ek0k9UADC/hT+i9ueM2mw0Zxiz+bOlydU6Oo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7a6f7f4c1c69eee05641beaa40e7f85da8e69fb0", + "rev": "9ebe222ec7ef9de52478f76cba3f0324c1d1119f", "type": "github" }, "original": { @@ -200,11 +200,11 @@ "treefmt-nix": "treefmt-nix" }, "locked": { - "lastModified": 1741294988, - "narHash": "sha256-3408u6q615kVTb23WtDriHRmCBBpwX7iau6rvfipcu4=", + "lastModified": 1753980880, + "narHash": "sha256-aj1pbYxL6N+XFqBHjB4B1QP0bnKRcg1AfpgT5zUFsW8=", "owner": "nix-community", "repo": "NUR", - "rev": "b30c245e2c44c7352a27485bfd5bc483df660f0e", + "rev": "16db3e61da7606984a05b4dfc33cd1d26d22fb22", "type": "github" }, "original": { diff --git a/flake/home-manager.nix b/flake/home-manager.nix index 093ae8c..88a74e8 100644 --- a/flake/home-manager.nix +++ b/flake/home-manager.nix @@ -22,10 +22,6 @@ let ]; mkHome = name: system: inputs.home-manager.lib.homeManagerConfiguration { - # Work-around for home-manager - # * not letting me set `lib` as an extraSpecialArgs - # * not respecting `nixpkgs.overlays` [1] - # [1]: https://github.com/nix-community/home-manager/issues/2954 pkgs = inputs.nixpkgs.legacyPackages.${system}; modules = defaultModules ++ [ diff --git a/flake/nixos.nix b/flake/nixos.nix index bf9eac8..0fbd3a6 100644 --- a/flake/nixos.nix +++ b/flake/nixos.nix @@ -15,8 +15,10 @@ let ]; buildHost = name: system: lib.nixosSystem { - inherit system; modules = defaultModules ++ [ + { + nixpkgs.hostPlatform = system; + } "${self}/hosts/nixos/${name}" ]; specialArgs = { diff --git a/hosts/homes/ambroisie@bazin/default.nix b/hosts/homes/ambroisie@bazin/default.nix index f52fbce..cfeba83 100644 --- a/hosts/homes/ambroisie@bazin/default.nix +++ b/hosts/homes/ambroisie@bazin/default.nix @@ -4,6 +4,20 @@ services.gpg-agent.enable = lib.mkForce false; my.home = { + atuin = { + package = pkgs.stdenv.mkDerivation { + pname = "atuin"; + version = "18.4.0"; + + buildCommand = '' + mkdir -p $out/bin + ln -s /usr/bin/atuin $out/bin/atuin + ''; + + meta.mainProgram = "atuin"; + }; + }; + git = { package = pkgs.emptyDirectory; }; @@ -15,6 +29,8 @@ terminalFeatures = { # HTerm uses `xterm-256color` as its `$TERM`, so use that here xterm-256color = { }; + # Terminal app uses `xterm.js`, not HTerm + "xterm.js" = { }; }; }; diff --git a/hosts/homes/ambroisie@mousqueton/default.nix b/hosts/homes/ambroisie@mousqueton/default.nix index 37884d7..b6193c9 100644 --- a/hosts/homes/ambroisie@mousqueton/default.nix +++ b/hosts/homes/ambroisie@mousqueton/default.nix @@ -7,6 +7,20 @@ services.gpg-agent.enable = lib.mkForce false; my.home = { + atuin = { + package = pkgs.stdenv.mkDerivation { + pname = "atuin"; + version = "18.4.0"; + + buildCommand = '' + mkdir -p $out/bin + ln -s /usr/bin/atuin $out/bin/atuin + ''; + + meta.mainProgram = "atuin"; + }; + }; + git = { package = pkgs.emptyDirectory; }; @@ -21,6 +35,8 @@ terminalFeatures = { # HTerm uses `xterm-256color` as its `$TERM`, so use that here xterm-256color = { }; + # Terminal app uses `xterm.js`, not HTerm + "xterm.js" = { }; }; }; }; diff --git a/hosts/nixos/aramis/home.nix b/hosts/nixos/aramis/home.nix index 64b63ce..221b1ea 100644 --- a/hosts/nixos/aramis/home.nix +++ b/hosts/nixos/aramis/home.nix @@ -20,7 +20,7 @@ element-desktop # Matrix client jellyfin-media-player # Wraps the webui and mpv together pavucontrol # Audio mixer GUI - transgui # Transmission remote + trgui-ng # Transmission remote ]; # Minimal video player mpv.enable = true; diff --git a/hosts/nixos/porthos/secrets/servarr/cross-seed/configuration.json.age b/hosts/nixos/porthos/secrets/servarr/cross-seed/configuration.json.age index e9af03f..e319f3a 100644 Binary files a/hosts/nixos/porthos/secrets/servarr/cross-seed/configuration.json.age and b/hosts/nixos/porthos/secrets/servarr/cross-seed/configuration.json.age differ diff --git a/modules/home/default.nix b/modules/home/default.nix index c8183cf..1c40377 100644 --- a/modules/home/default.nix +++ b/modules/home/default.nix @@ -8,6 +8,7 @@ ./bluetooth ./calibre ./comma + ./delta ./dircolors ./direnv ./discord @@ -50,9 +51,6 @@ # First sane reproducible version home.stateVersion = "20.09"; - # Who am I? - home.username = "ambroisie"; - # Start services automatically systemd.user.startServices = "sd-switch"; } diff --git a/modules/home/delta/default.nix b/modules/home/delta/default.nix new file mode 100644 index 0000000..58ee031 --- /dev/null +++ b/modules/home/delta/default.nix @@ -0,0 +1,68 @@ +{ config, pkgs, lib, ... }: +let + cfg = config.my.home.delta; +in +{ + options.my.home.delta = with lib; { + enable = my.mkDisableOption "delta configuration"; + + package = mkPackageOption pkgs "delta" { }; + + git = { + enable = my.mkDisableOption "git integration"; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + # For its configuration + assertion = cfg.enable -> cfg.git.enable; + message = '' + `config.my.home.delta` must enable `config.my.home.delta.git` to be + properly configured. + ''; + } + { + assertion = cfg.enable -> config.programs.git.enable; + message = '' + `config.my.home.delta` relies on `config.programs.git` to be + enabled. + ''; + } + ]; + + home.packages = [ cfg.package ]; + + programs.git = lib.mkIf cfg.git.enable { + delta = { + enable = true; + inherit (cfg) package; + + options = { + features = "diff-highlight decorations"; + + # Less jarring style for `diff-highlight` emulation + diff-highlight = { + minus-style = "red"; + minus-non-emph-style = "red"; + minus-emph-style = "bold red 52"; + + plus-style = "green"; + plus-non-emph-style = "green"; + plus-emph-style = "bold green 22"; + + whitespace-error-style = "reverse red"; + }; + + # Personal preference for easier reading + decorations = { + commit-style = "raw"; # Do not recolor meta information + keep-plus-minus-markers = true; + paging = "always"; + }; + }; + }; + }; + }; +} diff --git a/modules/home/direnv/lib/python.sh b/modules/home/direnv/lib/python.sh index b4b2bce..b1be8a9 100644 --- a/modules/home/direnv/lib/python.sh +++ b/modules/home/direnv/lib/python.sh @@ -46,7 +46,7 @@ layout_uv() { fi # create venv if it doesn't exist - uv venv -q + uv venv -q --allow-existing export VIRTUAL_ENV export UV_ACTIVE=1 diff --git a/modules/home/firefox/tridactyl/default.nix b/modules/home/firefox/tridactyl/default.nix index 35b58c2..26ddfad 100644 --- a/modules/home/firefox/tridactyl/default.nix +++ b/modules/home/firefox/tridactyl/default.nix @@ -12,9 +12,7 @@ let in { config = lib.mkIf cfg.enable { - xdg.configFile."tridactyl/tridactylrc".source = pkgs.substituteAll { - src = ./tridactylrc; - + xdg.configFile."tridactyl/tridactylrc".source = pkgs.replaceVars ./tridactylrc { editorcmd = lib.concatStringsSep " " [ # Use my configured terminal term diff --git a/modules/home/git/default.nix b/modules/home/git/default.nix index c88008f..ca59a5f 100644 --- a/modules/home/git/default.nix +++ b/modules/home/git/default.nix @@ -42,34 +42,6 @@ in lfs.enable = true; - delta = { - enable = true; - - options = { - features = "diff-highlight decorations"; - - # Less jarring style for `diff-highlight` emulation - diff-highlight = { - minus-style = "red"; - minus-non-emph-style = "red"; - minus-emph-style = "bold red 52"; - - plus-style = "green"; - plus-non-emph-style = "green"; - plus-emph-style = "bold green 22"; - - whitespace-error-style = "reverse red"; - }; - - # Personal preference for easier reading - decorations = { - commit-style = "raw"; # Do not recolor meta information - keep-plus-minus-markers = true; - paging = "always"; - }; - }; - }; - # There's more extraConfig = { # Makes it a bit more readable diff --git a/modules/home/gpg/default.nix b/modules/home/gpg/default.nix index 51c865a..2a00baf 100644 --- a/modules/home/gpg/default.nix +++ b/modules/home/gpg/default.nix @@ -17,7 +17,7 @@ in services.gpg-agent = { enable = true; enableSshSupport = true; # One agent to rule them all - pinentryPackage = cfg.pinentry; + pinentry.package = cfg.pinentry; extraConfig = '' allow-loopback-pinentry ''; diff --git a/modules/home/tmux/default.nix b/modules/home/tmux/default.nix index 08b9202..d267516 100644 --- a/modules/home/tmux/default.nix +++ b/modules/home/tmux/default.nix @@ -6,13 +6,16 @@ let (config.my.home.wm.windowManager != null) ]; - mkTerminalFlags = opt: flag: + mkTerminalFlag = tmuxVar: opt: flag: let - mkFlag = term: ''set -as terminal-features ",${term}:${flag}"''; + mkFlag = term: ''set -as ${tmuxVar} ",${term}:${flag}"''; enabledTerminals = lib.filterAttrs (_: v: v.${opt}) cfg.terminalFeatures; terminals = lib.attrNames enabledTerminals; in lib.concatMapStringsSep "\n" mkFlag terminals; + + mkTerminalFeature = mkTerminalFlag "terminal-features"; + mkTerminalOverride = mkTerminalFlag "terminal-overrides"; in { options.my.home.tmux = with lib; { @@ -28,6 +31,8 @@ in hyperlinks = my.mkDisableOption "hyperlinks through OSC8"; trueColor = my.mkDisableOption "24-bit (RGB) color support"; + + underscoreStyle = my.mkDisableOption "underscore style/color support"; }; }); @@ -48,12 +53,26 @@ in keyMode = "vi"; # Home-row keys and other niceties clock24 = true; # I'm one of those heathens escapeTime = 0; # Let vim do its thing instead - historyLimit = 100000; # Bigger buffer + historyLimit = 1000000; # Bigger buffer mouse = false; # I dislike mouse support focusEvents = true; # Report focus events terminal = "tmux-256color"; # I want accurate termcap info aggressiveResize = true; # Automatic resize when switching client size + # FIXME + # * Sixel support + # * OSC 133 prompt integration + # FIXME: when sensible-on-top is disabled: check if any of those are unset + # * tmux bind-key $prefix_without_ctrl last-window + # * + # * tmux bind-key C-b send-prefix: included + # * aggressive resize? done + # * tmux bind-key C-p previous-window: done + # * tmux bind-key C-n next-window: done + # * C-r to refresh my config: done + # * tmux set-option -g focus-events on: done + + # FIXME: make PRs for `bind-key` description plugins = with pkgs.tmuxPlugins; builtins.filter (attr: attr != { }) [ # Open high-lighted files in copy mode open @@ -123,9 +142,14 @@ in } # Force OSC8 hyperlinks for each relevant $TERM - ${mkTerminalFlags "hyperlinks" "hyperlinks"} + ${mkTerminalFeature "hyperlinks" "hyperlinks"} # Force 24-bit color for each relevant $TERM - ${mkTerminalFlags "trueColor" "RGB"} + ${mkTerminalFeature "trueColor" "RGB"} + # Force underscore style/color for each relevant $TERM + ${mkTerminalFeature "underscoreStyle" "usstyle"} + # FIXME: see https://github.com/folke/tokyonight.nvim#fix-undercurls-in-tmux for additional overrides + # ${mkTerminalOverride "underscoreStyle" "Smulx=\\E[4::%p1%dm"} + # ${mkTerminalOverride "underscoreStyle" "Setulc=\\E[58::2::::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m"} ''; }; } diff --git a/modules/home/vim/after/queries/gitcommit/highlights.scm b/modules/home/vim/after/queries/gitcommit/highlights.scm new file mode 100644 index 0000000..05162c9 --- /dev/null +++ b/modules/home/vim/after/queries/gitcommit/highlights.scm @@ -0,0 +1,6 @@ +; extends + +; Highlight over-extended subject lines (rely on wrapping for message body) +((subject) @comment.error + (#vim-match? @comment.error ".\{50,}") + (#offset! @comment.error 0 50 0 0)) diff --git a/modules/home/vim/default.nix b/modules/home/vim/default.nix index 20a74ff..930a853 100644 --- a/modules/home/vim/default.nix +++ b/modules/home/vim/default.nix @@ -80,7 +80,6 @@ in nvim-surround # Deal with pairs, now in Lua oil-nvim # Better alternative to NetrW telescope-fzf-native-nvim # Use 'fzf' fuzzy matching algorithm - telescope-lsp-handlers-nvim # Use 'telescope' for various LSP actions telescope-nvim # Fuzzy finder interface which-key-nvim # Show available mappings ]; diff --git a/modules/home/vim/lua/ambroisie/lsp.lua b/modules/home/vim/lua/ambroisie/lsp.lua index e48de12..fef0487 100644 --- a/modules/home/vim/lua/ambroisie/lsp.lua +++ b/modules/home/vim/lua/ambroisie/lsp.lua @@ -53,6 +53,10 @@ M.on_attach = function(client, bufnr) vim.diagnostic.open_float(nil, { scope = "buffer" }) end + local function toggle_inlay_hints() + vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled()) + end + local keys = { buffer = bufnr, -- LSP navigation @@ -67,6 +71,7 @@ M.on_attach = function(client, bufnr) { "ca", vim.lsp.buf.code_action, desc = "Code actions" }, { "cd", cycle_diagnostics_display, desc = "Cycle diagnostics display" }, { "cD", show_buffer_diagnostics, desc = "Show buffer diagnostics" }, + { "ch", toggle_inlay_hints, desc = "Toggle inlay hints" }, { "cr", vim.lsp.buf.rename, desc = "Rename symbol" }, { "cs", vim.lsp.buf.signature_help, desc = "Show signature" }, { "ct", vim.lsp.buf.type_definition, desc = "Go to type definition" }, diff --git a/modules/home/vim/plugin/settings/telescope.lua b/modules/home/vim/plugin/settings/telescope.lua index 1a23928..810d51c 100644 --- a/modules/home/vim/plugin/settings/telescope.lua +++ b/modules/home/vim/plugin/settings/telescope.lua @@ -23,7 +23,6 @@ telescope.setup({ }) telescope.load_extension("fzf") -telescope.load_extension("lsp_handlers") local keys = { { "f", group = "Fuzzy finder" }, diff --git a/modules/home/wm/i3/default.nix b/modules/home/wm/i3/default.nix index 029a14b..5f22bbe 100644 --- a/modules/home/wm/i3/default.nix +++ b/modules/home/wm/i3/default.nix @@ -127,6 +127,7 @@ in { class = "^Blueman-.*$"; } { title = "^htop$"; } { class = "^Thunderbird$"; instance = "Mailnews"; window_role = "filterlist"; } + { class = "^firefox$"; instance = "Places"; window_role = "Organizer"; } { class = "^pavucontrol.*$"; } { class = "^Arandr$"; } { class = "^\\.blueman-manager-wrapped$"; } diff --git a/modules/home/xdg/default.nix b/modules/home/xdg/default.nix index 803167f..7a0c517 100644 --- a/modules/home/xdg/default.nix +++ b/modules/home/xdg/default.nix @@ -56,4 +56,7 @@ in XCOMPOSECACHE = "${dataHome}/X11/xcompose"; _JAVA_OPTIONS = "-Djava.util.prefs.userRoot=${configHome}/java"; }; + + # Some modules *optionally* use `XDG_*_HOME` when told to + config.home.preferXdgDirectories = lib.mkIf cfg.enable true; } diff --git a/modules/home/zsh/default.nix b/modules/home/zsh/default.nix index f4092d8..1e85cce 100644 --- a/modules/home/zsh/default.nix +++ b/modules/home/zsh/default.nix @@ -1,14 +1,6 @@ { config, pkgs, lib, ... }: let cfg = config.my.home.zsh; - - # Have a nice relative path for XDG_CONFIG_HOME, without leading `/` - relativeXdgConfig = - let - noHome = lib.removePrefix config.home.homeDirectory; - noSlash = lib.removePrefix "/"; - in - noSlash (noHome config.xdg.configHome); in { options.my.home.zsh = with lib; { @@ -22,10 +14,12 @@ in exclude = mkOption { type = with types; listOf str; default = [ + "bat" "delta" "direnv reload" "fg" "git (?!push|pull|fetch)" + "home-manager (?!switch|build|news)" "htop" "less" "man" @@ -57,7 +51,7 @@ in programs.zsh = { enable = true; - dotDir = "${relativeXdgConfig}/zsh"; # Don't clutter $HOME + dotDir = "${config.xdg.configHome}/zsh"; # Don't clutter $HOME enableCompletion = true; history = { diff --git a/modules/nixos/profiles/wm/default.nix b/modules/nixos/profiles/wm/default.nix index c227328..bca4d70 100644 --- a/modules/nixos/profiles/wm/default.nix +++ b/modules/nixos/profiles/wm/default.nix @@ -24,6 +24,8 @@ in my.home.udiskie.enable = true; # udiskie fails if it can't find this dbus service services.udisks2.enable = true; + # Ensure i3lock can actually unlock the session + security.pam.services.i3lock.enable = true; }) ]; } diff --git a/modules/nixos/services/default.nix b/modules/nixos/services/default.nix index 27f8765..e03eca1 100644 --- a/modules/nixos/services/default.nix +++ b/modules/nixos/services/default.nix @@ -38,6 +38,7 @@ ./servarr ./ssh-server ./tandoor-recipes + ./thelounge ./tlp ./transmission ./vikunja diff --git a/modules/nixos/services/drone/server/default.nix b/modules/nixos/services/drone/server/default.nix index a3a1e49..d6148f4 100644 --- a/modules/nixos/services/drone/server/default.nix +++ b/modules/nixos/services/drone/server/default.nix @@ -6,8 +6,8 @@ in config = lib.mkIf cfg.enable { systemd.services.drone-server = { wantedBy = [ "multi-user.target" ]; - after = [ "postgresql.service" ]; - requires = [ "postgresql.service" ]; + after = [ "postgresql.target" ]; + requires = [ "postgresql.target" ]; serviceConfig = { EnvironmentFile = [ cfg.secretFile diff --git a/modules/nixos/services/matrix/bridges.nix b/modules/nixos/services/matrix/bridges.nix new file mode 100644 index 0000000..70f4118 --- /dev/null +++ b/modules/nixos/services/matrix/bridges.nix @@ -0,0 +1,143 @@ +# Matrix bridges for some services I use +{ config, lib, ... }: +let + cfg = config.my.services.matrix.bridges; + synapseCfg = config.services.matrix-synapse; + + domain = config.networking.domain; + serverName = synapseCfg.settings.server_name; + + mkBridgeOption = n: lib.mkEnableOption "${n} bridge" // { default = cfg.enable; }; + mkPortOption = n: default: lib.mkOption { + type = lib.types.port; + inherit default; + example = 8080; + description = "${n} bridge port"; + }; + mkEnvironmentFileOption = n: lib.mkOption { + type = lib.types.str; + example = "/run/secret/matrix/${lib.toLower n}-bridge-secrets.env"; + description = '' + Path to a file which should contain the secret values for ${n} bridge. + + Using through the following format: + + ``` + MATRIX_APPSERVICE_AS_TOKEN= + MATRIX_APPSERVICE_HS_TOKEN= + ``` + + Each bridge should use a different set of secrets, as they each register + their own independent double-puppetting appservice. + ''; + }; +in +{ + options.my.services.matrix.bridges = with lib; { + enable = mkEnableOption "bridges configuration"; + + admin = mkOption { + type = types.str; + default = "ambroisie"; + example = "admin"; + description = "Local username for the admin"; + }; + + facebook = { + enable = mkBridgeOption "Facebook"; + + port = mkPortOption "Facebook" 29321; + + environmentFile = mkEnvironmentFileOption "Facebook"; + }; + }; + + config = lib.mkMerge [ + (lib.mkIf cfg.facebook.enable { + services.mautrix-meta.instances.facebook = { + enable = true; + # Automatically register the bridge with synapse + registerToSynapse = true; + + # Provide `AS_TOKEN`, `HS_TOKEN` + inherit (cfg.facebook) environmentFile; + + settings = { + homeserver = { + domain = serverName; + address = "http://localhost:${toString config.my.services.matrix.port}"; + }; + + appservice = { + hostname = "localhost"; + inherit (cfg.facebook) port; + address = "http://localhost:${toString cfg.facebook.port}"; + public_address = "https://facebook-bridge.${domain}"; + + as_token = "$MATRIX_APPSERVICE_AS_TOKEN"; + hs_token = "$MATRIX_APPSERVICE_HS_TOKEN"; + + bot = { + username = "fbbot"; + }; + }; + + backfill = { + enabled = true; + }; + + bridge = { + delivery_receipts = true; + permissions = { + "*" = "relay"; + ${serverName} = "user"; + "@${cfg.admin}:${serverName}" = "admin"; + }; + }; + + database = { + type = "postgres"; + uri = "postgres:///mautrix-meta-facebook?host=/var/run/postgresql/"; + }; + + double_puppet = { + secrets = { + ${serverName} = "as_token:$MATRIX_APPSERVICE_AS_TOKEN"; + }; + }; + + network = { + # Don't be picky on Facebook/Messenger + allow_messenger_com_on_fb = true; + displayname_template = ''{{or .DisplayName .Username "Unknown user"}} (FB)''; + }; + + provisioning = { + shared_secret = "disable"; + }; + }; + }; + + services.postgresql = { + enable = true; + ensureDatabases = [ "mautrix-meta-facebook" ]; + ensureUsers = [{ + name = "mautrix-meta-facebook"; + ensureDBOwnership = true; + }]; + }; + + systemd.services.mautrix-meta-facebook = { + wants = [ "postgres.service" ]; + after = [ "postgres.service" ]; + }; + + my.services.nginx.virtualHosts = { + # Proxy to the bridge + "facebook-bridge" = { + inherit (cfg.facebook) port; + }; + }; + }) + ]; +} diff --git a/modules/nixos/services/matrix/default.nix b/modules/nixos/services/matrix/default.nix index f423834..97dec2e 100644 --- a/modules/nixos/services/matrix/default.nix +++ b/modules/nixos/services/matrix/default.nix @@ -1,24 +1,49 @@ -# Matrix homeserver setup, using different endpoints for federation and client -# traffic. The main trick for this is defining two nginx servers endpoints for -# matrix.domain.com, each listening on different ports. -# -# Configuration shamelessly stolen from [1] -# -# [1]: https://github.com/alarsyo/nixos-config/blob/main/services/matrix.nix +# Matrix homeserver setup. { config, lib, pkgs, ... }: let cfg = config.my.services.matrix; - federationPort = { public = 8448; private = 11338; }; - clientPort = { public = 443; private = 11339; }; + adminPkg = pkgs.synapse-admin-etkecc; + domain = config.networking.domain; matrixDomain = "matrix.${domain}"; + + serverConfig = { + "m.server" = "${matrixDomain}:443"; + }; + clientConfig = { + "m.homeserver" = { + "base_url" = "https://${matrixDomain}"; + "server_name" = domain; + }; + "m.identity_server" = { + "base_url" = "https://vector.im"; + }; + }; + + # ACAO required to allow element-web on any URL to request this json file + mkWellKnown = data: '' + default_type application/json; + add_header Access-Control-Allow-Origin *; + return 200 '${builtins.toJSON data}'; + ''; in { + imports = [ + ./bridges.nix + ]; + options.my.services.matrix = with lib; { enable = mkEnableOption "Matrix Synapse"; + port = mkOption { + type = types.port; + default = 8448; + example = 8008; + description = "Internal port for listeners"; + }; + secretFile = mkOption { type = with types; nullOr str; default = null; @@ -58,22 +83,22 @@ in enable_registration = false; listeners = [ - # Federation { + inherit (cfg) port; bind_addresses = [ "::1" ]; - port = federationPort.private; - tls = false; # Terminated by nginx. + type = "http"; + tls = false; x_forwarded = true; - resources = [{ names = [ "federation" ]; compress = false; }]; - } - - # Client - { - bind_addresses = [ "::1" ]; - port = clientPort.private; - tls = false; # Terminated by nginx. - x_forwarded = true; - resources = [{ names = [ "client" ]; compress = false; }]; + resources = [ + { + names = [ "client" ]; + compress = true; + } + { + names = [ "federation" ]; + compress = false; + } + ]; } ]; @@ -96,19 +121,12 @@ in chat = { root = pkgs.element-web.override { conf = { - default_server_config = { - "m.homeserver" = { - "base_url" = "https://${matrixDomain}"; - "server_name" = domain; - }; - "m.identity_server" = { - "base_url" = "https://vector.im"; - }; - }; - showLabsSettings = true; - defaultCountryCode = "FR"; # cocorico - roomDirectory = { + default_server_config = clientConfig; + show_labs_settings = true; + default_country_code = "FR"; # cocorico + room_directory = { "servers" = [ + domain "matrix.org" "mozilla.org" ]; @@ -116,99 +134,54 @@ in }; }; }; - # Dummy VHosts for port collision detection - matrix-federation = { - port = federationPort.private; - }; - matrix-client = { - port = clientPort.private; + matrix = { + # Somewhat unused, but necessary for port collision detection + inherit (cfg) port; + + extraConfig = { + locations = { + # Or do a redirect instead of the 404, or whatever is appropriate + # for you. But do not put a Matrix Web client here! See the + # Element web section above. + "/".return = "404"; + + "/_matrix".proxyPass = "http://[::1]:${toString cfg.port}"; + "/_synapse".proxyPass = "http://[::1]:${toString cfg.port}"; + + "= /admin".return = "307 /admin/"; + "/admin/" = { + alias = "${adminPkg}/"; + priority = 500; + tryFiles = "$uri $uri/ /index.html"; + }; + "~ ^/admin/.*\\.(?:css|js|jpg|jpeg|gif|png|svg|ico|woff|woff2|ttf|eot|webp)$" = { + priority = 400; + root = adminPkg; + extraConfig = '' + rewrite ^/admin/(.*)$ /$1 break; + expires 30d; + more_set_headers "Cache-Control: public"; + ''; + }; + }; + }; }; }; - # Those are too complicated to use my wrapper... + # Setup well-known locations services.nginx.virtualHosts = { - ${matrixDomain} = { - onlySSL = true; - useACMEHost = domain; - - locations = - let - proxyToClientPort = { - proxyPass = "http://[::1]:${toString clientPort.private}"; - }; - in - { - # Or do a redirect instead of the 404, or whatever is appropriate - # for you. But do not put a Matrix Web client here! See the - # Element web section below. - "/".return = "404"; - - "/_matrix" = proxyToClientPort; - "/_synapse/client" = proxyToClientPort; - }; - - listen = [ - { addr = "0.0.0.0"; port = clientPort.public; ssl = true; } - { addr = "[::]"; port = clientPort.public; ssl = true; } - ]; - - }; - - # same as above, but listening on the federation port - "${matrixDomain}_federation" = { - onlySSL = true; - serverName = matrixDomain; - useACMEHost = domain; - - locations."/".return = "404"; - - locations."/_matrix" = { - proxyPass = "http://[::1]:${toString federationPort.private}"; - }; - - listen = [ - { addr = "0.0.0.0"; port = federationPort.public; ssl = true; } - { addr = "[::]"; port = federationPort.public; ssl = true; } - ]; - }; - "${domain}" = { forceSSL = true; useACMEHost = domain; - locations."= /.well-known/matrix/server".extraConfig = - let - server = { "m.server" = "${matrixDomain}:${toString federationPort.public}"; }; - in - '' - add_header Content-Type application/json; - return 200 '${builtins.toJSON server}'; - ''; - - locations."= /.well-known/matrix/client".extraConfig = - let - client = { - "m.homeserver" = { "base_url" = "https://${matrixDomain}"; }; - "m.identity_server" = { "base_url" = "https://vector.im"; }; - }; - # ACAO required to allow element-web on any URL to request this json file - in - '' - add_header Content-Type application/json; - add_header Access-Control-Allow-Origin *; - return 200 '${builtins.toJSON client}'; - ''; + locations."= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig; + locations."= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig; }; }; # For administration tools. environment.systemPackages = [ pkgs.matrix-synapse ]; - networking.firewall.allowedTCPPorts = [ - clientPort.public - federationPort.public - ]; - my.services.backup = { paths = [ config.services.matrix-synapse.dataDir diff --git a/modules/nixos/services/mealie/default.nix b/modules/nixos/services/mealie/default.nix index 664d5ba..8c02398 100644 --- a/modules/nixos/services/mealie/default.nix +++ b/modules/nixos/services/mealie/default.nix @@ -32,33 +32,14 @@ in BASE_URL = "https://mealie.${config.networking.domain}"; TZ = config.time.timeZone; ALLOw_SIGNUP = "false"; - - # Use PostgreSQL - DB_ENGINE = "postgres"; - # Make it work with socket auth - POSTGRES_URL_OVERRIDE = "postgresql://mealie:@/mealie?host=/run/postgresql"; }; - }; - systemd.services = { - mealie = { - after = [ "postgresql.service" ]; - requires = [ "postgresql.service" ]; + # Automatic PostgreSQL provisioning + database = { + createLocally = true; }; }; - # Set-up database - services.postgresql = { - enable = true; - ensureDatabases = [ "mealie" ]; - ensureUsers = [ - { - name = "mealie"; - ensureDBOwnership = true; - } - ]; - }; - my.services.nginx.virtualHosts = { mealie = { inherit (cfg) port; diff --git a/modules/nixos/services/nextcloud/default.nix b/modules/nixos/services/nextcloud/default.nix index cf1b876..d8d4fce 100644 --- a/modules/nixos/services/nextcloud/default.nix +++ b/modules/nixos/services/nextcloud/default.nix @@ -44,11 +44,15 @@ in adminuser = cfg.admin; adminpassFile = cfg.passwordFile; dbtype = "pgsql"; - dbhost = "/run/postgresql"; }; https = true; + # Automatic PostgreSQL provisioning + database = { + createLocally = true; + }; + settings = { overwriteprotocol = "https"; # Nginx only allows SSL }; @@ -60,22 +64,6 @@ in }; }; - services.postgresql = { - enable = true; - ensureDatabases = [ "nextcloud" ]; - ensureUsers = [ - { - name = "nextcloud"; - ensureDBOwnership = true; - } - ]; - }; - - systemd.services."nextcloud-setup" = { - requires = [ "postgresql.service" ]; - after = [ "postgresql.service" ]; - }; - # The service above configures the domain, no need for my wrapper services.nginx.virtualHosts."nextcloud.${config.networking.domain}" = { forceSSL = true; diff --git a/modules/nixos/services/paperless/default.nix b/modules/nixos/services/paperless/default.nix index 63f456b..1195977 100644 --- a/modules/nixos/services/paperless/default.nix +++ b/modules/nixos/services/paperless/default.nix @@ -52,30 +52,28 @@ in mediaDir = lib.mkIf (cfg.documentPath != null) cfg.documentPath; - settings = - let - paperlessDomain = "paperless.${config.networking.domain}"; - in - { - # Use SSO - PAPERLESS_ENABLE_HTTP_REMOTE_USER = true; - PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME = "HTTP_X_USER"; + settings = { + # Use SSO + PAPERLESS_ENABLE_HTTP_REMOTE_USER = true; + PAPERLESS_ENABLE_HTTP_REMOTE_USER_API = true; + PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME = "HTTP_X_USER"; - # Security settings - PAPERLESS_ALLOWED_HOSTS = paperlessDomain; - PAPERLESS_CORS_ALLOWED_HOSTS = "https://${paperlessDomain}"; + # Security settings + PAPERLESS_URL = "https://paperless.${config.networking.domain}"; + PAPERLESS_USE_X_FORWARD_HOST = true; + PAPERLESS_PROXY_SSL_HEADER = [ "HTTP_X_FORWARDED_PROTO" "https" ]; - # OCR settings - PAPERLESS_OCR_LANGUAGE = "fra+eng"; + # OCR settings + PAPERLESS_OCR_LANGUAGE = "fra+eng"; - # Workers - PAPERLESS_TASK_WORKERS = 3; - PAPERLESS_THREADS_PER_WORKER = 4; + # Workers + PAPERLESS_TASK_WORKERS = 3; + PAPERLESS_THREADS_PER_WORKER = 4; - # Misc - PAPERLESS_TIME_ZONE = config.time.timeZone; - PAPERLESS_ADMIN_USER = cfg.username; - }; + # Misc + PAPERLESS_TIME_ZONE = config.time.timeZone; + PAPERLESS_ADMIN_USER = cfg.username; + }; # Admin password passwordFile = cfg.passwordFile; diff --git a/modules/nixos/services/tandoor-recipes/default.nix b/modules/nixos/services/tandoor-recipes/default.nix index 3447bee..4b4ed1a 100644 --- a/modules/nixos/services/tandoor-recipes/default.nix +++ b/modules/nixos/services/tandoor-recipes/default.nix @@ -26,18 +26,16 @@ in services.tandoor-recipes = { enable = true; + database = { + createLocally = true; + }; + port = cfg.port; extraConfig = let tandoorRecipesDomain = "recipes.${config.networking.domain}"; in { - # Use PostgreSQL - DB_ENGINE = "django.db.backends.postgresql"; - POSTGRES_HOST = "/run/postgresql"; - POSTGRES_USER = "tandoor_recipes"; - POSTGRES_DB = "tandoor_recipes"; - # Security settings ALLOWED_HOSTS = tandoorRecipesDomain; CSRF_TRUSTED_ORIGINS = "https://${tandoorRecipesDomain}"; @@ -49,27 +47,12 @@ in systemd.services = { tandoor-recipes = { - after = [ "postgresql.service" ]; - requires = [ "postgresql.service" ]; - serviceConfig = { EnvironmentFile = cfg.secretKeyFile; }; }; }; - # Set-up database - services.postgresql = { - enable = true; - ensureDatabases = [ "tandoor_recipes" ]; - ensureUsers = [ - { - name = "tandoor_recipes"; - ensureDBOwnership = true; - } - ]; - }; - my.services.nginx.virtualHosts = { recipes = { inherit (cfg) port; diff --git a/modules/nixos/services/thelounge/default.nix b/modules/nixos/services/thelounge/default.nix new file mode 100644 index 0000000..e224839 --- /dev/null +++ b/modules/nixos/services/thelounge/default.nix @@ -0,0 +1,59 @@ +# Web IRC client +{ config, lib, ... }: +let + cfg = config.my.services.thelounge; +in +{ + options.my.services.thelounge = with lib; { + enable = mkEnableOption "The Lounge, a self-hosted web IRC client"; + + port = mkOption { + type = types.port; + default = 9050; + example = 4242; + description = "The port on which The Lounge will listen for incoming HTTP traffic."; + }; + }; + + config = lib.mkIf cfg.enable { + services.thelounge = { + enable = true; + inherit (cfg) port; + + extraConfig = { + reverseProxy = true; + }; + }; + + my.services.nginx.virtualHosts = { + irc = { + inherit (cfg) port; + # Proxy websockets for RPC + websocketsLocations = [ "/" ]; + + extraConfig = { + locations."/".extraConfig = '' + proxy_read_timeout 1d; + ''; + }; + }; + }; + + services.fail2ban.jails = { + thelounge = '' + enabled = true + filter = thelounge + port = http,https + ''; + }; + + environment.etc = { + "fail2ban/filter.d/thelounge.conf".text = '' + [Definition] + failregex = Authentication failed for user .* from $ + Authentication for non existing user attempted from $ + journalmatch = _SYSTEMD_UNIT=thelounge.service + ''; + }; + }; +} diff --git a/modules/nixos/services/transmission/default.nix b/modules/nixos/services/transmission/default.nix index 16d51e3..ddd77d4 100644 --- a/modules/nixos/services/transmission/default.nix +++ b/modules/nixos/services/transmission/default.nix @@ -47,6 +47,7 @@ in enable = true; package = pkgs.transmission_4; group = "media"; + webHome = pkgs.trgui-ng-web; downloadDirPermissions = "775"; diff --git a/modules/nixos/services/woodpecker/server/default.nix b/modules/nixos/services/woodpecker/server/default.nix index adf533e..caf0179 100644 --- a/modules/nixos/services/woodpecker/server/default.nix +++ b/modules/nixos/services/woodpecker/server/default.nix @@ -24,8 +24,8 @@ in }; systemd.services.woodpecker-server = { - after = [ "postgresql.service" ]; - requires = [ "postgresql.service" ]; + after = [ "postgresql.target" ]; + requires = [ "postgresql.target" ]; serviceConfig = { # Set username for DB access diff --git a/pkgs/comma/comma b/pkgs/comma/comma index 4367a26..b03a7f2 100755 --- a/pkgs/comma/comma +++ b/pkgs/comma/comma @@ -12,9 +12,9 @@ usage() { find_program() { local CANDIDATE - CANDIDATE="$(nix-locate --top-level --minimal --at-root --whole-name "/bin/$1")" + CANDIDATE="$(nix-locate --minimal --at-root --whole-name "/bin/$1")" if [ "$(printf '%s\n' "$CANDIDATE" | wc -l)" -gt 1 ]; then - CANDIDATE="$(printf '%s' "$CANDIDATE" | fzf-tmux)" + CANDIDATE="$(printf '%s' "$CANDIDATE" | "${COMMA_PICKER:-fzf-tmux}")" fi printf '%s' "$CANDIDATE" } diff --git a/pkgs/lohr/default.nix b/pkgs/lohr/default.nix index aeb13b1..d8545e0 100644 --- a/pkgs/lohr/default.nix +++ b/pkgs/lohr/default.nix @@ -10,7 +10,6 @@ rustPlatform.buildRustPackage rec { hash = "sha256-dunQgtap+XCK5LoSyOqIY/6p6HizBeiyPWNuCffwjDU="; }; - useFetchCargoVendor = true; cargoHash = "sha256-R3/N/43+bGx6acE/rhBcrk6kS5zQu8NJ1sVvKJJkK9w="; meta = with lib; {