From 2c90f034e7428761a666918702b5c1b0fcf25018 Mon Sep 17 00:00:00 2001 From: Anish L Date: Sun, 14 Nov 2021 03:47:38 +1000 Subject: [PATCH] some changes --- flake.nix | 2 +- hosts/curve/default.nix | 7 +- profiles/core/common.nix | 5 +- profiles/core/default.nix | 4 + profiles/desktop/default.nix | 6 + profiles/matrix/default.nix | 309 +++++++++++++++++++++++++++ profiles/mossnet-hosts/default.nix | 7 + secrets/fastmail.age | 9 + secrets/mossnet.age | 9 + secrets/secrets.nix | 7 +- users/profiles/cal/default.nix | 102 +++++++++ users/profiles/desktop/bin/passmenu | 68 ++++++ users/profiles/desktop/bin/powermenu | 31 +++ users/profiles/desktop/default.nix | 12 +- users/profiles/desktop/sxhkdrc | 7 +- users/profiles/email/default.nix | 280 ++++++++++++++++++++++++ 16 files changed, 854 insertions(+), 11 deletions(-) create mode 100644 profiles/matrix/default.nix create mode 100644 profiles/mossnet-hosts/default.nix create mode 100644 secrets/fastmail.age create mode 100644 secrets/mossnet.age create mode 100644 users/profiles/cal/default.nix create mode 100755 users/profiles/desktop/bin/passmenu create mode 100755 users/profiles/desktop/bin/powermenu create mode 100644 users/profiles/email/default.nix diff --git a/flake.nix b/flake.nix index f854a22a..ba0ef82b 100644 --- a/flake.nix +++ b/flake.nix @@ -142,7 +142,7 @@ importables = rec { profiles = digga.lib.rakeLeaves ./users/profiles; suites = with profiles; rec { - base = [ direnv git ]; + hmBase = [ direnv git ]; #gui = [ base profiles.firefox profiles.desktop ]; }; }; diff --git a/hosts/curve/default.nix b/hosts/curve/default.nix index f12fc668..89ec34d0 100644 --- a/hosts/curve/default.nix +++ b/hosts/curve/default.nix @@ -5,10 +5,13 @@ profiles.users.anish #profiles.users.profiles.firefox #profiles.users.profiles.desktop + profiles.users.profiles.email + profiles.users.profiles.cal + profiles.mossnet-hosts ] ++ suites.curve; - home-manager.users.anish = { suites, ... }: { - imports = suites.base; + home-manager.users.anish = { self, suites, ... }: { + imports = [ ] ++ suites.hmBase; }; #bud.enable = true; diff --git a/profiles/core/common.nix b/profiles/core/common.nix index a3c69b77..cb520006 100644 --- a/profiles/core/common.nix +++ b/profiles/core/common.nix @@ -101,7 +101,10 @@ }; # needed for vcv-rack - nixpkgs.config.allowUnfree = true; + #nixpkgs.config.allowUnfree = true; + programs.gnupg.agent.enable = true; + programs.gnupg.agent.pinentryFlavor = "curses"; + programs.gnupg.agent.enableSSHSupport = false; #system.copySystemConfiguration = true; #services.syncthing = { diff --git a/profiles/core/default.nix b/profiles/core/default.nix index 700af517..7ee941aa 100644 --- a/profiles/core/default.nix +++ b/profiles/core/default.nix @@ -186,6 +186,7 @@ in interactiveShellInit = '' eval "$(${pkgs.direnv}/bin/direnv hook bash)" ''; + enableCompletion = true; }; # For rage encryption, all hosts need a ssh key pair @@ -194,6 +195,9 @@ in openFirewall = lib.mkDefault false; }; + programs.gnupg.agent.enable = true; + programs.gnupg.agent.pinentryFlavor = "curses"; + services.earlyoom.enable = true; } diff --git a/profiles/desktop/default.nix b/profiles/desktop/default.nix index 25ff03e8..3b544d4c 100644 --- a/profiles/desktop/default.nix +++ b/profiles/desktop/default.nix @@ -2,6 +2,12 @@ { #imports = [ ./music.nix ] + environment.systemPackages = with pkgs; [ + nheko + newsflash + sublime-music + tdesktop + ]; # environment.systemPackages = with pkgs; [ # lightdm # dunst diff --git a/profiles/matrix/default.nix b/profiles/matrix/default.nix new file mode 100644 index 00000000..a3995a12 --- /dev/null +++ b/profiles/matrix/default.nix @@ -0,0 +1,309 @@ +{ + security.acme.email = "anish+acme@lakhwara.com"; + security.acme.acceptTerms = true; + services.matrix-synapse = { + enable = true; + app_service_config_files = [ + # # The registration file is automatically generated after starting the appservice for the first time. + # # cp /var/lib/matrix-appservice-discord/discord-registration.yaml /var/lib/matrix-synapse/ + # # chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/discord-registration.yaml + # "/var/lib/matrix-synapse/discord-registration.yaml" + # "/var/lib/matrix-synapse/telegram-registration.yaml" + # "/var/lib/matrix-synapse/slack-registration.yaml" + # # "/var/lib/matrix-synapse/whatsapp-registration.yaml" + ]; + server_name = "sealight.xyz"; + registration_shared_secret = "hD9HQGTTDxp0mQsQ5JDsfudWMDiubmZENOgPchIvfBvUlPxlvQSvjoO4wn2L1seU"; # TODO use agnix + enable_metrics = true; + enable_registration = true; + database_type = "psycopg2"; + database_args = { + database = "matrix-synapse"; + }; + extraConfig = '' + max_upload_size: "50M" + use_presence: false + ''; + ## coturn based TURN server integration (TURN server setup mentioned later), + ## shared secret generated while configuring coturn + ## and reused here (power of Nix being a real programming language) + turn_uris = [ + "turn:turn.sealight.xyz:3478?transport=udp" + "turn:turn.sealight.xyz:3478?transport=tcp" + ]; + turn_shared_secret = config.services.coturn.static-auth-secret; + + listeners = [ + { + port = 8448; + tls = false; + resources = [{ + compress = true; + names = ["client" "federation"]; + }]; + } + { + port = 9090; + type = "metrics"; + bind_address = "0.0.0.0"; + resources = [{ + compress = false; + names = []; + }]; + tls = false; + } + ]; + }; + + services.coturn = { + enable = true; + use-auth-secret = true; + static-auth-secret = "jXW1ohIq6wM3NB00xeME3uBihY85xjpkhGoyzBIdwhOpj7gjyxXZu1fwp1lUiYwJ"; + realm = "turn.sealight.xyz"; + no-tcp-relay = true; + no-tls = true; + no-dtls = true; + extraConfig = '' + user-quota=12 + total-quota=1200 + denied-peer-ip=10.0.0.0-10.255.255.255 + denied-peer-ip=192.168.0.0-192.168.255.255 + denied-peer-ip=172.16.0.0-172.31.255.255 + + allowed-peer-ip=192.168.191.127 + ''; + }; + + services.jitsi-meet = { + enable = true; + hostName = "jitsi.sealight.xyz"; + + ## this setting is going to add relevant ports to + ## networking.firewall.allowedTCPPorts & + ## networking.firewall.allowedUDPPorts + }; + services.jitsi-videobridge.enable = true; + + services.mautrix-telegram = { + enable = true; + environmentFile = /etc/secrets/telegram.env; # file containing the appservice and telegram tokens + # The appservice is pre-configured to use SQLite by default. It's also possible to use PostgreSQL. + settings = { + homeserver = { + address = "https://chat.sealight.xyz"; + domain = "sealight.xyz"; + }; + appservice = { + provisioning.enabled = false; + id = "telegram"; + public = { + enabled = false; + prefix = "/public"; + external = "https://chat.sealight.xyz/public"; + }; + # The service uses SQLite by default, but it's also possible to use PostgreSQL instead: + #database = "postgresql:///mautrix-telegram?host=/run/postgresql"; + }; + bridge = { + relaybot.authless_portals = false; + permissions = { + "@aynish:sealight.xyz" = "admin"; + }; + }; + }; + }; + + services.mautrix-whatsapp = { + enable = true; + # The appservice is pre-configured to use SQLite by default. It's also possible to use PostgreSQL. + configOptions = { + homeserver = { + address = "https://chat.sealight.xyz"; + domain = "sealight.xyz"; + }; + appservice = { + id = "whatsapp"; + address = http://localhost:9897; + hostname = "0.0.0.0"; + port = 9897; + database = { + type = "sqlite3"; + uri = "/var/lib/mautrix-whatsapp/mautrix-whatsapp.db"; + }; + state_store_path = "/var/lib/mautrix-whatsapp/mx-state.json"; + bot = { + username = "whatsappbot"; + displayname = "WhatsApp bridge bot"; + avatar = "mxc://maunium.net/NeXNQarUbrlYBiPCpprYsRqr"; + }; + as_token = ""; + hs_token = ""; + }; + bridge = { + username_template = "whatsapp_{{.}}"; + displayname_template = "{{if .Notify}}{{.Notify}}{{else}}{{.Jid}}{{end}} (WA)"; + command_prefix = "!wa"; + permissions = { + "@aynish:sealight.xyz" = 100; + }; + }; + logging = { + directory = "/var/lib/mautrix-whatsapp/logs"; + file_name_format = "{{.Date}}-{{.Index}}.log"; + file_date_format = "\"2006-01-02\""; + file_mode = 384; + timestamp_format = "Jan _2, 2006 15:04:05"; + print_level = "debug"; + }; + metrics = { + enabled = true; + listen = "http://localhost:5070"; + }; + }; + }; + + services.matrix-appservice-slack = { + enable = true; + #environmentFile = /etc/secrets/matrix-appservice-slack.env; + settings = { + homeserver = { + server_name = "sealight.xyz"; + url = "https://chat.sealight.xyz"; + }; + db = { + engine = "postgres"; + connectionString = "postgres://slackbridge_user:somethingverysecret@localhost/slack_bridge?sslmode=require"; + }; + matrix_admin_room = "!ikEWOHCcmoZtVzSmPF:sealight.xyz"; + username_prefix = "slack_"; + rtm = { + enable = true; + logging = "silent"; + }; + slack_hook_port = 9899; + enable_metrics = true; + puppeting = { + enabled = true; + onboard_users = true; + }; + oauth2 = { + client_id = "2832868673.1609454840563"; + client_secret = "079a7ca42b192e66a9ff32740a69cb9d"; + redirect_prefix = "https://sealight.xyz/slackbridge/"; + }; + #team_sync = { + # T02QGRJKT = { + # users = { + # enabled = false; + # }; + # channels = { + # enabled = true; + # alias_prefix = "qf_"; + # }; + # }; + #}; + }; + }; + + services.postgresql = { + enable = true; + ## postgresql user and db name remains in the + ## service.matrix-synapse.database_args setting which + ## by default is matrix-synapse + initialScript = pkgs.writeText "synapse-init.sql" '' + CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD "Da0?H*9i{x?,]|'kq@iBwlIzu"; + CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" + TEMPLATE template0 + LC_COLLATE = "C" + LC_CTYPE = "C"; + ''; + }; + + networking.firewall = { + enable = true; + allowedTCPPorts = [ + 22 # SSH + 8448 # Matrix federation + 8008 + 80 + 443 + 9090 # Synapse Metrics + 9899 # Matrix <-> Slack Bridge Puppeting + ]; + }; + + nixpkgs.overlays = [ + (self: super: { + element-web = super.element-web.override { + conf = { + default_server_config = { + "m.homeserver" = { + "base_url" = "https://chat.sealight.xyz"; + "server_name" = "sealight.xyz"; + }; + "m.identity_server" = { + "base_url" = "https://vector.im"; + }; + }; + + ## jitsi will be setup later, + ## but we need to add to Riot configuration + jitsi.preferredDomain = "jitsi.sealight.xyz"; + }; + }; + }) + ]; + + services.nginx = { + enable = true; + virtualHosts = { + + "sealight.xyz" = { + forceSSL = true; + enableACME = true; + locations."/" = { + root = "/var/www/sealight.xyz"; + }; + locations."/_matrix" = { + proxyPass = "http://localhost:8448"; + }; + locations."/slackbridge" = { + proxyPass = "http://localhost:9899"; + }; + }; + + ## virtual host for Synapse + "chat.sealight.xyz" = { + forceSSL = true; + enableACME = true; + #useACMEHost = "sealight.xyz"; + locations."/" = { + proxyPass = "http://localhost:8448"; + }; + }; + + ## virtual host for Riot/Web + "element.sealight.xyz" = { + forceSSL = true; + enableACME = true; + #useACMEHost = "sealight.xyz"; + + ## root points to the riot-web package content, also configured via Nix + locations."/" = { + root = pkgs.element-web; + }; + }; + + ${config.services.jitsi-meet.hostName} = { + enableACME = true; + forceSSL = true; + }; + }; + ## other nginx specific best practices + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedTlsSettings = true; + }; + + environment.systemPackages = with pkgs; [ matrix-appservice-slack ]; +} diff --git a/profiles/mossnet-hosts/default.nix b/profiles/mossnet-hosts/default.nix new file mode 100644 index 00000000..2fdaf767 --- /dev/null +++ b/profiles/mossnet-hosts/default.nix @@ -0,0 +1,7 @@ +{ + networking.extraHosts = '' + 172.16.11.240 mossnet.lan + 172.16.11.240 links.mossnet.lan + 172.16.11.240 read.mossnet.lan + ''; +} diff --git a/secrets/fastmail.age b/secrets/fastmail.age new file mode 100644 index 00000000..d65baa50 --- /dev/null +++ b/secrets/fastmail.age @@ -0,0 +1,9 @@ +age-encryption.org/v1 +-> ssh-ed25519 E8y8hg wa7dEOcDQKqi3zTAkZQy4/dYZZ0oUVX8v5WeSpxs/A4 +nznzTXatP4LCEAFgJR66rCjEzOV7ifRttTGZmmP9c2w +-> ssh-ed25519 AiezdQ dznLcf8z/LGX5GmAkgEtAMePomkelBGJn6Xda2qWGgQ +dce7/xpxFvpbynT5THAnLrdGoKCsiPHMf4pb87rv4DM +-> JCA\o-grease =d\4" +xjWZZedUIwPV8E0tPMlUz9XRm+BxsT+dYdf2Zw +--- blJDPOKPAxBqYQN3WHiF/KGW9sNCPpckWY2hEmf8p4c +-ōݕ!++:궾hAx= $ͅRpVN \ No newline at end of file diff --git a/secrets/mossnet.age b/secrets/mossnet.age new file mode 100644 index 00000000..d2ac8f74 --- /dev/null +++ b/secrets/mossnet.age @@ -0,0 +1,9 @@ +age-encryption.org/v1 +-> ssh-ed25519 E8y8hg zUl7tdxWGLDPiv9cX9/vTITX+H+rqgVSZ77YFZUQzBQ +ZW9d2bKCo969jT1HWKw8tPSlYJpjm8T7mbcztPVWdyA +-> ssh-ed25519 AiezdQ Gb5IB4nHlyBsjIgt52/BL7lcWZFEWly26HND0I/Q824 +VyTx5jzEhsekC87qejQsfJGcHNlt0VghloDT+AVo9rQ +-> Nbgn:*-grease +5IfKwbqa8Yrv5zz2Vcy98A +--- D26v86VajBn6V2Go1nnNdBBwe7K+rLiVw5MVvAob/dk +ҍ@=s`62ZނO:ռ30rSo=] \ No newline at end of file diff --git a/secrets/secrets.nix b/secrets/secrets.nix index bac30e03..2e285dd5 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -1,9 +1,10 @@ let # set ssh public keys here for your system and user - system = ""; - user = ""; + user = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIItTdCyYVur6LzRQf08JZUcEAr23H7fTRRmDJOzoOc6A anish@curve"; + system = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIMPcqWQ/L5nLTsBFHArl3AJb9xynhfsKenb5h0NNuMV root@curve"; allKeys = [ system user ]; in { - "secret.age".publicKeys = allKeys; + "fastmail.age".publicKeys = allKeys; + "mossnet.age".publicKeys = allKeys; } diff --git a/users/profiles/cal/default.nix b/users/profiles/cal/default.nix new file mode 100644 index 00000000..910d5a03 --- /dev/null +++ b/users/profiles/cal/default.nix @@ -0,0 +1,102 @@ +{pkgs, config, ...}: + +{ + age.secrets.mossnet.file = "/etc/nixos/secrets/mossnet.age"; + age.secrets.mossnet.owner = "anish"; + home-manager.users.anish = { + home.packages = with pkgs; [ + khal + khard + vdirsyncer + ]; + + xdg.configFile = { + "vdirsyncer/config".text = '' + [general] + status_path = "/home/anish/.config/vdirsyncer/status/" + + [pair contacts] + a = "contacts_local" + b = "contacts_remote" + collections = ["from a", "from b"] + metadata = ["displayname"] + + [storage contacts_local] + type = "filesystem" + path = "~/.contacts/" + fileext = ".vcf" + + [storage contacts_remote] + type = "carddav" + url = "http://mossnet.lan/remote.php/dav/files/anish/" + username = "anish" + password.fetch = ["command", "cat", "/run/secrets/mossnet"] + + [pair calendar] + a = "calendar_local" + b = "calendar_remote" + collections = ["from a", "from b"] + metadata = ["displayname"] + + [storage calendar_local] + type = "filesystem" + path = "~/.calendar/" + fileext = ".ics" + + [storage calendar_remote] + type = "caldav" + url = "http://mossnet.lan/remote.php/dav/files/anish/" + username = "anish" + password.fetch = ["command", "cat", "/run/secrets/mossnet"] + ''; + + "khal/config".text = '' + [calendars] + + [[calendar_local]] + path = ~/.calendar/* + type = discover + + [[contacts_local]] + path = ~/.contacts/* + type = birthdays + + [locale] + timeformat = %H:%M + dateformat = %Y-%m-%d + longdateformat = %Y-%m-%d + datetimeformat = %Y-%m-%d %H:%M + longdatetimeformat = %Y-%m-%d %H:%M + ''; + + "khard/khard.conf".text = '' + [addressbooks] + [[personal]] + path = ~/.contacts/* + + [general] + debug = no + default_action = list + editor = nvim, -i, NONE + merge_editor = nvim, -d + + [contact table] + display = first_name + group_by_addressbook = no + reverse = no + show_nicknames = yes + show_uids = no + sort = last_name + localize_dates = yes + preferred_phone_number_type = pref, cell, home + preferred_email_address_type = pref, home, work + + [vcard] + private_objects = Jabber, + preferred_version = 3.0 + search_in_source_files = no + skip_unparsable = no + ''; + }; + }; +} diff --git a/users/profiles/desktop/bin/passmenu b/users/profiles/desktop/bin/passmenu new file mode 100755 index 00000000..bdca124e --- /dev/null +++ b/users/profiles/desktop/bin/passmenu @@ -0,0 +1,68 @@ +#!/usr/bin/env bash + +# Prompts for a pass entry, then for a specific field. Similar to passmenu, but +# uses rofi, and can resume from a previous session. +# +# Example: passmenu [RESUME] + +ROFI_CMD='rofi -dmenu -theme theme/passmenu.rasi' +MSG_CMD='notify-send' +set -e +shopt -s nullglob globstar + +for prog in xclip pass; do + if ! command -v "$prog" >/dev/null; then + >&2 echo "$prog not installed, aborting" + exit 1 + fi +done + +if [[ $1 == -r ]]; then + resume=1; shift +fi + +url= +# Get qutebrowser's current url +win=$(xdotool getactivewindow) +if [[ -n $win ]]; then + winname=$(xdotool getwindowname $win) + if [[ $winname =~ " - Mozilla Firefox$" ]]; then + url=${winname% - Mozilla*} + url=${url##* - } + while (( ${#url//[^.]/} > 1 )); do + url=${url#*.} + done + fi +fi + +LAST_ENTRY_FILE=/tmp/_upm +if [[ -n $resume && -f $LAST_ENTRY_FILE ]]; then + entry="$(<$LAST_ENTRY_FILE)" +else + prefix=${PASSWORD_STORE_DIR-~/.password-store} + password_files=( "$prefix"/**/*.gpg ) + password_files=( "${password_files[@]#"$prefix"/}" ) + password_files=( "${password_files[@]%.gpg}" ) + entry=$(printf "%s\n" "${password_files[@]}" | $ROFI_CMD -p "..." -filter "$url") +fi + +if [[ -z $entry ]]; then + $MSG_CMD "Error!" "Failed to select $entry" + exit 1 +fi + +echo "$entry" >/tmp/_upm +secrets="$(pass show "$entry")" +if [[ -n $secrets ]]; then + fields=$(awk -F': ' 'NR>1 && !/^otpauth:/ {print $1}' <<<"$secrets") + field=$(printf "password\n%s\notp\n" "${fields[@]}" | $ROFI_CMD -p "$entry") + case $field in + password) pass -c "$entry" ;; + otp) printf "%s" "$(pass otp -c "$entry")" ;; + *) printf "%s" "$(awk -v "key=$field:" '$1 == key {print $2}' <<<"$secrets")" | xclip -selection clipboard -in ;; + esac + $MSG_CMD "Success!" "Copied $entry/$field to clipboard for 45s" +else + $MSG_CMD "Error!" "Failed to retrieve $entry" + exit 2 +fi diff --git a/users/profiles/desktop/bin/powermenu b/users/profiles/desktop/bin/powermenu new file mode 100755 index 00000000..daeb1dc7 --- /dev/null +++ b/users/profiles/desktop/bin/powermenu @@ -0,0 +1,31 @@ +#!/usr/bin/env sh + +rofi_command="rofi -theme theme/powermenu.rasi" + +### Options ### +power_off="\tShutdown" +reboot="\tReboot" +lock="\tLock" +suspend="鈴\tSleep" +log_out="\tLogout" +# Variable passed to rofi +options="$power_off\n$reboot\n$lock\n$suspend\n$log_out" + +case "$(echo -e "$options" | $rofi_command -dmenu -selected-row 2)" in + $power_off) + systemctl poweroff + ;; + $reboot) + systemctl reboot + ;; + $lock) + zzz + ;; + $suspend) + dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Pause + systemctl suspend + ;; + $log_out) + bspc quit + ;; +esac diff --git a/users/profiles/desktop/default.nix b/users/profiles/desktop/default.nix index c511d133..55f825aa 100644 --- a/users/profiles/desktop/default.nix +++ b/users/profiles/desktop/default.nix @@ -1,9 +1,10 @@ -{pkgs, ...}: +{pkgs, config, ...}: { #imports = [ ./xdg.nix ]; home-manager.users.anish.xdg.enable = true; # This doesn't seem to do anything so we have below + home-manager.users.anish.xdg.configHome = "/home/anish/.config"; # TODO bad hard coded environment.sessionVariables = rec { XDG_CACHE_HOME = "\${HOME}/.cache"; XDG_CONFIG_HOME = "\${HOME}/.config"; @@ -15,7 +16,12 @@ ]; }; environment.systemPackages = with pkgs; [ - nheko # TODO move somewhere meaningful + # TODO move somewhere meaningful + tdesktop # TODO get rid of this once bridged on sealight + sublime-music + nheko + newsflash + zeal xclip xdotool rofi @@ -182,6 +188,8 @@ gtk-icon-theme-name=Paper gtk-font-name="Sans 10" ''; + "$XDG_BIN_HOME/passmenu".source = ./bin/passmenu; + "$XDG_BIN_HOME/powermenu".source = ./bin/powermenu; }; diff --git a/users/profiles/desktop/sxhkdrc b/users/profiles/desktop/sxhkdrc index 7661a254..e38e5603 100644 --- a/users/profiles/desktop/sxhkdrc +++ b/users/profiles/desktop/sxhkdrc @@ -38,10 +38,13 @@ super + Tab rofi -show window -show-icons -theme theme/windowmenu.rasi super + p - $DOTFILES_BIN/rofi/passmenu + passmenu super + slash - $DOTFILES_BIN/rofi/filemenu -x + filemenu -x + +super + s + powermenu super + Escape pkill -USR1 -x sxhkd diff --git a/users/profiles/email/default.nix b/users/profiles/email/default.nix new file mode 100644 index 00000000..5f60dcf9 --- /dev/null +++ b/users/profiles/email/default.nix @@ -0,0 +1,280 @@ +{pkgs, ... }: + +{ + age.secrets.fastmail.file = "/etc/nixos/secrets/fastmail.age"; + age.secrets.fastmail.owner = "anish"; + home-manager.users.anish = { + services.mbsync = { + enable = true; + frequency = "*:0/30"; + postExec = "${pkgs.notmuch}/bin/notmuch index"; + }; + programs.mbsync.enable = true; + programs.msmtp.enable = true; + programs.notmuch = { + enable = true; + hooks = { + preNew = "mbsync --all"; + }; + }; + programs.neomutt = { + enable = true; + extraConfig = '' + # Shamelessly Stolen from https://gideonwolfe.com/posts/workflow/neomutt/intro/ + # set editor to neovim + set editor = "nvim" + # Folder with emails + set folder = "~/Mail/anish" + # Type of mailbox + set mbox_type = Maildir + # Directory to poll for new mail + set spoolfile = +Inbox + # Directory to save sent messages into + set record = +Sent + # Sets the drafts folder + set postponed = +Drafts + # File that headers will be cached + # set header_cache = ~/.cache/mutt + + set my_name = "Anish" + set imap_check_subscribed + + # Set preffered view modes + auto_view text/html text/calendar application/ics # view html automatically + # alternative_order text/html text/plain text/enriched text/* + + # main options + set envelope_from + set edit_headers # show headers when composing + set fast_reply # skip to compose when replying + set askcc # ask for CC: + set fcc_attach # save attachments with the body + set forward_format = "Fwd: %s" # format of subject when forwarding + set forward_decode # decode when forwarding + set attribution = "On %d, %n wrote:" # format of quoting header + set reply_to # reply to Reply to: field + set reverse_name # reply as whomever it was to + set include # include message in replies + set forward_quote # include message in forwards + set text_flowed + unset sig_dashes # no dashes before sig + unset mime_forward # forward attachments as part of body + unset help # No help bar at the top of index + # set status_on_top # Status bar on top of index + set tmpdir = ~/Programs/neomutt/temp # where to keep temp files + + unset confirmappend # don't ask, just do! + set quit # don't ask, just do!! + unset mark_old # read/new is good enough for me + #set beep_new # bell on new mails + set pipe_decode # strip headers and eval mimes when piping + set thorough_search # strip headers and eval mimes before searching + set timeout = 0 + + # status bar, date format, finding stuff etc. + set status_chars = " *%A" + set status_format = "[ Folder: %f ] [%r%m messages%?n? (%n new)?%?d? (%d to delete)?%?t? (%t tagged)? ]%>─%?p?( %p postponed )?" + set date_format = "%d.%m.%Y %H:%M" + set sort = threads + set sort_aux = reverse-last-date-received + set uncollapse_jump + set sort_re + set reply_regexp = "^(([Rr][Ee]?(\[[0-9]+\])?: *)?(\[[^]]+\] *)?)*" + set quote_regexp = "^( {0,4}[>|:#%]| {0,4}[a-z0-9]+[>|]+)+" + set send_charset = "utf-8:iso-8859-1:us-ascii" + set charset = "utf-8" + set arrow_cursor = "no" # Change `color indicator` depending + + # Pager View Options + set pager_index_lines = 10 # Shows 10 lines of index when pager is active + set pager_context = 3 + set pager_stop + set menu_scroll + set tilde + unset markers + + #set mailcap_path = ~/.config/neomutt/mailcap + #set header_cache = "~/.cache/mutt" + #set message_cachedir = "~/.cache/mutt" + + set query_command = "khard email --parsable --search-in-source-files '%s'" + + ### Color Settings + # Header colors: + color header blue default ".*" + color header brightmagenta default "^(From)" + color header brightcyan default "^(Subject)" + color header brightwhite default "^(CC|BCC)" + + mono bold bold + mono underline underline + mono indicator reverse + mono error bold + color normal default default + color indicator brightyellow default # currently selected message. default makes bar clear, disabled arrow to save space. + color sidebar_highlight red default + color sidebar_divider brightblack black + color sidebar_flagged red black + color sidebar_new green black + color normal brightyellow default + color error red default + color tilde black default + color message cyan default + color markers red white + color attachment white default + color search brightmagenta default + color status brightyellow black + color hdrdefault brightgreen default + color quoted green default + color quoted1 blue default + color quoted2 cyan default + color quoted3 yellow default + color quoted4 red default + color quoted5 brightred default + color signature brightgreen default + color bold black default + color underline black default + color normal default default + + color body brightred default "[\-\.+_a-zA-Z0-9]+@[\-\.a-zA-Z0-9]+" # Email addresses + color body brightblue default "(https?|ftp)://[\-\.,/%~_:?&=\#a-zA-Z0-9]+" # URL + color body green default "\`[^\`]*\`" # Green text between ` and ` + color body brightblue default "^# \.*" # Headings as bold blue + color body brightcyan default "^## \.*" # Subheadings as bold cyan + color body brightgreen default "^### \.*" # Subsubheadings as bold green + color body yellow default "^(\t| )*(-|\\*) \.*" # List items as yellow + color body brightcyan default "[;:][-o][)/(|]" # emoticons + color body brightcyan default "[;:][)(|]" # emoticons + color body brightcyan default "[ ][*][^*]*[*][ ]?" # more emoticon? + color body brightcyan default "[ ]?[*][^*]*[*][ ]" # more emoticon? + color body red default "(BAD signature)" + color body cyan default "(Good signature)" + color body brightblack default "^gpg: Good signature .*" + color body brightyellow default "^gpg: " + color body brightyellow red "^gpg: BAD signature from.*" + mono body bold "^gpg: Good signature" + mono body bold "^gpg: BAD signature from.*" + color body red default "([a-z][a-z0-9+-]*://(((([a-z0-9_.!~*'();:&=+$,-]|%[0-9a-f][0-9a-f])*@)?((([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?|[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+)(:[0-9]+)?)|([a-z0-9_.!~*'()$,;:@&=+-]|%[0-9a-f][0-9a-f])+)(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*(/([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*(;([a-z0-9_.!~*'():@&=+$,-]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?(#([a-z0-9_.!~*'();/?:@&=+$,-]|%[0-9a-f][0-9a-f])*)?|(www|ftp)\\.(([a-z0-9]([a-z0-9-]*[a-z0-9])?)\\.)*([a-z]([a-z0-9-]*[a-z0-9])?)\\.?(:[0-9]+)?(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*(/([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*(;([-a-z0-9_.!~*'():@&=+$,]|%[0-9a-f][0-9a-f])*)*)*)?(\\?([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?(#([-a-z0-9_.!~*'();/?:@&=+$,]|%[0-9a-f][0-9a-f])*)?)[^].,:;!)? \t\r\n<>\"]" + + # Default index colors: + color index yellow default '.*' + color index_author red default '.*' + color index_number blue default + color index_subject cyan default '.*' + + # For new mail: + color index brightyellow black "~N" + color index_author brightred black "~N" + color index_subject brightcyan black "~N" + + color progress black cyan + + ### Mappings Settings + + # General rebindings + bind attach view-mailcap + bind attach l view-mailcap + bind editor noop + bind pager c imap-fetch-mail + bind index G last-entry + bind index g noop + bind index gg first-entry + bind pager,attach h exit + bind pager j next-line + bind pager k previous-line + bind pager l view-attachments + bind index D delete-message + bind index U undelete-message + bind index L limit + bind index h noop + bind index l display-message + bind browser h goto-parent + bind browser l select-entry + bind pager,browser gg top-page + bind pager,browser G bottom-page + bind index,pager,browser d half-down + bind index,pager,browser u half-up + bind index,pager R group-reply + bind index \031 previous-undeleted # Mouse wheel + bind index \005 next-undeleted # Mouse wheel + bind pager \031 previous-line # Mouse wheel + bind pager \005 next-line # Mouse wheel + bind editor complete-query + + + # sidebar mappings + bind index,pager \Ck sidebar-prev + bind index,pager \Cj sidebar-next + bind index,pager \Co sidebar-open + bind index,pager \Cp sidebar-prev-new + bind index,pager \Cn sidebar-next-new + bind index,pager B sidebar-toggle-visible + + # global index and pager shortcuts + bind index,pager @ compose-to-sender + bind index,pager D purge-message + bind index sync-mailbox + bind index collapse-thread + + # Email completion bindings + bind editor complete-query + bind editor ^T complete + + # Press A to add contact to Khard address book + macro index,pager A \ + "khard add-email" \ + "add the sender email address to khard" + ''; + }; + services.imapnotify.enable = true; + home.packages = [ pkgs.neomutt pkgs.evolution ]; + + accounts.email = { + accounts.anish = { + primary = true; + address = "anish@lakhwara.com"; + #alias = [ "*@lakhwara.com" ]; + #gpg = { + # key = ""; + # signByDefault = true; + #}; + imap.host = "imap.fastmail.com"; + mbsync = { + enable = true; + create = "both"; + expunge = "both"; + remove = "both"; + extraConfig.local.subFolders = "Verbatim"; + }; + imapnotify = { + enable = true; + boxes = [ "Inbox" ]; + onNotify = "${pkgs.isync}/bin/mbsync anish && ${pkgs.notmuch}/bin/notmuch index"; + onNotifyPost = { + mail = "${pkgs.libnotify}/bin/notify-send -a mail 'email: new in %s'"; + update = "${pkgs.libnotify}/bin/notify-send -a mail 'email: update %s'"; + expunge = "${pkgs.libnotify}/bin/notify-send -a mail 'email: expunge %s'"; + }; + }; + msmtp.enable = true; + notmuch.enable = true; + realName = "Anish Lakhwara"; + signature = { + text = '' + Thanks, + Anish + ''; + showSignature = "append"; + }; + passwordCommand = "cat /run/secrets/fastmail"; + smtp = { + host = "fastmail.com"; + }; + userName = "anish@lakhwara.com"; + neomutt = { + enable = true; + }; + }; + }; + }; +}