From 5f271a7194fed58f89443ce2331adf2f3e5e6707 Mon Sep 17 00:00:00 2001 From: Konstantin Nazarov Date: Sun, 30 Jul 2023 17:18:49 +0100 Subject: [PATCH] Initial release of my NixOS configuration --- .sops.yaml | 20 + README.md | 19 + configuration.nix | 572 ++++++++++++ emacs.el | 929 +++++++++++++++++++ flake.lock | 220 +++++ flake.nix | 67 ++ gpg_public_key.asc | 109 +++ nodes/framework/configuration.nix | 22 + nodes/framework/hardware-configuration.nix | 44 + nodes/framework/host-metadata.nix | 4 + nodes/knazarovcom/configuration.nix | 117 +++ nodes/knazarovcom/hardware-configuration.nix | 32 + nodes/knazarovcom/host-metadata.nix | 4 + nodes/knazarovcom/secrets.yaml | 44 + nodes/mira/configuration.nix | 22 + nodes/mira/hardware-configuration.nix | 50 + nodes/mira/host-metadata.nix | 4 + secrets.yaml | 53 ++ switch.sh | 9 + wallpaper.jpg | Bin 0 -> 124499 bytes 20 files changed, 2341 insertions(+) create mode 100644 .sops.yaml create mode 100644 README.md create mode 100644 configuration.nix create mode 100755 emacs.el create mode 100755 flake.lock create mode 100755 flake.nix create mode 100644 gpg_public_key.asc create mode 100644 nodes/framework/configuration.nix create mode 100755 nodes/framework/hardware-configuration.nix create mode 100644 nodes/framework/host-metadata.nix create mode 100644 nodes/knazarovcom/configuration.nix create mode 100644 nodes/knazarovcom/hardware-configuration.nix create mode 100644 nodes/knazarovcom/host-metadata.nix create mode 100644 nodes/knazarovcom/secrets.yaml create mode 100644 nodes/mira/configuration.nix create mode 100644 nodes/mira/hardware-configuration.nix create mode 100644 nodes/mira/host-metadata.nix create mode 100644 secrets.yaml create mode 100755 switch.sh create mode 100755 wallpaper.jpg diff --git a/.sops.yaml b/.sops.yaml new file mode 100644 index 0000000..317e71d --- /dev/null +++ b/.sops.yaml @@ -0,0 +1,20 @@ +keys: + - &admin_knazarov DDB4423999505236CF585F9B0560020C9C577C1B + - &server_mira age1le98v5v0xnlnc4y0ydgj9kwfftt8g5wduws8zsadgc97pj0fzecs55tjvz + - &server_framework age1rkmhgep2jhdnma24x7ufzr686cwq6p3nk7mmedykan0d7c36xaus2y58sw + - &server_knazarovcom age1esdg28lplhhvrj6vmqu9x0adyxj5trp2dp7my3k57kjhkstkk9cqkg5qkj +creation_rules: + - path_regex: secrets\.yaml$ + key_groups: + - pgp: + - *admin_knazarov + age: + - *server_mira + - *server_framework + + - path_regex: secrets-knazarovcom\.yaml$ + key_groups: + - pgp: + - *admin_knazarov + age: + - *server_knazarovcom diff --git a/README.md b/README.md new file mode 100644 index 0000000..034444e --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# My NixOS configuration + +This configuration is used to provision both of my "desktop" machines, and a personal website. + +Most important features this configuration provides: + +- PGP, commit signing, U2F +- Secret management with [SOPS](https://github.com/getsops/sops) +- Email / mbsync configuration +- VPN with [Mullvad](https://mullvad.net) + +# Updating machine configuration + +There are solutions that allow to push configuration to remote hosts, but I find them a bit heavy, +so a simple shell script does the trick for me: + +``` +./switch.sh +``` diff --git a/configuration.nix b/configuration.nix new file mode 100644 index 0000000..cb62f2d --- /dev/null +++ b/configuration.nix @@ -0,0 +1,572 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running ‘nixos-help’). + +{ config, lib, nixpkgs, pkgs, home-manager, ... }: + +let + +in +{ + imports = + [ + #./gnupg.nix + ]; + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + nix.extraOptions = '' + !include ${config.sops.secrets.github_token.path} + bash-prompt = (nix:$name)\040\[\033[1;32m\][\u@\h:\w]\$\[\033[0m\]\040 + ''; + + sops = { + environment.SOPS_GPG_EXEC = "${pkgs.gnupg}/bin/gpg"; + defaultSopsFile = ./secrets.yaml; + secrets = { + fastmail_password = { + owner = config.users.users.knazarov.name; + group = config.users.users.knazarov.group; + }; + github_token = { + owner = config.users.users.knazarov.name; + group = config.users.users.knazarov.group; + }; + mullvad_account = {}; + }; + }; + + # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. + + # Configure network proxy if necessary + # networking.proxy.default = "http://user:password@proxy:port/"; + # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; + + # Enable networking + networking.networkmanager.enable = true; + + # Set your time zone. + time.timeZone = "Europe/London"; + + # Select internationalisation properties. + i18n.defaultLocale = "en_US.UTF-8"; + + i18n.extraLocaleSettings = { + LC_ADDRESS = "en_US.UTF-8"; + LC_IDENTIFICATION = "en_US.UTF-8"; + LC_MEASUREMENT = "en_US.UTF-8"; + LC_MONETARY = "en_US.UTF-8"; + LC_NAME = "en_US.UTF-8"; + LC_NUMERIC = "en_US.UTF-8"; + LC_PAPER = "en_US.UTF-8"; + LC_TELEPHONE = "en_US.UTF-8"; + LC_TIME = "en_US.UTF-8"; + }; + + # Mainly to access SMB shares on local network + services.gvfs = { + enable = true; + package = lib.mkForce pkgs.gnome3.gvfs; + }; + + + # Configure keymap in X11 + services.xserver = { + layout = "us"; + xkbVariant = ""; + }; + + # Define a user account. Don't forget to set a password with ‘passwd’. + users.users.knazarov = { + isNormalUser = true; + description = "Konstantin Nazarov"; + extraGroups = [ + "networkmanager" + "wheel" + config.users.groups.keys.name + ]; + packages = with pkgs; []; + openssh.authorizedKeys.keys = [ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDGxebDydOcs7URJjXFHMU++ruaZOJpXbK4ixH19pWTsX7WtxxriZxD4+RQ3oyllGG/8sEFzEe0NoTHUPU6YrBpfwT/ekGDmCJHtvZ+rZs+cRQd6tObfAUip1B1Mcvhuaj0prnrbfohOuHpvQ/L8TogIKuHgczDmud4KGUu0mxCsUHbD5tlKpsgN+dJXkvjxsO7JhhF9JpFTrYAU0gTuBPTt3ynpnZKrE1NgnE0iy+CEr/v41dLqxw3fUjT3nOFUQ1l/VKTw5mLt5Iw7XmBLuFGLRAVrwzXxeBCfYqKGYgY4QV8HCcVpcqC8zWmRskiRetzQ/5HwRagm4yZr0I+LZ305nGB0cSJzLWXXOUF6SDg2cqAXFpF/o2LoFCmaV5h3jmCGOUrowF7oV4mYwBMWfabrbZx21z/R56GkAOOEKc2h+Qh5wIj4yayX081SkqJK3J9+3vGG4VvXnwGnPnWQFqrzeedyV74maffGBGFYm0UOcD+oG6EwM+7MEUBpJm9m4c= knazarov" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHkDvP2BO1uV0AwEjABYFEiA2BbGo1IsSht4emYMRLgi root@mira" + ]; + }; + + nixpkgs.config.allowUnfree = true; + + environment.systemPackages = with pkgs; [ + # needed to request polkit access (for instance, for SMB shares) + lxqt.lxqt-policykit + vim + waybar + foot + wayland + xdg-utils + glib + dracula-theme + gnome3.adwaita-icon-theme + swaylock + swayidle + wl-clipboard + qutebrowser + keyd + tdesktop + git + source-code-pro + pavucontrol + brightnessctl + sops + age + ssh-to-age + syncthing + pass + pkgs.gnupg + pciutils + slack + q-sh + transmission-gtk + mpv + imv + okular + yt-dlp + evince # document viewer + firefox + gthumb + unzip + somafm-cli + yubikey-manager + yubikey-manager-qt + gnome.gedit # temporary + ripgrep + file + zoom-us + obs-studio + gnome.nautilus + xfce.thunar + zig + morph + gomuks + nheko + mullvad-vpn + mullvad + clang-tools # mainly for clang-format + (emacsWithPackagesFromUsePackage { + config = ./emacs.el; + defaultInitFile = true; + package = emacs-unstable-pgtk.overrideAttrs (old: { + withTreeSitter = true; + }); + alwaysEnsure = true; + extraEmacsPackages = epkgs: [ + pkgs.mu + epkgs.treesit-grammars.with-all-grammars + ]; + }) + # wget + ]; + + services.mullvad-vpn = { + enable = true; + }; + systemd.services."mullvad-daemon".postStart = let + mullvad = config.services.mullvad-vpn.package; + in '' + while ! ${mullvad}/bin/mullvad status >/dev/null; do sleep 1; done + ${mullvad}/bin/mullvad account login `cat /var/run/secrets/mullvad_account` + ${mullvad}/bin/mullvad auto-connect set on + ${mullvad}/bin/mullvad tunnel ipv6 set on + ''; + + services.gnome.gnome-keyring.enable = true; + services.emacs.package = nixpkgs.emacsUnstablePgtk; + + # Enables wayland support in electron apps (e.g. slack) + environment.sessionVariables.NIXOS_OZONE_WL = "1"; + + # Set default browser to qutebrowser in electron apps + environment.sessionVariables.DEFAULT_BROWSER = "${pkgs.qutebrowser}/bin/qutebrowser"; + + # Set default browser to qutebrowser everywhere else + xdg.mime.defaultApplications = { + "text/html" = "org.qutebrowser.qutebrowser.desktop"; + "x-scheme-handler/http" = "org.qutebrowser.qutebrowser.desktop"; + "x-scheme-handler/https" = "org.qutebrowser.qutebrowser.desktop"; + "x-scheme-handler/about" = "org.qutebrowser.qutebrowser.desktop"; + "x-scheme-handler/unknown" = "org.qutebrowser.qutebrowser.desktop"; + }; + + # Enable screen sharing on Wayland + xdg = { + portal = { + enable = true; + extraPortals = with pkgs; [ + xdg-desktop-portal-wlr + xdg-desktop-portal-gtk + ]; + }; + }; + + + + + # Some programs need SUID wrappers, can be configured further or are + # started in user sessions. + # programs.mtr.enable = true; + programs.gnupg.package = pkgs.gnupg; + programs.gnupg.agent = { + enable = true; + enableSSHSupport = true; + }; + + programs.sway = { + enable = true; + wrapperFeatures.gtk = true; + }; + + # List services that you want to enable: + + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + }; + services.dbus.enable = true; + + services.greetd = { + enable = true; + settings = rec { + initial_session = { + command = "${pkgs.sway}/bin/sway"; + user = "knazarov"; + }; + default_session = initial_session; + }; + }; + + services.keyd = { + enable = true; + keyboards = { + default = { + ids = [ "*" ]; + settings = { + main = { + capslock = "overload(control, esc)"; + leftalt = "layer(meta_mac)"; + leftmeta = "layer(alt)"; + }; + "meta_mac:M" = { + c = "C-insert"; + v = "S-insert"; + }; + }; + }; + }; + }; + + # Enable the OpenSSH daemon. + services.openssh = { + enable = true; +# settings = { +# passwordAuthentication = false; +# kbdInteractiveAuthentication = false; +# }; + }; + + networking.firewall.allowedTCPPorts = [ + # Syncthing + 8384 22000 + ]; + + networking.firewall.allowedUDPPorts = [ + # Syncthing + 22000 21027 + ]; + + # This value determines the NixOS release from which the default + # settings for stateful data, like file locations and database versions + # on your system were taken. It‘s perfectly fine and recommended to leave + # this value at the release version of the first install of this system. + # Before changing this value read the documentation for this option + # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). + system.stateVersion = "23.05"; # Did you read the comment? + + # needed for sway + security.polkit.enable = true; + # needed for pipewire + security.rtkit.enable = true; + + # allow remote rebuilds + nix.settings.trusted-users = [ "@wheel" ]; + + # needed for YubiKey smartcard support + services.pcscd.enable = true; + + fonts.fontDir.enable = true; + fonts.packages = with pkgs; [ + dejavu_fonts + source-code-pro + font-awesome # for waybar indicators + ]; + + + home-manager.users.knazarov = { + /* The home.stateVersion option does not have a default and must be set */ + home.stateVersion = "23.05"; + + programs.bash = { + enable = true; + bashrcExtra = '' + if [[ "$INSIDE_EMACS" = 'vterm' ]] \ + && [[ -n ''${EMACS_VTERM_PATH} ]] \ + && [[ -f ''${EMACS_VTERM_PATH}/etc/emacs-vterm-bash.sh ]]; then + source ''${EMACS_VTERM_PATH}/etc/emacs-vterm-bash.sh + fi + ''; + }; + + programs.direnv = { + enable = true; + nix-direnv = { + enable = true; + }; + }; + + programs.gpg = { + enable = true; + package = pkgs.gnupg; + publicKeys = [{source = ./gpg_public_key.asc; trust="ultimate"; }]; + settings = { + default-key = "0x0560020C9C577C1B"; + }; + mutableKeys = false; + mutableTrust = false; + }; + + programs.git = { + enable = true; + userName = "Konstantin Nazarov"; + userEmail = "mail@knazarov.com"; + signing = { + gpgPath = "${pkgs.gnupg}/bin/gpg2"; + key = "0x0560020C9C577C1B"; + signByDefault = true; + }; + }; + + accounts.email = { + maildirBasePath = "${config.users.users.knazarov.home}/Maildir"; + accounts = { + personal = let account = "mail@knazarov.com"; in { + primary = true; + flavor = "fastmail.com"; + address = account; + userName = account; + realName = "Konstantin Nazarov"; + passwordCommand = "cat /run/secrets/fastmail_password"; + gpg = { + key = "0x0560020C9C577C1B"; + signByDefault = true; + }; + mu.enable = true; + msmtp.enable = true; + mbsync = { + enable = true; + # Folders existing on the server, but not locally, will be created. + create = "maildir"; + + }; + }; + }; + }; + + programs.mu = { + enable = true; + }; + programs.msmtp.enable = true; + + programs.mbsync = { + enable = true; + }; + + #services.easyeffects = { + # enable = true; + #}; + + services.swayidle = { + enable = true; + timeouts = [ + { timeout = 300; command = "${pkgs.swaylock}/bin/swaylock -f -c 000000";} + { timeout = 600; + command = "${pkgs.sway}/bin/swaymsg \"output * dpms off\""; + resumeCommand = "${pkgs.sway}/bin/swaymsg \"output * dpms on\"";} + ]; + events = [ + { event = "before-sleep"; command = "${pkgs.swaylock}/bin/swaylock -f -c 000000"; } + ]; + }; + + wayland.windowManager.sway = { + enable = true; + xwayland = true; + config = rec { + modifier = "Mod4"; + terminal = "foot"; + bars = [{ + "command" = "waybar"; + }]; + keybindings = pkgs.lib.mkOptionDefault { + "XF86AudioRaiseVolume" = "exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"; + "XF86AudioLowerVolume" = "exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"; + "XF86AudioMute" = "exec wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; + "XF86AudioMicMute" = "exec pactl set-source-mute @DEFAULT_SOURCE@ toggle"; + "XF86MonBrightnessUp" = "exec brightnessctl s +5%"; + "XF86MonBrightnessDown" = "exec brightnessctl s 5%-"; + "Mod4+Return" = "exec emacs --eval '(progn (setq confirm-kill-processes nil) (vterm))'"; + "Mod4+space" = "exec ${pkgs.foot}/bin/foot -T mylauncher -a mylauncher ${pkgs.q-sh}/bin/q"; + "Mod4+p" = "exec '${pkgs.grim}/bin/grim -g \"$$(${pkgs.slurp}/bin/slurp)\" - | ${pkgs.wl-clipboard}/bin/wl-copy -t image/png'"; + }; + output = { + "*" = { bg = "${./wallpaper.jpg} fill";}; + "Lenovo Group Limited LEN T32p-20 VNA4VRNY" = { scale = "1.5"; }; + }; + input = { + "type:keyboard" = { + xkb_layout = "us,ru"; + xkb_options = "grp:alt_space_toggle"; + }; + }; + gaps = { + inner = 10; + outer = 5; + }; + colors.unfocused = {border = "#dddddd"; + background = "#dddddd"; + text = "#888888"; + indicator = "#888888"; + childBorder = "#888888";}; + }; + extraConfig = '' + for_window [title="mylauncher"] floating enable + default_border pixel 3 + ''; + }; + programs.foot = { + enable = true; + settings = { + main = { + font="monospace:size=10"; + }; + + colors = { + background="feffff"; + foreground="333333"; + + regular0="333333"; + regular1="bd4436"; + regular2="008700"; + regular3="cdcc42"; + regular4="0017f5"; + regular5="b92cc6"; + regular6="5bbdf9"; + regular7="c7c7c7"; + + bright0="333333"; + bright1="bd4436"; + bright2="008700"; + bright3="cdcc42"; + bright4="0017f5"; + bright5="b92cc6"; + bright6="5bbdf9"; + bright7="feffff"; + }; + key-bindings = { + clipboard-copy="Control+Insert"; + clipboard-paste="Shift+Insert"; + primary-paste="Control+Shift+v"; + }; + }; + }; + programs.qutebrowser = { + enable = true; + searchEngines = { + DEFAULT = "https://kagi.com/search?q={}"; + g = "https://www.google.com/search?hl=en&q={}"; + }; + #config.set('content.media.video_capture', True, 'https://www.meet.google.com') + settings = { + tabs.position = "left"; + content.cookies.accept = "no-3rdparty"; + }; + extraConfig = '' + config.set('content.javascript.can_access_clipboard', True, 'amazon.com') + config.set('content.javascript.can_access_clipboard', True, 'awsapps.com') + config.set('content.media.audio_capture', True, 'https://meet.google.com') + config.set('content.media.video_capture', True, 'https://meet.google.com') + config.set('content.media.audio_video_capture', True, 'https://meet.google.com') + config.set('content.notifications.enabled', False, 'https://meet.google.com') + config.set('content.register_protocol_handler', False, 'https://calendar.google.com?cid=%25s') + ''; + keyBindings = { + insert = { + "" = "insert-text -- {clipboard}"; + }; + }; + }; + programs.waybar = { + enable = true; + settings = [{ + layer = "top"; + position = "top"; + height = 24; + modules-left = ["sway/workspaces" "sway/mode"]; + modules-center = ["sway/window"]; + modules-right = + [ "idle_inhibitor" "battery" "clock" "tray" ]; + clock.format = "{:%Y-%m-%d %H:%M}"; + battery = { + states = { + # good = 95; + warning = 30; + critical = 15; + }; + format = "{capacity}% {icon}"; + format-charging = "{capacity}% "; + format-plugged = "{capacity}% "; + format-alt = "{time} {icon}"; + format-icons = ["" "" "" "" ""]; + }; + idle_inhibitor = { + format = "{icon}"; + format-icons = { + activated = ""; + deactivated = ""; + }; + }; + }]; + }; + services.syncthing = { + enable = true; + }; + home.pointerCursor = { + name = "Adwaita"; + package = pkgs.gnome.adwaita-icon-theme; + size = 24; + x11 = { + enable = true; + defaultCursor = "Adwaita"; + }; + }; + }; + + virtualisation = { + podman = { + enable = true; + dockerCompat = true; + defaultNetwork.settings = { + dns_enabled = true; + }; + }; + }; + services.udev.packages = [ + pkgs.android-udev-rules + ]; +} diff --git a/emacs.el b/emacs.el new file mode 100755 index 0000000..a7ca60c --- /dev/null +++ b/emacs.el @@ -0,0 +1,929 @@ +;; -------- Speed up load time ------- + +;; I don't use emacs-server, so startup times are very important to me. + +;; Garbage collection is triggered very often during start up, and it +;; slows the whole thing down. It is safe to increase threshold +;; temporarily to prevent aggressive GC, and then re-enable it at the +;; end. + +(setq gc-cons-threshold 402653184 + gc-cons-percentage 0.6) + + +;; There are special ways to handle files (via SSH or in archives), +;; but this is not necessary during startup, and it also slows down +;; the load significantly, as emacs is going through lots of files. +(defvar saved--file-name-handler-alist file-name-handler-alist) +(setq file-name-handler-alist nil) + +;; Restore defaults after initialization has completed +(add-hook 'after-init-hook #'(lambda () + (setq gc-cons-threshold 16777216 + gc-cons-percentage 0.1) + (setq file-name-handler-alist saved--file-name-handler-alist))) + +;; -------- Default directories -------- + +(setq default-directory "~/") +(setq command-line-default-directory "~/") + +;; -------- State files -------- + +;; By default emacs leaves lots of trash around your filesystem while +;; you are editing. This section cleans up the basics. + +;; Don't leave =yourfile~= temporary files nearby, and put them to a +;; separate directory instead. + +(setq backup-directory-alist '(("." . "~/.emacs.d/backups"))) +(setq auto-save-file-name-transforms + '((".*" "~/.emacs.d/backups" t))) + +;; -------- Command history -------- + +;; Save command history so that when emacs is restarted, the history +;; is preserved. + +(setq savehist-file "~/.emacs.d/savehist") +(savehist-mode +1) +(setq savehist-save-minibuffer-history +1) +(setq savehist-additional-variables + '(kill-ring + search-ring + regexp-search-ring)) + +;; -------- Recent files -------- + +;; Recent files are convenient to record because you can use them to +;; quickly jump to what you've been editing recently. + +(setq recentf-save-file "~/.emacs.d/recentf" + recentf-max-menu-items 0 + recentf-max-saved-items 300 + recentf-filename-handlers '(file-truename) + recentf-exclude + (list "^/tmp/" "^/ssh:" "\\.?ido\\.last$" "\\.revive$" "/TAGS$" + "^/var/folders/.+$" + )) + +(recentf-mode 1) + +;; -------- De-clutter -------- + +;; Toolbar and scrollbars are only useful to novices. The same for +;; startup screen and menu bar. + +(tool-bar-mode -1) +(scroll-bar-mode -1) +(setq inhibit-startup-screen t) + +(if (not (eq window-system 'mac)) + (menu-bar-mode -1)) + +;; More reliable inter-window border +;; The native border "consumes" a pixel of the fringe on righter-most splits, +;; ~window-divider~ does not. Available since Emacs 25.1. + +(setq-default window-divider-default-places t + window-divider-default-bottom-width 0 + window-divider-default-right-width 1) +(window-divider-mode +1) + +;; Remove continuation arrow on right fringe + +(setq fringe-indicator-alist (delq (assq 'continuation fringe-indicator-alist) + fringe-indicator-alist)) + +;; No more typing the whole yes or no. Just y or n will do. +(fset 'yes-or-no-p 'y-or-n-p) + +;; Makes *scratch* empty. +(setq initial-scratch-message "") + +;; Hide modeline in the vterm mode +(use-package hide-mode-line) +(add-hook 'vterm-mode-hook #'hide-mode-line-mode) + +;; -------- Cursor and movement -------- + +;; On emacs mac port use Alt as meta key + +(if (eq window-system 'mac) + (progn + (setq mac-option-modifier 'meta) + (setq mac-command-modifier nil) + (setq mac-pass-command-to-system 't))) + +;; Blinking cursor is inconvenient + +(blink-cursor-mode -1) + +;; Disable bell ring when moving outside of available area + +(setq ring-bell-function 'ignore) + +;; Disable annoying blink-matching-paren + +(setq blink-matching-paren nil) + +;; -------- Window decoration -------- + +;; This makes the header transparent on Emacs 26.1+ under OS X + +(add-to-list 'default-frame-alist '(ns-transparent-titlebar . t)) +(add-to-list 'default-frame-alist '(ns-appearance . dark)) +(setq ns-use-proxy-icon nil) + +;; -------- Minor modes -------- + +;; Hide some miror modes from sight to not clutter the modeline + +(use-package diminish) +(require 'diminish) + +(diminish 'company-mode) +(diminish 'projectile-mode) +(diminish 'editorconfig-mode) +(diminish 'eldoc-mode) +(diminish 'flycheck-mode) +(diminish 'which-key-mode) + +;; -------- Theme -------- + +;; - I don't like that fringes are visible, so I set them to regular +;; background color +;; - Panels look better without outset/inset shadows + +(use-package modus-themes) +(load-theme 'modus-operandi t) + +(set-face-attribute 'fringe nil + :foreground (face-foreground 'default) + :background (face-background 'default)) + +;; On many OSs the modeline has an outset border (lighter on top and +;; darker on the bottom). This doesn't look pretty on a flat theme. + +(set-face-attribute 'mode-line nil :box nil) +(set-face-attribute 'mode-line-inactive nil :box nil) + +;; -------- Font -------- + +;; Some time ago I've purchased a great font called Pragmata Pro, +;; which is easy on the eyes and tailored for programmers. It may +;; not be available everywhere though, hence conditional load. + +(when window-system + (if (not (null (x-list-fonts "PragmataPro"))) + (add-to-list 'default-frame-alist + '(font . "PragmataPro-15")) + (add-to-list 'default-frame-alist + '(font . "Source Code Pro-11")) + )) + + +;; -------- Packages -------- + +(diminish 'company-mode) +(diminish 'projectile-mode) +(diminish 'editorconfig-mode) +(diminish 'eldoc-mode) +(diminish 'flycheck-mode) +(diminish 'which-key-mode) + +;; -------- Navigation -------- + +;; Quickly find my way around emacs + +;; Default scheme for uniquifying buffer names is not convenient. +;; It's better to have a regular path-like structure. + +;;(require 'uniquify) +(setq uniquify-buffer-name-style 'forward) +(setq uniquify-separator "/") +(setq uniquify-after-kill-buffer-p t) ; rename after killing uniquified +(setq uniquify-ignore-buffers-re "^\\*") ; don't muck with special buffers + + +;; If you stop after typing a part of keybinding, shows available +;; options in minibuffer. + + +(use-package which-key) +(add-hook 'after-init-hook 'which-key-mode) +(with-eval-after-load 'which-key + (which-key-setup-side-window-bottom)) + +;; persp-mode allows you to have tagged workspaces akin to +;; Linux tiled-window managers. + +(use-package persp-mode) +;; persp-mode clashes with corfu +(setq persp-auto-resume-time 0) +(add-hook 'after-init-hook 'persp-mode) +(global-set-key (kbd "C-x x s") 'persp-switch) + +;; vertico-mode allows for easy navigation between buffers and files + +(use-package vertico) +(add-hook 'after-init-hook 'vertico-mode) +(setq completion-ignore-case t) +(setq completion-styles '(basic substring partial-completion flex)) + +(use-package marginalia) +(add-hook 'after-init-hook 'marginalia-mode) + +;; ripgrep search with consult + +(use-package consult) +(global-set-key (kbd "M-s r") 'consult-ripgrep) + +;; Navigation when in russian layout + +(cl-loop + for from across "йцукенгшщзхъфывапролджэячсмитьбюЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖ\ЭЯЧСМИТЬБЮ№" + for to across "qwertyuiop[]asdfghjkl;'zxcvbnm,.QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>#" + do + (eval `(define-key key-translation-map (kbd ,(concat "C-" (string from))) (kbd ,(concat "C-" (string to))))) + (eval `(define-key key-translation-map (kbd ,(concat "M-" (string from))) (kbd ,(concat "M-" (string to)))))) + + +;; -------- Editor basics -------- + +;; Use 4 spaces to indent by default + +(setq-default indent-tabs-mode nil) +(setq-default tab-width 4) + +;; Clean up trailing whitespace on file save + +(add-hook 'before-save-hook 'whitespace-cleanup) + +;; But use editorconfig to guess proper project-wide indentation rules + +(use-package editorconfig) +(add-hook 'prog-mode-hook #'editorconfig-mode) + + +;; Speed up comint buffers by disabling bidirectional language support + +(setq-default bidi-display-reordering nil) + +;; -------- Tools and environment -------- + +;; By default, Emacs doesn't add system path to its search places + +(use-package exec-path-from-shell) +(require 'exec-path-from-shell) +(setenv "PATH" (concat "/usr/local/bin:" (getenv "PATH"))) + +;; On a mac, this will set up PATH and MANPATH from your environment +(when (memq window-system '(mac ns x pgtk)) + (exec-path-from-shell-initialize)) + +;; -------- Org roam -------- + +(use-package org) +(use-package org-contrib) +(use-package org-roam) +(use-package consult-org-roam) + +(setq org-roam-completion-everywhere t) +(setq org-roam-directory "~/notes") +(setq org-roam-node-default-sort 'file-mtime) +(setq consult-org-roam-grep-func #'consult-ripgrep) + +(global-set-key (kbd "C-c n l") 'org-roam-buffer-toggle) +(global-set-key (kbd "C-c n i") 'org-roam-node-insert) +(global-set-key (kbd "C-c n f") 'org-roam-node-find) +(global-set-key (kbd "C-c n r") 'consult-org-roam-search) + +(autoload 'org-roam-buffer-toggle "org-roam" "\ +Enable org-roam +" t nil) +(autoload 'org-roam-setup "org-roam" "\ +Enable org-roam +" t nil) + +(setq org-roam-capture-templates + `(("d" "default" plain "%?" + :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" + "#+title: ${title}\n") + :unnarrowed t) + ("i" "interview" plain "%?" + :target (file+head "%<%Y%m%d%H%M%S>-${slug}.org" + ,(concat "#+title: ${title}\n" + "#+filetags: Interview\n" + "\n")) + :unnarrowed t) + + )) + +(setq org-roam-node-display-template + (concat "${title:80} " (propertize "${tags:20}" 'face 'org-tag)) + org-roam-node-annotation-function + (lambda (node) (marginalia--time (org-roam-node-file-mtime node)))) + +(add-hook 'after-init-hook 'org-roam-setup) + +(defun roam-extra:get-filetags () + (split-string (or (org-roam-get-keyword "filetags") ""))) + +(defun roam-extra:add-filetag (tag) + (let* ((new-tags (cons tag (roam-extra:get-filetags))) + (new-tags-str (combine-and-quote-strings new-tags))) + (org-roam-set-keyword "filetags" new-tags-str))) + +(defun roam-extra:del-filetag (tag) + (let* ((new-tags (seq-difference (roam-extra:get-filetags) `(,tag))) + (new-tags-str (combine-and-quote-strings new-tags))) + (org-roam-set-keyword "filetags" new-tags-str))) + +(defun roam-extra:todo-p () + "Return non-nil if current buffer has any TODO entry. + + TODO entries marked as done are ignored, meaning the this + function returns nil if current buffer contains only completed + tasks." + (org-element-map + (org-element-parse-buffer 'headline) + 'headline + (lambda (h) + (eq (org-element-property :todo-type h) + 'todo)) + nil 'first-match)) + +(defun roam-extra:update-todo-tag () + "Update TODO tag in the current buffer." + (when (and (not (active-minibuffer-window)) + (org-roam-file-p)) + (org-with-point-at 1 + (let* ((tags (roam-extra:get-filetags)) + (is-todo (roam-extra:todo-p))) + (cond ((and is-todo (not (seq-contains-p tags "todo"))) + (roam-extra:add-filetag "todo")) + ((and (not is-todo) (seq-contains-p tags "todo")) + (roam-extra:del-filetag "todo"))))))) + +(defun roam-extra:todo-files () + "Return a list of roam files containing todo tag." + (org-roam-db-sync) + (let ((todo-nodes (seq-filter (lambda (n) + (seq-contains-p (org-roam-node-tags n) "todo")) + (org-roam-node-list)))) + (seq-uniq (seq-map #'org-roam-node-file todo-nodes)))) + +(defun roam-extra:update-todo-files (&rest _) + "Update the value of `org-agenda-files'." + (setq org-agenda-files (roam-extra:todo-files))) + +(add-hook 'find-file-hook #'roam-extra:update-todo-tag) +(add-hook 'before-save-hook #'roam-extra:update-todo-tag) +(advice-add 'org-agenda :before #'roam-extra:update-todo-files) + + +(defun org-roam-week (&optional other-window) + "Opens or creates a weekly note." + (interactive) + (let* ((title (format-time-string "Week %U %Y")) + (nodes (org-roam-node-list)) + (node (seq-find (lambda (n) (string-equal (org-roam-node-title n) title)) nodes))) + (if (and node (org-roam-node-file node)) + (org-roam-node-visit node other-window) + (org-roam-capture- + :node (org-roam-node-create :title title) + :templates + `(("w" "week" plain "* Goals\n\n%?\n\n* Tasks\n\n" + :if-new (file+head "%<%Y%m%d%H%M%S>-${slug}.org" "#+title: ${title}\n#+category: ${title}\n#+filetags: Week") + :unnarrowed t)) + :props '(:finalize find-file)) + ) + ) + ) + +(global-set-key (kbd "C-c n w") 'org-roam-week) + +;; -------- Org mode --------- + +(use-package org-modern) +(with-eval-after-load 'org (global-org-modern-mode)) + +(setq org-modules '(org-w3m org-bbdb org-bibtex org-docview + org-gnus org-info org-irc org-mhe + org-rmail org-checklist org-mu4e)) + +;; Sometimes I sit at night until 4 AM, and I still want org to treat it +;; as "today" +(setq org-extend-today-until 4) + +;; navigate with (org-goto) by offering the full list of targets in ido-mode +(setq org-goto-interface 'outline-path-completion) ;; don't search incrementally +(setq org-outline-path-complete-in-steps nil) ;; see whole path at once + +;; avoid inadvertently editing hidden text +(setq org-catch-invisible-edits 'show-and-error) + +;; hide empty spaces between folded subtrees +(setq org-cycle-separator-lines 0) + +;; use hours in clocktable instead of days and hours +(setq org-time-clocksum-format "%d:%02d") + +;; After a recurring task is marked as done, reset it to TODO. This +;; is important because I have the "INBOX" state first in the sequence +;; of states. +(setq org-todo-repeat-to-state "TODO") + +;; Default format for column view +(setq org-columns-default-format "%38ITEM(Details) %TAGS(Context) %7TODO(To Do) %5Effort(Time){:} %6CLOCKSUM(Total){:}") + +;; Better source code editing + +(setq org-src-fontify-natively t + org-src-window-setup 'current-window + org-src-strip-leading-and-trailing-blank-lines t + org-src-preserve-indentation t + org-src-tab-acts-natively t) + +;; Default tags +(setq org-tag-alist '((:startgroup . nil) + ("WORK" . ?w) ("HOME" . ?h) + (:endgroup . nil) + ("PROJECT" . ?p) + ("PHONE" . ?n) + ("MEETING" . ?m) + ("DOC" . ?d) + ("GOOGLE" . ?g) + ("QUICK" . ?q))) + +;; Default todo sequence +(setq org-todo-keywords + '((sequence "INBOX(i)" "TODO(t)" "ERRAND(k)" + "SOMEDAY(s)" "WAITING(w@/!)" "APPT(a)" "|" + "DONE(d!)" "CANCELLED(c!)"))) + +;; Babel and code block embedding +(setq org-confirm-babel-evaluate nil) +(org-babel-do-load-languages + 'org-babel-load-languages + '((emacs-lisp . t) + (python . t))) + +;; Log TODO state changes and clock-ins into the LOGBOOK drawer +(setq org-clock-into-drawer t) +(setq org-log-into-drawer t) + +;; Quickly creating new tasks +(global-set-key (kbd "\C-c r") 'org-capture) +(setq org-capture-templates + `(("t" "Todo" entry (file+headline "~/org/gtd.org" "Tasks") + "* TODO %?\n %U\n %a") + ("i" "Inbox" entry (file+headline "~/org/gtd.org" "Tasks") + "* INBOX %?\n %U") + ("f" "Follow-up" entry (file+headline "~/org/gtd.org" "Tasks") + ,(concat "* TODO %? :EMAIL:\n" + " %U\n" + " %a")) + ("c" "Contacts" entry (file "~/org/contacts.org") + (concat "* %(org-contacts-template-name)\n" + ":PROPERTIES:\n" + ":EMAIL: %(org-contacts-template-email)\n" + ":END:")) + + ("q" + "Org capture template" + entry + (file+headline "~/org/capture.org" "Notes") + "* %:description\n\n Source: %u, %:link\n\n %i" + :empty-lines 1) + ) + ) +;; org-protocol allows you to capture stuff into your system from web +;; browsers +(require 'org-protocol) + +;; Refiling allows you to quickly move an element with its children to +;; another location. + +;; By default, refile works up to 2-level sections, which is not very +;; convenient if you have project-based organization +;; (/Projects/ProjectName). +(setq org-refile-targets '((org-agenda-files :maxlevel . 3))) + +;; Then, it's nice to have a full path to the target element appear in +;; completion +(setq org-refile-use-outline-path 'file) + +;; But, when using helm, we also need to tell org mode to present the +;; whole list of possible completions right away, and not use +;; incremental search: +(setq org-outline-path-complete-in-steps nil) + +;; It may also be useful to be able to create elements, if the refile +;; target doesn't already exist. +(setq org-refile-allow-creating-parent-nodes 'confirm) + +;; Agenda +(global-set-key "\C-ca" 'org-agenda) +(setq org-agenda-files '("~/org/gtd.org" + "~/org/weeklyreview.org" + )) + +(setq org-agenda-custom-commands nil) +(add-to-list 'org-agenda-custom-commands + '("h" "Work todos" tags-todo + "-personal-doat={.+}-dowith={.+}/!-ERRAND" + ((org-agenda-todo-ignore-scheduled t)))) +(add-to-list 'org-agenda-custom-commands + '("H" "All work todos" tags-todo "-personal/!-ERRAND-MAYBE" + ((org-agenda-todo-ignore-scheduled nil)))) +(add-to-list 'org-agenda-custom-commands + '("A" "Work todos with doat or dowith" tags-todo + "-personal+doat={.+}|dowith={.+}/!-ERRAND" + ((org-agenda-todo-ignore-scheduled nil)))) +(add-to-list 'org-agenda-custom-commands + '("P" "Projects" + tags "+PROJECT-TODO=\"SOMEDAY\"")) + +(add-to-list 'org-agenda-custom-commands + '("i" "Inbox" + todo "INBOX")) + +(add-to-list 'org-agenda-custom-commands + '("o" "Someday" + todo "SOMEDAY")) + +(add-to-list 'org-agenda-custom-commands + '("c" "Simple agenda view" + ( + (agenda "" + ) + (todo "" + ( + (org-agenda-overriding-header "\nUnscheduled TODO") + (org-agenda-skip-function '(org-agenda-skip-entry-if + 'timestamp 'todo '("SOMEDAY" "ERRAND"))) + (org-agenda-sorting-strategy + (quote ((agenda time-up priority-down tag-up)))) + )) + ) + ((org-agenda-overriding-columns-format + "%38ITEM(Details) %TAGS(Context) %7TODO(To Do) %5Effort(Time){:} %6CLOCKSUM_T(Total){:}") + (org-agenda-view-columns-initially t)) + ) + ) + +(setq org-todo-keyword-faces + '(("ERRAND" . (:foreground "light sea green" :weight bold)) + ("INBOX" . (:foreground "DarkGoldenrod" :weight bold)))) + +;;(set-face-foreground 'org-scheduled-previously "DarkGoldenrod") + +(setq org-tags-exclude-from-inheritance '("PROJECT") + org-stuck-projects '("+PROJECT/-MAYBE-DONE-SOMEDAY" + ("TODO" "ERRAND" "WAITING") () ())) + +;; -------- Email -------- + +;;(use-package mu4e) + +;;(add-to-list 'load-path "/usr/share/emacs/site-lisp/mu4e") + +(setq sendmail-program (executable-find "msmtp")) + +(autoload 'mu4e "mu4e" "\ +If mu4e is not running yet, start it. Then, show the main +window, unless BACKGROUND (prefix-argument) is non-nil. +" t nil) + +(setq mu4e-update-interval 600) ;; refresh every X seconds + +(setq message-citation-line-format "On %d %b %Y at %R, %f wrote:\n") +(setq message-citation-line-function 'message-insert-formatted-citation-line) + +(setq mu4e-attachment-dir "~/Downloads") + +(setq mu4e-html2text-command 'mu4e-shr2text) + +(setq mu4e-user-mail-address-list '("mail@knazarov.com" "k.nazarov@corp.mail.ru")) + +;; exlude myself from the email replies +(setq mu4e-compose-dont-reply-to-self t) + +;; set mu4e as a default mail agent +(setq mail-user-agent 'mu4e-user-agent) + +(setq mu4e-maildir "/home/knazarov/Maildir") + +(setq + mu4e-view-show-images t + mu4e-image-max-width 800 + mu4e-view-prefer-html t + mu4e-change-filenames-when-moving t ;; prevent duplicate UIDs + mu4e-get-mail-command "mbsync -a -q" + mu4e-headers-include-related nil) + +(setq mu4e-sent-folder "/personal/Sent" + mu4e-drafts-folder "/personal/Drafts" + mu4e-trash-folder "/personal/Trash" + mu4e-refile-folder "/personal/Archive" + user-full-name "Konstantin Nazarov" + user-mail-address "mail@knazarov.com" + smtpmail-default-smtp-server "smtp.fastmail.com" + smtpmail-local-domain "knazarov.com" + smtpmail-smtp-server "smtp.fastmail.com" + smtpmail-stream-type 'starttls + smtpmail-smtp-service 587 + message-send-mail-function 'message-send-mail-with-sendmail + ;;message-sendmail-extra-arguments '("--read-envelope-from") + ) + +(setq mu4e-compose-signature + "<#part type=text/html>

Hello ! I am the html signature which can contains anything in html !

<#/part>" ) + +(defvar my-mu4e-account-alist + `(("personal" + (mu4e-sent-folder "/personal/Sent") + (mu4e-drafts-folder "/personal/Drafts") + (mu4e-trash-folder "/personal/Trash") + (mu4e-refile-folder "/personal/Archive") + (user-mail-address "mail@knazarov.com") + (message-sendmail-envelope-from "mail@knazarov.com") + ;;(mu4e-compose-signature-auto-include nil) + (mu4e-compose-signature ,(if (file-exists-p "~/.mail-sig.txt") + (with-temp-buffer + (insert-file-contents "~/.mail-sig.txt") + (buffer-string)) + "")) + (message-signature-file "~/.mail-sig.txt") + (message-cite-reply-position above) + (message-cite-style message-cite-style-outlook)) + ("work" + (mu4e-sent-folder "/work/Sent") + (mu4e-drafts-folder "/work/Drafts") + (mu4e-trash-folder "/work/Trash") + (mu4e-refile-folder "/work/Archive") + (user-mail-address "k.nazarov@corp.mail.ru") + (message-sendmail-envelope-from "k.nazarov@corp.mail.ru") + (mu4e-compose-signature-auto-include nil) + (message-signature-file "~/.mail-sig.txt") + (mu4e-compose-signature ,(if (file-exists-p "~/.mail-sig.txt") + (with-temp-buffer + (insert-file-contents "~/.mail-sig.txt") + (buffer-string)) + "")) + (message-cite-reply-position above) + (message-cite-style message-cite-style-outlook)) + )) + +(defun my-mu4e-set-account () + "Set the account for composing a message." + (let* ((account + (if mu4e-compose-parent-message + (let ((maildir (mu4e-message-field mu4e-compose-parent-message :maildir))) + (string-match "/\\(.*?\\)/" maildir) + (match-string 1 maildir)) + (completing-read (format "Compose with account: (%s) " + (mapconcat #'(lambda (var) (car var)) + my-mu4e-account-alist "/")) + (mapcar #'(lambda (var) (car var)) my-mu4e-account-alist) + nil t nil nil (caar my-mu4e-account-alist)))) + (account-vars (cdr (assoc account my-mu4e-account-alist)))) + (if account-vars + (mapc #'(lambda (var) + (set (car var) (cadr var))) + account-vars) + (error "No email account found")))) + +(defun my-mu4e-refile-folder-function (msg) + (let ((mu4e-accounts my-mu4e-account-alist) + (current-message msg) + (account)) + (setq account (catch 'found + (dolist (candidate mu4e-accounts) + (if (string-match (car candidate) + (mu4e-message-field current-message :maildir)) + (throw 'found candidate) + )))) + (if account + (cadr (assoc 'mu4e-refile-folder account)) + (throw 'account_not_found (mu4e-message-field current-message :maildir)) + ) + ) + ) + +(setq mu4e-refile-folder 'my-mu4e-refile-folder-function) + +(add-hook 'mu4e-compose-pre-hook 'my-mu4e-set-account) + +;; Be smart about inserting signature for either cite-reply-position used +(defun insert-signature () + "Insert signature where you are replying" + ;; Do not insert if already done - needed when switching modes back/forth + (unless (save-excursion (message-goto-signature)) + (save-excursion + (if (eq message-cite-reply-position 'below) + (goto-char (point-max)) + (message-goto-body)) + (insert-file-contents message-signature-file) + (save-excursion (insert "\n-- \n"))))) +(add-hook 'mu4e-compose-mode-hook 'insert-signature) + +;;(add-to-list 'mu4e-bookmarks +;; '("maildir:/work/INBOX" "work inbox" ?w)) + +;;(add-to-list 'mu4e-bookmarks +;; '("maildir:/knazarov/INBOX" "personal inbox" ?p)) + +(setq mu4e-bookmarks + '(("maildir:/personal/INBOX OR maildir:/work/INBOX" "inbox" ?i))) + +;; -------- Programming -------- + +;; Enable direnv-mode to automatically load Nix flake dependencies for projects +(use-package direnv + :config + (direnv-mode)) + +;; Rainbow delimeters highlight matching pairs of braces in different colors + +(use-package rainbow-delimiters) +(add-hook 'prog-mode-hook #'rainbow-delimiters-mode) + +;; Flycheck is an on-the-fly syntax checker for emacs with pluggable backengs. + +(use-package flycheck) +;; Not usable for every single mode, so need to be selective +;;(add-hook 'prog-mode-hook #'flycheck-mode) + +;; Scroll compilation buffer with the output + +(setq compilation-scroll-output t) + +;; Projectile auto-detects projects and allows to run project-wide commands + +(use-package projectile) +(setq projectile-cache-file "~/.emacs.d/projectile.cache") +(projectile-mode +1) +(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map) + +;; Corfu mode is a simple auto completion framework with +;; pluggable backends + +;;(setq company-backends '(company-capf (company-dabbrev-code) company-dabbrev)) +;;(add-hook 'prog-mode-hook #'company-mode) +;;(add-hook 'mu4e-compose-mode-hook #'company-mode) +(use-package corfu) +(add-hook 'after-init-hook 'global-corfu-mode) +(add-hook 'after-init-hook 'corfu-popupinfo-mode) +(setq corfu-auto t) +(setq tab-always-indent 'complete) +(setq corfu-quit-no-match 'separator) + +(use-package cape) +(add-to-list 'completion-at-point-functions #'cape-dabbrev) +(add-to-list 'completion-at-point-functions #'cape-file) + +;; Can't live without magit. It makes working with git sooo much easie + +(use-package magit) +(global-set-key (kbd "C-x g") 'magit-status) + +;;(setq magit-completing-read-function 'magit-ido-completing-read) + + +;; LSP + +;; Maybe switch to EGLOT, which is shipped in Emacs 29 +(add-hook 'lua-mode-hook #'lsp) + +;; Tree-sitter + +(setq major-mode-remap-alist + '((yaml-mode . yaml-ts-mode) + (bash-mode . bash-ts-mode) + (js2-mode . js-ts-mode) + (typescript-mode . typescript-ts-mode) + (json-mode . json-ts-mode) + (css-mode . css-ts-mode) + (python-mode . python-ts-mode) + (cpp-mode . cpp-ts-mode) + (c-mode . c-ts-mode) + )) + +(setq treesit-font-lock-level 4) + +;; vterm + +;; Vterm is a fully featured terminal emulator, that works inside +;; emacs buffers. It is miles ahead of "term" and "eshell" both in +;; speed and features. + +(setq vterm-always-compile-module t) +(use-package vterm) + +;;(add-to-list 'load-path (expand-file-name "~/dev/emacs-libvterm/")) + +(defun vterm-less (content) + (let ((less-buffer (get-buffer-create (make-temp-name "vterm-less-")))) + (with-current-buffer less-buffer + (switch-to-buffer less-buffer) + (special-mode) + (insert (base64-decode-string content))) + ) + ) + + +(use-package with-editor) +(defun my-vterm-mode-hook () + (add-to-list 'vterm-eval-cmds (list "less" #'vterm-less)) + (with-editor-export-editor) + ) + +(add-hook 'vterm-mode-hook #'my-vterm-mode-hook) + +(put 'upcase-region 'disabled nil) + +(autoload 'vterm "vterm" "\ +If vterm is not running yet, start it. Then, show the main +window, unless BACKGROUND (prefix-argument) is non-nil. +" t nil) + + +;; lua + +(use-package lua-mode) +(setq lua-indent-level 4) + +;; common lisp + +(use-package sly) +(use-package sly-asdf) +(use-package aggressive-indent) + +(add-to-list 'sly-contribs 'sly-asdf 'append) +(autoload 'sly "sly" + "Start an inferior^_superior Lisp and connect to its Swank server." + t nil) + +(define-key lisp-mode-map (kbd "C-c v") + 'sly-asdf-test-system) + +;autoload 'sly-lisp-mode-hook "sly" +; "Set up sly for a lisp buffer." +; t nil) + +(add-hook 'lisp-mode-hook #'aggressive-indent-mode) +;(add-hook 'lisp-mode-hook 'sly-lisp-mode-hook) +;(setq slime-contribs '(slime-fancy slime-company)) +(setq inferior-lisp-program "sbcl") + + +;; Markdown + +(use-package markdown-mode) + +;; Dockerfiles + +(use-package dockerfile-mode) + +;; Yaml + +(use-package yaml-mode) + +;; CMake + +(use-package cmake-mode) + +;; C++ + +(with-eval-after-load 'eglot + (add-to-list 'eglot-server-programs + `(c++-mode . ("clangd")))) + +(add-hook 'c++-mode-hook 'eglot-ensure) + +(use-package clang-format) +(use-package clang-format+) +(add-hook 'c-mode-hook 'clang-format+-mode) +(add-hook 'c++-mode-hook 'clang-format+-mode) + +;; Zig + +(use-package zig-mode) + +;; Terraform + +(use-package terraform-mode) + + +;; Nix + +(use-package nix-mode) + +(use-package sudo-edit) +(global-set-key (kbd "C-c C-r") 'sudo-edit) + +(provide 'init) +;;; init.el ends here diff --git a/flake.lock b/flake.lock new file mode 100755 index 0000000..09f7cbe --- /dev/null +++ b/flake.lock @@ -0,0 +1,220 @@ +{ + "nodes": { + "emacs-overlay": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1690655028, + "narHash": "sha256-6ApYk2XOiyDFKDus5Ysmiw591AgxJpxK4/5rWtRWYfU=", + "owner": "nix-community", + "repo": "emacs-overlay", + "rev": "2a52d78c85ee0608938670c7db79ffaba6f7b31d", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "emacs-overlay", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1689068808, + "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1690652600, + "narHash": "sha256-Dy09g7mezToVwtFPyY25fAx1hzqNXv73/QmY5/qyR44=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "f58889c07efa8e1328fdf93dc1796ec2a5c47f38", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "knazarovcom": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1690578969, + "narHash": "sha256-aouJyTWiVstw8xRKxasvFdaO4r8H/ZBoMDpeF6Sz86I=", + "owner": "~knazarov", + "repo": "knazarov.com", + "rev": "01ca3704520430ca3b8a36f4ce9dd8581bbd77f6", + "type": "sourcehut" + }, + "original": { + "owner": "~knazarov", + "repo": "knazarov.com", + "type": "sourcehut" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1690659494, + "narHash": "sha256-aW5Iupj/GQ3ghbZJHxdLhwOrmMRkaVcpwBR/Qf7/Uwg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d63df5a32b6292679c95af0e41272ae0dcbb0186", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1690558459, + "narHash": "sha256-5W7y1l2cLYPkpJGNlAja7XW2X2o9rjf0O1mo9nxS9jQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "48e82fe1b1c863ee26a33ce9bd39621d2ada0a33", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable_2": { + "locked": { + "lastModified": 1690066826, + "narHash": "sha256-6L2qb+Zc0BFkh72OS9uuX637gniOjzU6qCDBpjB2LGY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ce45b591975d070044ca24e3003c830d26fea1c8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "release-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "q-sh": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1684711176, + "narHash": "sha256-PbMTPJNQMivX2uHthyDy4C1UUKD8moQVWlHPWiP9xI0=", + "owner": "~knazarov", + "repo": "q.sh", + "rev": "ee95b2afb54074fd004652816ffc9ad52fea9fc4", + "type": "sourcehut" + }, + "original": { + "owner": "~knazarov", + "repo": "q.sh", + "type": "sourcehut" + } + }, + "root": { + "inputs": { + "emacs-overlay": "emacs-overlay", + "home-manager": "home-manager", + "knazarovcom": "knazarovcom", + "nixpkgs": "nixpkgs", + "q-sh": "q-sh", + "sops-nix": "sops-nix", + "vmatveevacom": "vmatveevacom" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable_2" + }, + "locked": { + "lastModified": 1690199016, + "narHash": "sha256-yTLL72q6aqGmzHq+C3rDp3rIjno7EJZkFLof6Ika7cE=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "c36df4fe4bf4bb87759b1891cab21e7a05219500", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "vmatveevacom": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1686509156, + "narHash": "sha256-zV1DbAvNlfGznLdpCoqSNNXtAHFjzYaO9vY76BV+CnQ=", + "owner": "valeriya-matveeva", + "repo": "vmatveeva.com", + "rev": "4a5799dfa115f05bd09ced89bd962a35a9018978", + "type": "github" + }, + "original": { + "owner": "valeriya-matveeva", + "repo": "vmatveeva.com", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100755 index 0000000..c8be36d --- /dev/null +++ b/flake.nix @@ -0,0 +1,67 @@ +# reference: https://github.com/kenranunderscore/dotfiles/blob/main/flake.nix +# also good: https://github.com/cab404/home + +{ + inputs = { + nixpkgs.url = github:NixOS/nixpkgs; + home-manager.url = github:nix-community/home-manager; + home-manager.inputs.nixpkgs.follows = "nixpkgs"; + emacs-overlay.url = github:nix-community/emacs-overlay; + emacs-overlay.inputs.nixpkgs.follows = "nixpkgs"; + sops-nix.url = github:Mic92/sops-nix; + sops-nix.inputs.nixpkgs.follows = "nixpkgs"; + q-sh.url = sourcehut:~knazarov/q.sh; + q-sh.inputs.nixpkgs.follows = "nixpkgs"; + knazarovcom.url = sourcehut:~knazarov/knazarov.com; + knazarovcom.inputs.nixpkgs.follows = "nixpkgs"; + vmatveevacom.url = github:valeriya-matveeva/vmatveeva.com; + vmatveevacom.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = { self, nixpkgs, home-manager, emacs-overlay, sops-nix, q-sh, knazarovcom, vmatveevacom, ... }@attrs: + let + system = "x86_64-linux"; + + specialArgs = { + inherit attrs; + }; + buildConfig = modules: system: { inherit modules system specialArgs; }; + buildSystem = modules: system: nixpkgs.lib.nixosSystem (buildConfig modules system); + hostAttrs = dir: { + settings = import "${dir}/host-metadata.nix"; + config = import "${dir}/configuration.nix"; + hw-config = import "${dir}/hardware-configuration.nix"; + }; + + node = dir: with hostAttrs dir; buildSystem [ + ({ config, pkgs, ... }: { nixpkgs.overlays = [ emacs-overlay.overlay q-sh.overlays.default]; }) + sops-nix.nixosModules.sops + home-manager.nixosModule + config + hw-config + ./configuration.nix + ] + settings.system; + + server = dir: with hostAttrs dir; buildSystem [ + ({ config, pkgs, ... }: { nixpkgs.overlays = [ + emacs-overlay.overlay + q-sh.overlays.default + knazarovcom.overlays.default + vmatveevacom.overlays.default]; }) + sops-nix.nixosModules.sops + home-manager.nixosModule + config + hw-config + #(dir + "/configuration.nix") + ] + settings.system; + in + { + nixosConfigurations = { + mira = node ./nodes/mira; + framework = node ./nodes/framework; + knazarovcom = server ./nodes/knazarovcom; + }; + }; +} diff --git a/gpg_public_key.asc b/gpg_public_key.asc new file mode 100644 index 0000000..324058e --- /dev/null +++ b/gpg_public_key.asc @@ -0,0 +1,109 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=Wr86 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/nodes/framework/configuration.nix b/nodes/framework/configuration.nix new file mode 100644 index 0000000..0fa2709 --- /dev/null +++ b/nodes/framework/configuration.nix @@ -0,0 +1,22 @@ +{ self, config, lib, nixpkgs, pkgs, ... }: + +let + +in +{ + # Bootloader. + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + boot.loader.efi.efiSysMountPoint = "/boot/efi"; + + # Setup keyfile + boot.initrd.secrets = { + "/crypto_keyfile.bin" = null; + }; + + networking.hostName = "framework"; + # Enable swap on luks + boot.initrd.luks.devices."luks-20e33e39-6349-4763-ab23-c14cde35055f".device = "/dev/disk/by-uuid/20e33e39-6349-4763-ab23-c14cde35055f"; + boot.initrd.luks.devices."luks-20e33e39-6349-4763-ab23-c14cde35055f".keyFile = "/crypto_keyfile.bin"; + +} diff --git a/nodes/framework/hardware-configuration.nix b/nodes/framework/hardware-configuration.nix new file mode 100755 index 0000000..d9f34b0 --- /dev/null +++ b/nodes/framework/hardware-configuration.nix @@ -0,0 +1,44 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/ba814b49-32a4-469a-867d-e00c697c25dd"; + fsType = "ext4"; + }; + + boot.initrd.luks.devices."luks-8a5e5d06-1728-4275-9ca6-0a9c8e959796".device = "/dev/disk/by-uuid/8a5e5d06-1728-4275-9ca6-0a9c8e959796"; + + fileSystems."/boot/efi" = + { device = "/dev/disk/by-uuid/9818-F10B"; + fsType = "vfat"; + }; + + swapDevices = + [ { device = "/dev/disk/by-uuid/eb01f39e-e4c2-4bff-8994-b859e338343c"; } + ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp170s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + # high-resolution display + # hardware.video.hidpi.enable = lib.mkDefault true; +} diff --git a/nodes/framework/host-metadata.nix b/nodes/framework/host-metadata.nix new file mode 100644 index 0000000..a76f7d1 --- /dev/null +++ b/nodes/framework/host-metadata.nix @@ -0,0 +1,4 @@ +{ + system = "x86_64-linux"; + host = "framework"; +} diff --git a/nodes/knazarovcom/configuration.nix b/nodes/knazarovcom/configuration.nix new file mode 100644 index 0000000..41885ea --- /dev/null +++ b/nodes/knazarovcom/configuration.nix @@ -0,0 +1,117 @@ +{ config, pkgs, ... }: + +{ + imports = + [ + ./hardware-configuration.nix + ]; + + boot.loader.grub.enable = true; + networking.hostName = "knazarovcom"; + boot.loader.grub.device = "/dev/vda"; + + + users.users.knazarov = { + isNormalUser = true; + extraGroups = [ "wheel" ]; + openssh.authorizedKeys.keys = [ + "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJkgpPDojl4RtsuFLIsHkH/19s3trYljdn/Jmbb3FCHNAAAABHNzaDo= knazarov@framework" + "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIO7W7yDKxAj9u1hu3zsZMJW+0HUnA/C/rkbuzkQantkaAAAABHNzaDo= knazarov@mira"]; + }; + + environment.systemPackages = with pkgs; [ + vim + sops + goaccess + ]; + + services.openssh.enable = true; + services.openssh.settings = { + PermitRootLogin = "no"; + PasswordAuthentication = false; + }; + + security.pam.enableSSHAgentAuth = true; + security.sudo.wheelNeedsPassword = false; + nix.settings.trusted-users = [ "@wheel" ]; + + services.nginx = { + enable = true; + virtualHosts = { + "knazarov.com" = { + enableACME = true; + forceSSL = true; + root = "${pkgs.knazarovcom}/srv/knazarov.com"; + + locations."/.well-known/matrix/server" = { + extraConfig = '' + default_type application/json; + return 200 '{ "m.server": "matrix.knazarov.com:443" }'; + ''; + }; + locations."/.well-known/matrix/client" = { + extraConfig = '' + default_type application/json; + return 200 '{ "m.homeserver": { "base_url": "https://matrix.knazarov.com" } }'; + add_header "Access-Control-Allow-Origin" *; + ''; + }; + }; + "vmatveeva.com" = { + enableACME = true; + forceSSL = true; + root = "${pkgs.vmatveevacom}/srv/vmatveeva.com"; + }; + "matrix.knazarov.com" = { + enableACME = true; + forceSSL = true; + locations."/_matrix" = { + proxyPass = "http://127.0.0.1:8008"; + }; + }; + }; + }; + security.acme.acceptTerms = true; + security.acme.certs = { + "knazarov.com".email = "mail@knazarov.com"; + "vmatveeva.com".email = "mail@knazarov.com"; + "matrix.knazarov.com".email = "mail@knazarov.com"; + }; + + services.dendrite = { + enable = true; + environmentFile = config.sops.secrets.matrix_registration_secret.path; + settings = { + global = { + server_name = "knazarov.com"; + private_key = config.sops.secrets.matrix_key.path; + jetstream = { + storage_path = "/var/lib/dendrite/nats"; + }; + }; + client_api.registration_shared_secret = "$REGISTRATION_SHARED_SECRET"; + }; + }; + + systemd.services.dendrite = { + serviceConfig.SupplementaryGroups = [ config.users.groups.keys.name ]; + }; + + sops.defaultSopsFile = ./secrets.yaml; + sops.secrets = { + example_key = {}; + matrix_key = { + mode = "0440"; + group = config.users.groups.keys.name; + }; + matrix_registration_secret = { + mode = "0440"; + group = config.users.groups.keys.name; + }; + }; + + networking.firewall.allowedTCPPorts = [ 80 443 ]; + # networking.firewall.allowedUDPPorts = [ ... ]; + + system.stateVersion = "23.05"; +} diff --git a/nodes/knazarovcom/hardware-configuration.nix b/nodes/knazarovcom/hardware-configuration.nix new file mode 100644 index 0000000..0d0aa2c --- /dev/null +++ b/nodes/knazarovcom/hardware-configuration.nix @@ -0,0 +1,32 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = [ ]; + + boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "sr_mod" "virtio_blk" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/3c286fff-9eaf-4839-9b29-5c686d33cf49"; + fsType = "btrfs"; + }; + + swapDevices = + [ { device = "/dev/disk/by-uuid/976561a7-9e30-42cf-8598-97f1d93cafed"; } + ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.ens3.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + virtualisation.hypervGuest.enable = true; +} diff --git a/nodes/knazarovcom/host-metadata.nix b/nodes/knazarovcom/host-metadata.nix new file mode 100644 index 0000000..3e5ebe8 --- /dev/null +++ b/nodes/knazarovcom/host-metadata.nix @@ -0,0 +1,4 @@ +{ + system = "x86_64-linux"; + host = "knazarovcom"; +} diff --git a/nodes/knazarovcom/secrets.yaml b/nodes/knazarovcom/secrets.yaml new file mode 100644 index 0000000..5003776 --- /dev/null +++ b/nodes/knazarovcom/secrets.yaml @@ -0,0 +1,44 @@ +hello: ENC[AES256_GCM,data:Bv1MBhqWVzeDc0Qx0n3QagUbEUDUjCARZNiQ4qYnX9PsiQvHN21vsBiu9blBaA==,iv:rhxag0W9EER7lNRY9WsrvOyxxvqC7DSjgI9KR71hjm4=,tag:qJoMp8G0jQGBeoakBR+Zlw==,type:str] +example_key: ENC[AES256_GCM,data:J09ZRQJg34iARNVGlQ==,iv:tFtCB+FfSLJad4oQNJsyOE9lz6y3Pj8nNq4x5WswNNs=,tag:8+OWJHmXzUrDl6qrSvWlYA==,type:str] +matrix_registration_secret: ENC[AES256_GCM,data:YbEp3LRrMs3gGG9tE1CCXXWoFdV9hXaTx4/VOHwSqyxAlQWnBXGUHwI6R1fE0e6ZzLT2+9g=,iv:YXLG/GsfRxSMwLd0Trl7xjuVPdAe7krEbh5YxAYzOb8=,tag:DYoEoMGH76pkVr6DAzjj+g==,type:str] +matrix_key: ENC[AES256_GCM,data:+7Ru9Q57kECDCPp/SjvdIDFGveFJ8XI8/Dv+tTwpUdRt6yNeXOT1his8kP/F9Bod5LZLKD+3mZBJV39GCfl7Mha1pQowWj3UGLwUu1o/wJ2G83YSoa9leJc9Ug9vBSixAsP34g9lUTD/zrlvQtCNjZbtqx3D4B4DTUWUmN8jiE1ah+zXoO4U5YY=,iv:gUdM5cEh+LMP++1I7F/+148u7HBY3SKQvGVcVX6bL/U=,tag:evbi9tmmlbklrpaB1tvezA==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1esdg28lplhhvrj6vmqu9x0adyxj5trp2dp7my3k57kjhkstkk9cqkg5qkj + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5ODlUK3d2RkoyQU11MFlT + SW1UeWhzYmxDQW40UkMyUmpGNGpJZjh3SldZCjNTR2NiajUrT1VybWRYbTNrZUs5 + UE9kQ0pOb2FrSzk0d2tiNGtMQW83K1UKLS0tIDdKUE9CRlZwN0hMcXdhdWRvNXFh + anBCR0NXVlhLSXVCc2swTzNqOUFOSkUKyIRL9aCv3m6Qz7OaE7dSYzFYNeeFEprW + /9XLB4FzTCK3xoBeeFGevm8Z6z9k+2eku5dQUjAZ5FrVZLPM+fUgRw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2023-06-11T20:37:31Z" + mac: ENC[AES256_GCM,data:7ke0oXjI31ocCqOxDriTOIVTm4Y/vsNKrsS1GioenIzzUBmkc+cFABuczAbkLMr7C0AEgMdHEA57e56xArQWJTNb0juBsA4oBWzIYxm/sYhZRdh29Mbp3zoJsNkLeiSi9JjF5Rptr5k8x01CV5swthStGUMQQ0TfbAQmqG7blBg=,iv:DSMu0htVdJ02yIqm6OTFsIejV901PryF9D6U/K5XqPk=,tag:yo1h+zrv5RFL/NniiZ70Bg==,type:str] + pgp: + - created_at: "2023-06-11T20:10:06Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + wcFMAz3KbDTqPV7IAQ/6A4DxTlvQhUDgjBwnYmXSKIjcSo8baOoPNrkYDpAOdMFd + IzQ6gVHwQWKTifuvv6rWArwDW1vD6pC8urmvCB0kzoGPr/4oX/K+881aTREJKmIe + DMZd1kz9N+hw92fJ1SCwYPgTwdjm2+e1yaHl1SzM/N1TgO1Li0LA9ZH+zxwheLBw + zJtdX6ND894MiptITBfNhkXKxj1YpyZvZeoFbR6Tj2fnyTPxgNluHKDXVpuY8m7f + Ma/rdd2eXcOJBpI2iVnkgVqnwjP+lSpYAYvjYeAoe6z+0Cmh8/qpqS1UrdhqUUgI + An75cYeUV9XjuozuvyUcTvHaOFygDK++W8Q/50s9aniz9kyy88fV0PZH1TsByu9N + wi3PTYc3VpkeIyDz+T4Xk++8jCWyUXBS6LB+9AxTFGRmnjv5u93JQ7m+82lkhpR/ + DVgdGZKpD2wUvfF1pCGq3qXL/Cy1EOs5PDkbirmqvMLgkcRNn4+cuJqbLsHR+T5F + hngtOKFhcgaFtrNLN8p59PTvW4xI+CkAkhKFQs7MCS3SjtojGqVxeKJQlTws3P6P + QRxbNlMh2YagSAhVHl2uJGOYey0ylvU0ROZFL4F4FQWEcGv7zHBxGr9d6yv9ygrF + 6KO25T1y8w6jnptZfnGTaMW83stOLGUyRRp7x3OxfOZbDabvnLwzqKyfPgNXv03S + UQENFxwrbTf+YiKpzF9Z99CmMEqVEJBZz9cO5jnBffN2/bRb8KNaImiDge759QSn + cpfJadxIM1KFbj54Y0CS8GuRN2ycl8myhqGsC0D1W0kFXA== + =rJP2 + -----END PGP MESSAGE----- + fp: DDB4423999505236CF585F9B0560020C9C577C1B + unencrypted_suffix: _unencrypted + version: 3.7.3 diff --git a/nodes/mira/configuration.nix b/nodes/mira/configuration.nix new file mode 100644 index 0000000..98ae196 --- /dev/null +++ b/nodes/mira/configuration.nix @@ -0,0 +1,22 @@ +{ self, config, lib, nixpkgs, pkgs, ... }: + +let + +in +{ + # Bootloader. + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + boot.loader.efi.efiSysMountPoint = "/boot/efi"; + + # Setup keyfile + boot.initrd.secrets = { + "/crypto_keyfile.bin" = null; + }; + + networking.hostName = "mira"; + # Enable swap on luks + boot.initrd.luks.devices."luks-8aa0584a-df60-42c3-adc2-d88b85544c85".device = "/dev/disk/by-uuid/8aa0584a-df60-42c3-adc2-d88b85544c85"; + boot.initrd.luks.devices."luks-8aa0584a-df60-42c3-adc2-d88b85544c85".keyFile = "/crypto_keyfile.bin"; + +} diff --git a/nodes/mira/hardware-configuration.nix b/nodes/mira/hardware-configuration.nix new file mode 100644 index 0000000..4890840 --- /dev/null +++ b/nodes/mira/hardware-configuration.nix @@ -0,0 +1,50 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, system76, modulesPath, ... }: + +let + +in +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + + boot.kernelModules = [ "kvm-amd"]; + + boot.kernelParams = [ "mem_sleep_default=deep" ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/1a71ab59-b65c-4866-a76c-a1372cc30cb8"; + fsType = "ext4"; + }; + + boot.initrd.luks.devices."luks-ad5fe721-9e57-45ae-bc7a-9724590d97e8".device = "/dev/disk/by-uuid/ad5fe721-9e57-45ae-bc7a-9724590d97e8"; + + fileSystems."/boot/efi" = + { device = "/dev/disk/by-uuid/36AD-6828"; + fsType = "vfat"; + }; + + swapDevices = + [ { device = "/dev/disk/by-uuid/9ea6aaab-0e78-411f-90fa-5161d897419b"; } + ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp16s0.useDHCP = lib.mkDefault true; + # networking.interfaces.enp21s0u4.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + + # for mira + hardware.system76.enableAll = true; +} diff --git a/nodes/mira/host-metadata.nix b/nodes/mira/host-metadata.nix new file mode 100644 index 0000000..7df5570 --- /dev/null +++ b/nodes/mira/host-metadata.nix @@ -0,0 +1,4 @@ +{ + system = "x86_64-linux"; + host = "mira"; +} diff --git a/secrets.yaml b/secrets.yaml new file mode 100644 index 0000000..4293836 --- /dev/null +++ b/secrets.yaml @@ -0,0 +1,53 @@ +hello: ENC[AES256_GCM,data:+LPt8J+Ks1m10+zZ2Q96r3K2W6Yeng7M7+c2TYDQ+/4AJl6Xc6hVnU8PKk28RA==,iv:v3B/CcFFA7kuuPcYDa5qha0ZrtskW5p443Zm8kM7xqA=,tag:r8Y9uf1dmp+VfJOHFG75PQ==,type:str] +fastmail_password: ENC[AES256_GCM,data:tHr8PqIg9DigRBu2bgjUeg==,iv:NI9bENFPuKcOt1cd2kg2DKU22J1dJ+3mK7UoceZagR4=,tag:oEgeQb1iLKisOqHi9Ds7xg==,type:str] +github_token: ENC[AES256_GCM,data:E1+wrI5VUlnsqfKNH6fY7IXqHIiagAByLYCfIfdd2+HcvniAvZzaIyKB3nma5eks3csN5A9XgYXRb09lELroW00obmIWbWZPdFhDccHRtVOqFq/r+x27O/3MAkDqID5mc8xD8SqWUibr9UZfXjFcXC4bx7+a4pyy45akz9RLIJRVKDzxMBGmZ/wQcuFS9uy2Pv2yWRL7q4olzvc/kzNFRWCLU7ThIAJSIx//NluOE8xjsA==,iv:Cdc2wwGdXprch1hHd0CwJM6vUAYmfhI4FpcKjcoIZYY=,tag:so8BJtjHGcGzayPqMwy43A==,type:str] +mullvad_account: ENC[AES256_GCM,data:CO4wl2vNAMEC9oy37nIrpw==,iv:a3w64u8XQ/tihIDxIPPtdZ6F7dldLPvRzGUs1MpVe4M=,tag:HQxJVuGEvI0fVj8yGptbdA==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1le98v5v0xnlnc4y0ydgj9kwfftt8g5wduws8zsadgc97pj0fzecs55tjvz + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXR0U3YzJ0cmlJT3kyM1RX + TFVqYXd2ZExQbjlYV25zOTRRdURZMFB6aFhvCldENzRReWFUVC9Eb3Y5YjZ1dTN3 + SFBMb2hHUU1hbHUxaTlmQ1g0MldvS1EKLS0tIGlIVi9VTFpWa2tUL0dNTkdxcUh6 + Wkw4bzhQQkZTL2NWWkdZZG56SXIzUjAK1BAmCn/xthTFMuGi+wfxtmGbl8OGDWVd + eK292+qPudunqhhkuCvRCSO4A/MOIYcuiGN4IgIpw3rt8IdcypjOzQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age1rkmhgep2jhdnma24x7ufzr686cwq6p3nk7mmedykan0d7c36xaus2y58sw + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOWnR2b3F5SWp3VlJHQXB1 + WlJhWFJ4ZWZsd3FvaVBYMzlSNnE1R3JQWEdZCnh4bjNOVytBWE1DT1JZN1ZCYnN5 + TXB2NDFnSldQRlJBOWtjTStBT0cyS3cKLS0tIGdBY2YyWm83dVN0bk4vOVhQRS9x + U3loV2xDMkM5SWNXRDJobDloL0FVUUkK3OP7KvcKkE8mJ880dm6LMFZUxELjl8/P + 6+q8qAYiAvl0Cbd4GzkNpUuBbLlFFWfFmC0vbgg8gyZ6xI5AFhHAPw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2023-07-09T20:32:29Z" + mac: ENC[AES256_GCM,data:c9+qPvLsiCgZPZ2vguQGCb+5LEr8cg32VGCyUvqiqICq5xtMZeDK7Uj8n0yLj0USaZ7bttUiI2CBpEl6anRSrXUGoJwmvJboXVi9/Xex5tv45hvdGA4Hd3P88K8kVRankOVhpogBRzcOpp4JsrtgxDTKabekpnaEr2l7H+5sXDU=,iv:no7t2FUwUaQWiuDDHe3Z5C5zoG5rnMeD9ar8PhtxyE4=,tag:AJYWdPdRGhG5epTsiD+cTw==,type:str] + pgp: + - created_at: "2023-06-10T01:03:11Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + wcFMAz3KbDTqPV7IAQ/9ExkcLHiNnRPI9tls9yD6/FhLDoNnQDeDlezcHarqGXF8 + 971t2odI+vHFMNfq3xNqCbIBsycwP9FTey3P1bMnUuZ7Pp1kFc4Z3DFjm3nsnoky + PnoRfPJzETOmwb4TExv6XxlUAnjzPWkRrhWL4sacg9ia+LIa1mBzHkc2h0ldNcDF + TkG/tbPR6raJcd4LgVvPJLpBe7FUQAQDsQ3mozt364KnZ+poltR5sf4kttAhfgVt + lbkbFleOsIc1mhmQSMbi4ta6ofc96XPyHN7rwAGWIrhxUl9oGpnLrlxNXxytNYLG + hokRnFgi5DQMIhzO2DJb3Z88+92+xpub5IOhUhn5vJJcT74NNXcGd9/1b4srLdDt + NoFtKEZQWBys0u3wrJUW3Lm/ouEmDPuQbSZlV3/dddMF6Vx4KixU/03yg3fBuHUF + f7zhw1l1fGuKv4FFLGgAShMsqPOK+KZswHQr2JSE1tv69VbD2C11wmf2lr5tmJBM + Dy3HNPsIFsmzkAVt5be0ehZbyF91Gwjg89TO4gV8PN2gSVWxBwk5n7jKpoKOta3e + PYyC/z/OVp0HayxZOIShhdY1N9lxAYXO1kS8AhpGttAj5Xd4jm3gr6O8+6sM8yqL + BYKR2g/dnPm1QcChPTNxSgzmYxhK0Rud4mNXw/RB9DPTHlBbjkt4pDvrm/UvJZXS + UQHNnqrqjq3U8cLpP6x1wGexp+VilezFpzzrR9B9nLWVvskbfeUy3CoIq4Kedzoh + 9l1/byLB8CIcnDz7ewA3wZsCYCuP+np8uvbMx9srJVia8Q== + =3Z1t + -----END PGP MESSAGE----- + fp: DDB4423999505236CF585F9B0560020C9C577C1B + unencrypted_suffix: _unencrypted + version: 3.7.3 diff --git a/switch.sh b/switch.sh new file mode 100755 index 0000000..f041a91 --- /dev/null +++ b/switch.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +if [ "$1" = "mira" ]; then + nixos-rebuild switch --use-remote-sudo --flake `pwd`#mira +elif [ "$1" = "framework" ]; then + NIX_SSHOPTS="-t" nixos-rebuild switch --target-host framework --use-remote-sudo --flake `pwd`#framework +elif [ "$1" = "knazarovcom" ]; then + nixos-rebuild switch --target-host knazarov.com --use-remote-sudo --flake `pwd`#knazarovcom +fi diff --git a/wallpaper.jpg b/wallpaper.jpg new file mode 100755 index 0000000000000000000000000000000000000000..88495da9d6dfc611d276445c864180d47926b915 GIT binary patch literal 124499 zcmeEv2V7Ih+V=qg7jb1J3O2-5DdJ*Oq)3Ym5dsDzh>9d@0VE2nQVcC1>S9npDIzT( zNDB%ppcDf^r3eC1AR-{WNhgFBNWwP<_1=B&b<1t zg8Z*KC1|#Y=;zh9x#0wXYWI*fRS7>! zrSBH^1k+M(GpAzs20kW8f+~Z>V2l4_#Q-3}SJZ161Nk#ui_MHjKlg?^&y6MEuf2xRLsohci z!MxBu&3)$|DNqYCl|J7_f|@!U&eVy3TXWbNTjg5(Pu>5IGYJuc@)sJS`zO6iME8^$ z%r|OG-oAnK;83mfF8P73PbCsAsd7b|ot%1Uwu^D@kMH_-Db^$?dSz?gsWB|+5T_D3 z^1YXh{+dRD>M4J^An_5&`PR0)5$lu1f4%hY+Y<&o&crlsx9**#1L_Rokw! zpf4;VZ}{f~DlsDO*H`~&U!=OAuUetN91J!>dSHmH-IKr1A>^cE*ZD5Po*nu^=A_$; z!DP>)tdhS^_RpVLgf$?X4|-+d{2Ym$s8d!hN9f5R<}}x zfBTXU0_#>eNI_@b+D5hYU@-arKof{lHIws#eyDcVHB__Ez2y6~iU@tky*GURBoFA| z4vEaLxZQI4q)S0!U`nCdQGcXe{92xW>YSRhiD^{Im0yj;zurcIv688qb)F)T9x~AT z*VDhhr;s;ms5W-3!BWXEl9IpYHxtty^^vI=3e>zzc;Y<49g5<(XQYBz)d|u3o0sTURw5hIyEl5|vD`qa}FTnCLKf zv2}Y8|IV9KHJBQqnZ5`U=e z)yzuO#;-A}6&xX9Zwp9dmI{eag8w;nAQe(%nnDxu&`MnMfLYdM#?kyI&1+ zA^vx7`}v|+S`d?|BZFT_!~8Qg&X-4sySK-@`Eu}ETWgklH!UO8+HAtB+LYk;JCh6o zyXHPp>CX=2zZ>#GGDG3Opq6KrI<2$Jz4Tk<`Q!6T|2PRS-@mjE8;pF%uCHeSHfJ4H zA#DU!()z4D5Pk(D`Y&&+j}+vqbOlU}?D_gb|M;ws@874fGHN1XigTt8aKBaaUOlr$ zd3L9Lk3v+@Ev^Jcd`5wvzP8i!Z*qx_Ah&uH-JyPKS`bgW_*Eq;QH}uh#~||mChPAV zT2&5oNf0{=pWXhwRKIua$G^FFULSwZQs2j*ij&_Z!6r4_VS8s=hHzVS)_1vzi%Tvy)8}c z;&s|ZT+1s+q8S#^ZxsUi&m>v(tHu^>t9GfH+7^(XSKk+ zZ<^2fSM(>{gzmKTJLz}a2l#}DDca3B+`$YZSd9OHBoA9PrBgn>uut)iOrUH@(B90U zpRd@3S*7PleBsq{5@B*un(2(ji2SMw5G2Ykcn5|6+`4P>x1}Q2q03j#_-`T;Il`?i>A*U^&clAW**~-usY4l5)yY$5gRg7*yCrGiy0Aeq*?m$R!c&PTe?(=R_<`8GnU-hlmvII5L(-68jgDa;tZ| z&=XC(w#L3a>dfO^&btf{pjc71TFKw;1f?xMoAh9G&(}sbWK}_*4KKtWVk)Gm?HdSA z?2Wqb>Zx}SG>eJZdz@xOkbHj^ri6C!OTQOpHMlTe(Z+1PqAEU*-G6Z-^)EiRfN zHI6&VE~brPVtS*xIhA?IX=;YR-An7n5!WQSmWwdAW@xT?RtJ>rw!HT9L1KCB1bznY zTkGD8@iBZO5_r06QX;7o(RQY6E++QntQqUmuiwRA5;F=&TR3GhxI9eFFGZ0@&oAod z7?CbtFC&TXu0j&L5bPmTqUB^~DCK1kRe2o4=;yECVi;W++fzCj{o+F}X6obOm|V@7 zxVY2aOE3%;DNyf1jprI4x8Q3jeR

an6)R?YQFZ;0bPIOz)X&DUvwn9f~E7+Fj09 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 literal 0 HcmV?d00001