commit 5f271a7194fed58f89443ce2331adf2f3e5e6707 Author: Konstantin Nazarov Date: Sun Jul 30 17:18:49 2023 +0100 Initial release of my NixOS configuration 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 0000000..88495da Binary files /dev/null and b/wallpaper.jpg differ