diff --git a/flake.lock b/flake.lock index 6b7f926..f178a7e 100644 --- a/flake.lock +++ b/flake.lock @@ -302,6 +302,7 @@ "nixpkgs": "nixpkgs_4", "nixpkgs-old": "nixpkgs-old", "nixpkgs-wayland": "nixpkgs-wayland", + "secrets": "secrets", "simple-nixos-mailserver": "simple-nixos-mailserver", "simple-osd-daemons": "simple-osd-daemons", "weechat-notify-send": "weechat-notify-send", @@ -309,6 +310,21 @@ "yt-utilities": "yt-utilities" } }, + "secrets": { + "locked": { + "lastModified": 1610367002, + "narHash": "sha256-u2bwZhhTvXl9XK6EMVRyBiEjs7DDTCx1Nog1mQkB0yQ=", + "ref": "master", + "rev": "77a6f919690c8a0dd383fccdd61f2c7c99fc24cb", + "revCount": 1, + "type": "git", + "url": "ssh://git@github.com/balsoft/pass" + }, + "original": { + "type": "git", + "url": "ssh://git@github.com/balsoft/pass" + } + }, "simple-nixos-mailserver": { "flake": false, "locked": { @@ -333,15 +349,15 @@ "locked": { "lastModified": 1608815402, "narHash": "sha256-oBgd7ZjGho0ivROpc9bIAqN+AbD70HBVWMz36LefK2E=", - "ref": "master", + "owner": "balsoft", + "repo": "simple-osd-daemons", "rev": "dd5883f58c7e49d2b00bd186dfb54afe0dc8fa8a", - "revCount": 20, - "type": "git", - "url": "https://code.balsoft.ru/balsoft/simple-osd-daemons.git" + "type": "github" }, "original": { - "type": "git", - "url": "https://code.balsoft.ru/balsoft/simple-osd-daemons.git" + "owner": "balsoft", + "repo": "simple-osd-daemons", + "type": "github" } }, "weechat-notify-send": { diff --git a/flake.nix b/flake.nix index 33efe06..26ea724 100644 --- a/flake.nix +++ b/flake.nix @@ -45,7 +45,9 @@ ref = "flake"; }; nixos-fhs-compat.url = github:balsoft/nixos-fhs-compat; - simple-osd-daemons.url = git+https://code.balsoft.ru/balsoft/simple-osd-daemons.git; + simple-osd-daemons.url = github:balsoft/simple-osd-daemons; + + secrets.url = git+ssh://git@github.com/balsoft/pass; }; outputs = { nixpkgs, nix, self, ... }@inputs: { diff --git a/hardware-configuration/NixOS-VM.nix b/hardware-configuration/NixOS-VM.nix new file mode 100644 index 0000000..0db3279 --- /dev/null +++ b/hardware-configuration/NixOS-VM.nix @@ -0,0 +1,3 @@ +{ + +} diff --git a/hardware-configuration/iso-image.nix b/hardware-configuration/iso-image.nix new file mode 100644 index 0000000..4e1656c --- /dev/null +++ b/hardware-configuration/iso-image.nix @@ -0,0 +1,9 @@ +{ modulesPath, lib, ... }: { + imports = [ + "${modulesPath}/installer/cd-dvd/installation-cd-minimal.nix" + ]; + networking.wireless.enable = lib.mkForce false; + services.openssh.permitRootLogin = lib.mkForce "no"; + services.mingetty.autologinUser = lib.mkForce "balsoft"; + disabledModules = [ "installer/cd-dvd/channel.nix" ]; +} diff --git a/misc/Passwords.kdbx b/misc/Passwords.kdbx deleted file mode 100644 index 56d1941..0000000 Binary files a/misc/Passwords.kdbx and /dev/null differ diff --git a/modules/applications/firefox.nix b/modules/applications/firefox.nix index 76d32cc..2dca0bd 100644 --- a/modules/applications/firefox.nix +++ b/modules/applications/firefox.nix @@ -6,6 +6,7 @@ in { MOZ_USE_XINPUT2 = "1"; MOZ_DBUS_REMOTE = "1"; }; + programs.browserpass.enable = true; home-manager.users.balsoft = lib.mkIf (config.deviceSpecific.goodMachine) { programs.firefox = { enable = true; @@ -57,6 +58,7 @@ in { close-other-windows adsum-notabs ublock-origin + browserpass ]; }; }; diff --git a/modules/applications/geary.nix b/modules/applications/geary.nix index cae5864..8f46388 100644 --- a/modules/applications/geary.nix +++ b/modules/applications/geary.nix @@ -1,10 +1,10 @@ { config, pkgs, lib, ... }: -let +with import ../../support.nix { inherit lib config; }; let gearyConfig = { Account = { label = ""; ordinal = 6; - prefetch_days = 30; + prefetch_days = -1; save_drafts = true; save_sent = true; sender_mailboxes = "Alexander Bantyev ;"; @@ -65,6 +65,6 @@ in { font-size: 16px; } ''; - xdg.configFile."geary/account_03/geary.ini".text = lib.generators.toGitINI gearyConfig; + xdg.configFile."geary/account_03/geary.ini".text = genIni gearyConfig; }; } diff --git a/modules/applications/weechat.nix b/modules/applications/weechat.nix index 6f67bdd..214c259 100644 --- a/modules/applications/weechat.nix +++ b/modules/applications/weechat.nix @@ -6,17 +6,10 @@ let }; }; in { - home-manager.users.balsoft = { - home.file.".weechat/python/autoload/notify_send.py".source = - "${inputs.weechat-notify-send}/notify_send.py"; - - home.file.".weechat/perl/autoload/multiline.pl".source = - "${inputs.weechat-scripts}/perl/multiline.pl"; - - home.file.".weechat/python/autoload/go.py".source = - "${inputs.weechat-scripts}/python/go.py"; - - home.file.".weechat/plugins.conf".text = '' + secrets-envsubst.weechat = { + owner = "balsoft:users"; + directory = "weechat"; + template = '' [var] python.slack.auto_open_threads = "true" python.slack.background_load_all_history = "true" @@ -46,12 +39,7 @@ in { python.slack.short_buffer_names = "false" python.slack.show_buflist_presence = "true" python.slack.show_reaction_nicks = "true" - python.slack.slack_api_token = "${ - if isNull config.secrets.slack-term then - "" - else - config.secrets.slack-term - }" + python.slack.slack_api_token = "$slack_api_token" python.slack.slack_timeout = "20000" python.slack.switch_buffer_on_join = "true" python.slack.thread_messages_in_channel = "false" @@ -59,6 +47,22 @@ in { python.slack.unfurl_ignore_alt_text = "false" python.slack.unhide_buffers_with_activity = "false" ''; + }; + + home-manager.users.balsoft = { + home.file.".weechat/python/autoload/notify_send.py".source = + "${inputs.weechat-notify-send}/notify_send.py"; + + home.file.".weechat/perl/autoload/multiline.pl".source = + "${inputs.weechat-scripts}/perl/multiline.pl"; + + home.file.".weechat/python/autoload/go.py".source = + "${inputs.weechat-scripts}/python/go.py"; + + home.activation.weechat = '' + $DRY_RUN_CMD mkdir -p $HOME/.weechat + $DRY_RUN_CMD ln -sf $VERBOSE_ARG ${config.secrets-envsubst.weechat} $HOME/.weechat/plugins.conf + ''; home.file.".weechat/weechat.conf".text = '' # diff --git a/modules/applications/yt-utilities.nix b/modules/applications/yt-utilities.nix index bca926f..8179865 100644 --- a/modules/applications/yt-utilities.nix +++ b/modules/applications/yt-utilities.nix @@ -1,8 +1,13 @@ -{ pkgs, config, lib, ... }: lib.mkIf (! isNull config.secrets.yt-utilities) { - home-manager.users.balsoft = { - home.file.".yt.yaml".text = builtins.toJSON { - yt-token = config.secrets.yt-utilities.token; - user = config.secrets.yt-utilities.user; +{ pkgs, config, lib, ... }: { + home-manager.users.balsoft = { + home.activation.yt-config = "$DRY_RUN_CMD ln -sf $VERBOSE_ARG ${config.secrets-envsubst.yt} $HOME/.yt.yaml"; + }; + secrets-envsubst.yt = { + directory = "yt"; + owner = "balsoft:users"; + template = builtins.toJSON { + yt-token = "$user"; + user = "$token"; from = { org = "/home/balsoft/Documents/serokell.org"; full-file = true; diff --git a/modules/default.nix b/modules/default.nix index 0989489..9475211 100755 --- a/modules/default.nix +++ b/modules/default.nix @@ -27,6 +27,7 @@ device: ./themes.nix ./applications.nix ./secrets.nix + ./secrets-envsubst.nix ./devices.nix ./packages.nix ./users.nix @@ -39,7 +40,7 @@ device: ./nextcloud.nix ./mailserver.nix ./matrix-synapse.nix - ./workspace/kanshi.nix + # ./workspace/kanshi.nix ./nginx.nix ./gitea.nix ./minidlna.nix diff --git a/modules/devices.nix b/modules/devices.nix index 0e0d42c..27765a1 100644 --- a/modules/devices.nix +++ b/modules/devices.nix @@ -2,7 +2,7 @@ with lib; with types; { options = { - device = mkOption { type = strMatching "[A-z|0-9]*-(Laptop|Workstation|VM)"; }; + device = mkOption { type = strMatching "[A-z|0-9]*-(Laptop|Workstation|VM|image)"; }; devices = mkOption { type = attrs; }; deviceSpecific = mkOption { type = attrs; }; }; @@ -28,7 +28,6 @@ with types; { T490s-Laptop = { cpu = { vendor = "intel"; - clock = 4600; cores = 4; }; @@ -120,6 +119,19 @@ with types; { }; ram = 4; }; + iso-image = { + cpu = { + vendor = "intel"; + clock = 1000; + cores = 1; + }; + drive = { + type = "ssd"; + speed = 50; + size = 8; + }; + ram = 4; + }; }; }; } diff --git a/modules/hardware.nix b/modules/hardware.nix index 781e471..e90797e 100644 --- a/modules/hardware.nix +++ b/modules/hardware.nix @@ -86,7 +86,7 @@ with deviceSpecific; { }; boot = { - loader = { + loader = lib.mkIf (config.device != "iso-image") ({ timeout = 1; } // (if deviceSpecific.devInfo.legacy or false then { # Non-UEFI config grub.enable = true; @@ -95,7 +95,7 @@ with deviceSpecific; { grub.device = "/dev/sda"; } else { # UEFI config systemd-boot.enable = true; - }); + })); kernelPackages = pkgs.linuxPackages_latest; consoleLogLevel = 3; extraModprobeConfig = '' diff --git a/modules/mailserver.nix b/modules/mailserver.nix index f25cb0d..6eae842 100644 --- a/modules/mailserver.nix +++ b/modules/mailserver.nix @@ -1,13 +1,12 @@ { pkgs, config, lib, inputs, ... }: let module = toString inputs.simple-nixos-mailserver; - readCommandResult = command: - builtins.readFile (pkgs.runCommand "cmd" { preferLocalBuild = true; } - "echo -n $(${command}) > $out"); - hashedPassword = readCommandResult - "${pkgs.mkpasswd}/bin/mkpasswd -m sha-512 '${config.secrets.mail.password}'"; in { imports = [ module ]; + secrets.mailserver = { + owner = "dovecot2:dovecot2"; + services = [ "dovecot2" ]; + }; services.postfix = { dnsBlacklists = [ "all.s5h.net" @@ -72,15 +71,15 @@ in { 192.168.0.0/16 OK ''; }; - mailserver = lib.mkIf (! isNull config.secrets.mail) { + mailserver = { enable = true; - fqdn = config.secrets.mail.host; - domains = [ config.secrets.mail.host ]; + fqdn = "balsoft.ru"; + domains = [ "balsoft.ru" ]; loginAccounts = { "balsoft@balsoft.ru" = { aliases = [ "balsoft" "admin@balsoft.ru" "patches" "patches@balsoft.ru" "issues" "issues@balsoft.ru" "admin" "root@balsoft.ru" "root" ]; - inherit hashedPassword; + hashedPasswordFile = config.secrets.mailserver.decrypted; }; }; localDnsResolver = false; diff --git a/modules/matrix-synapse.nix b/modules/matrix-synapse.nix index b5f0fdd..5dde951 100644 --- a/modules/matrix-synapse.nix +++ b/modules/matrix-synapse.nix @@ -1,4 +1,4 @@ -{ pkgs, config, lib, ... }: lib.mkIf (! isNull config.secrets.matrix) { +{ pkgs, config, lib, ... }: { services.matrix-synapse = { enable = true; allow_guest_access = true; @@ -19,49 +19,191 @@ tls = false; x_forwarded = true; }]; - registration_shared_secret = config.secrets.matrix.shared_secret; public_baseurl = "https://balsoft.ru"; server_name = "balsoft.ru"; app_service_config_files = [ - (builtins.toFile "registration_tg.yaml" - (builtins.toJSON config.secrets.matrix.mautrix-telegram.registration)) - (builtins.toFile "registration_wa.yaml" - (builtins.toJSON config.secrets.matrix.mautrix-whatsapp.registration)) + config.secrets-envsubst.mautrix-telegram-registration.substituted + config.secrets-envsubst.mautrix-whatsapp-registration.substituted ]; }; services.postgresql.enable = true; - home-manager.users.balsoft.xsession.windowManager.i3.config.startup = [{ - command = "anbox launch --package=com.whatsapp --component=.HomeActivity"; - }]; systemd.services.mautrix-whatsapp = { description = "A bridge between whatsapp and matrix"; path = with pkgs; [ coreutils mautrix-whatsapp ]; wantedBy = [ "multi-user.target" ]; - requires = [ - "matrix-synapse.service" - "network-online.target" - ]; + requires = [ "matrix-synapse.service" "network-online.target" ]; serviceConfig = { Restart = "always"; RestartSec = 1; + User = "mautrix-whatsapp"; + StateDirectory = "mautrix-whatsapp"; }; script = '' - mkdir -p /var/lib/mautrix-whatsapp cd /var/lib/mautrix-whatsapp sleep 5 - mautrix-whatsapp -c ${ - builtins.toFile "config_wa.yaml" - (builtins.toJSON config.secrets.matrix.mautrix-whatsapp.config) - } + mautrix-whatsapp -c ${config.secrets-envsubst.mautrix-whatsapp} ''; }; + users.users.mautrix-whatsapp.isSystemUser = true; services.mautrix-telegram = { enable = true; - settings = config.secrets.matrix.mautrix-telegram.config; + environmentFile = toString config.secrets-envsubst.mautrix-telegram; + settings = { + appservice = { + address = "http://localhost:29317"; + bot_avatar = "mxc://maunium.net/tJCRmUyJDsgRNgqhOgoiHWbX"; + id = "telegram"; + max_body_size = 1; + port = 29317; + }; + bridge = { + alias_template = "tg_{groupname}"; + allow_matrix_login = true; + bot_messages_as_notices = true; + catch_up = true; + command_prefix = "!tg"; + image_as_file_size = 10; + max_document_size = 100; + max_initial_member_sync = -1; + max_telegram_delete = 10; + permissions = { + "*" = "relaybot"; + "@balsoft:balsoft.ru" = "admin"; + }; + plaintext_highlights = true; + startup_sync = true; + username_template = "tg_{userid}"; + }; + homeserver = { + address = "https://matrix.balsoft.ru"; + domain = "balsoft.ru"; + verify_ssl = true; + }; + telegram = { bot_token = "disabled"; }; + }; }; - systemd.services.mautrix-telegram.serviceConfig.DynamicUser = lib.mkForce false; + secrets-envsubst.mautrix-telegram = { + directory = "mautrix-telegram"; + template = '' + MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=$as_token + MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=$hs_token + MAUTRIX_TELEGRAM_TELEGRAM_API_ID=$api_id + MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=$api_hash + ''; + }; + + secrets-envsubst.mautrix-telegram-registration = { + directory = "mautrix-telegram"; + owner = "matrix-synapse"; + template = builtins.toJSON { + as_token = "$as_token"; + hs_token = "$hs_token"; + id = "telegram"; + namespaces = { + aliases = [{ + exclusive = true; + regex = "#tg_.+:balsoft.ru"; + }]; + users = [{ + exclusive = true; + regex = "@tg_.+:balsoft.ru"; + }]; + }; + rate_limited = false; + sender_localpart = "telegrambot"; + url = "http://localhost:29317"; + }; + }; + + secrets-envsubst.mautrix-whatsapp = { + directory = "mautrix-whatsapp"; + owner = "mautrix-whatsapp"; + template = builtins.toJSON { + appservice = { + address = "http://localhost:29318"; + as_token = "$as_token"; + bot = { + avatar = "mxc://maunium.net/NeXNQarUbrlYBiPCpprYsRqr"; + displayname = "WhatsApp bridge bot"; + username = "whatsappbot"; + }; + database = { + max_idle_conns = 2; + max_open_conns = 20; + type = "sqlite3"; + uri = "mautrix-whatsapp.db"; + }; + hostname = "0.0.0.0"; + hs_token = "$hs_token"; + id = "whatsapp"; + port = 29318; + state_store_path = "./mx-state.json"; + }; + bridge = { + command_prefix = "!wa"; + connection_retry_delay = -1; + connection_timeout = 20; + contact_wait_delay = 1; + displayname_template = + "{{if .Notify}}{{.Notify}}{{else}}{{.Jid}}{{end}} (WA)"; + initial_chat_sync_count = 10; + initial_history_fill_count = 20; + invite_own_puppet_for_backfilling = true; + max_connection_attempts = 3; + permissions = { + "*" = 10; + "@balsoft:balsoft.ru" = 100; + }; + private_chat_portal_meta = false; + recovery_chat_sync_count = -1; + recovery_history_backfill = true; + report_connection_retry = true; + sync_max_chat_age = 259200; + sync_with_custom_puppets = true; + username_template = "whatsapp_{{.}}"; + }; + homeserver = { + address = "http://localhost:13748"; + domain = "balsoft.ru"; + }; + logging = { + directory = "./logs"; + file_date_format = "2006-01-02"; + file_mode = 384; + file_name_format = "{{.Date}}-{{.Index}}.log"; + print_level = "debug"; + timestamp_format = "Jan _2, 2006 15:04:05"; + }; + }; + }; + + secrets-envsubst.mautrix-whatsapp-registration = { + directory = "mautrix-whatsapp"; + owner = "matrix-synapse"; + template = builtins.toJSON { + as_token = "$as_token"; + hs_token = "$hs_token"; + id = "whatsapp"; + namespaces = { + users = [{ + exclusive = true; + regex = "^@whatsapp_[0-9]+:balsoft.ru$"; + }]; + }; + rate_limited = false; + sender_localpart = "whatsappbot"; + url = "http://localhost:29318"; + }; + }; + + systemd.services.mautrix-telegram.serviceConfig.DynamicUser = + lib.mkForce false; + + systemd.services.mautrix-telegram.serviceConfig.User = "mautrix-telegram"; + + users.users.mautrix-telegram.isSystemUser = true; users.users.matrix-synapse.name = lib.mkForce "matrix-synapse"; } diff --git a/modules/nextcloud.nix b/modules/nextcloud.nix index e2d19d7..0007517 100644 --- a/modules/nextcloud.nix +++ b/modules/nextcloud.nix @@ -3,10 +3,14 @@ services.nextcloud = { enable = true; hostName = "nextcloud.balsoft.ru"; - config.adminpassFile = "/home/balsoft/nextcloud-admin"; + config.adminpassFile = config.secrets.nextcloud.decrypted; package = pkgs.nextcloud20; https = true; }; + secrets.nextcloud = { + owner = "nextcloud:nextcloud"; + services = [ "nextcloud-setup" ]; + }; services.nginx.virtualHosts."nextcloud.balsoft.ru" = { enableACME = true; forceSSL = true; diff --git a/modules/secrets-envsubst.nix b/modules/secrets-envsubst.nix new file mode 100644 index 0000000..de7f10d --- /dev/null +++ b/modules/secrets-envsubst.nix @@ -0,0 +1,107 @@ +{ pkgs, config, lib, inputs, ... }: +with lib; +with types; +let + envsubstSecrets = { name, ... }: { + options = { + directory = mkOption { type = str; }; + template = mkOption { type = str; }; + prefix = mkOption { + type = nullOr str; + default = null; + }; + substituted = mkOption { + type = path; + default = "/var/secrets/${name}-envsubst"; + }; + envsubst = mkOption { + type = str; + default = "${pkgs.envsubst}/bin/envsubst -no-unset -no-empty"; + }; + owner = mkOption { + type = str; + default = "root:root"; + }; + permissions = mkOption { + type = lib.types.addCheck lib.types.str + (perm: !isNull (builtins.match "[0-7]{3}" perm)); + default = "400"; + }; + services = mkOption { + type = listOf str; + default = [ "${name}.service" ]; + }; + __toString = mkOption { + readOnly = true; + default = s: s.substituted; + }; + }; + }; + + individualSecrets = name: cfg: + map (x: builtins.elemAt (builtins.match "(.*).gpg" x) 0) (builtins.attrNames (lib.filterAttrs (n: v: v == "regular" || v == "symlink") + (builtins.readDir (inputs.secrets + "/${cfg.directory}")))); + + exportSecrets = name: cfg: + let prefix = lib.optionalString (!isNull cfg.prefix) "${cfg.prefix}_"; + in map (secret: + '' + export ${prefix}${secret}="$(cat ${ + config.secrets."${name}-envsubst-${secret}".decrypted + })"'') (individualSecrets name cfg); + + envsubst = name: cfg: + with cfg; { + "${name}-envsubst" = rec { + + wantedBy = [ "multi-user.target" ]; + + requires = [ "user@1000.service" "gpg-setup.service" ] + ++ map (secret: "${name}-envsubst-${secret}-secrets.service") (individualSecrets name cfg); + after = requires; + + preStart = "mkdir -p '${builtins.dirOf substituted}'"; + + script = '' + ${builtins.concatStringsSep "\n" (exportSecrets name cfg)} + + if cat '${builtins.toFile "template" template}' | ${cfg.envsubst} > '${substituted}.tmp'; then + mv -f '${substituted}.tmp' '${substituted}' + chown '${owner}' '${substituted}' + chmod '${permissions}' '${substituted}' + else + echo "Failed to run the substition" + rm '${substituted}.tmp' + fi + ''; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = "yes"; + }; + }; + }; + + addDependencies = name: cfg: + with cfg; + genAttrs services (service: rec { + requires = [ "${name}-envsubst" ]; + after = requires; + }); + mkServices = name: cfg: [ (envsubst name cfg) (addDependencies name cfg) ]; + + mkIndividualSecrets = name: cfg: + map (x: { + "${name}-envsubst-${x}" = { + encrypted = inputs.secrets + "/${cfg.directory}/${x}.gpg"; + services = [ ]; + }; + }) (individualSecrets name cfg); +in { + options.secrets-envsubst = + lib.mkOption { type = attrsOf (submodule envsubstSecrets); }; + config.systemd.services = + mkMerge (concatLists (mapAttrsToList mkServices config.secrets-envsubst)); + config.secrets = mkMerge + (concatLists (mapAttrsToList mkIndividualSecrets config.secrets-envsubst)); +} diff --git a/modules/secrets.nix b/modules/secrets.nix index 1de074c..ff23d5d 100755 --- a/modules/secrets.nix +++ b/modules/secrets.nix @@ -2,98 +2,161 @@ with lib; with types; let - secret = description: - mkOption { - inherit description; - type = nullOr str; - }; - mkCredOption = service: extra: - mkOption { - description = "Credentials for ${service}"; - type = nullOr (submodule { - options = { - user = mkOption { - type = str; - description = "Username for ${service}"; - }; - password = mkOption { - type = str; - description = "Password for ${service}"; - }; - } // extra; - }); - }; -in rec { - options.secrets = { - slack-term = secret "slack token"; - yt-utilities = mkOption { - description = "youtrack"; - type = nullOr (submodule { - options = { - user = secret "youtrack user"; - url = secret "youtrack url"; - token = secret "youtrack token"; - }; - }); - }; - wage = secret "wage (sum CURRENCY/TIME, like 10EUR/h)"; - gcal = mkOption { - description = "Google calendar auth"; - type = nullOr (submodule { - options = { - email = mkOption { type = lib.types.str; }; - client-id = mkOption { type = lib.types.str; }; - client-secret = mkOption { type = lib.types.str; }; - refresh-token = mkOption { type = lib.types.str; }; - }; - }); - }; - mail = mkCredOption "email" { - host = mkOption { + secret = { name, ... }: { + options = { + encrypted = mkOption { + type = path; + default = inputs.secrets + "/${name}.gpg"; + }; + decrypted = mkOption { + type = path; + default = "/var/secrets/${name}"; + }; + decrypt = mkOption { + default = pkgs.writeShellScript "gpg-decrypt" '' + set -euo pipefail + export GPG_TTY="$(tty)" + ${pkgs.gnupg}/bin/gpg-connect-agent updatestartuptty /bye 1>&2 + ${pkgs.gnupg}/bin/gpg --batch --no-tty --decrypt + ''; + }; + user = mkOption { type = str; - description = "Mail server"; + default = "balsoft"; }; - }; - openvpn = mkCredOption "openvpn" { }; - rclone = mkOption { - type = nullOr str; - description = "Rclone config"; - }; - ssl = mkOption { - description = "Certs"; - type = nullOr (submodule { - options = { - cert = mkOption { - type = nullOr str; - description = "SSL certificate"; - }; - priv = mkOption { - type = nullOr str; - description = "SSL RSA private key"; - }; - }; - }); - }; - matrix = mkCredOption "matrix" rec { - shared_secret = mkOption { - type = nullOr str; - description = "A shared secret for matrix instance"; + owner = mkOption { + type = str; + default = "root:root"; }; - mautrix-whatsapp = { - config = mkOption { type = attrs; }; - registration = mkOption { type = attrs; }; + permissions = mkOption { + type = lib.types.addCheck lib.types.str + (perm: !isNull (builtins.match "[0-7]{3}" perm)); + default = "400"; + }; + services = mkOption { + type = listOf str; + default = [ "${name}.service" ]; + }; + __toString = mkOption { + readOnly = true; + default = s: s.decrypted; }; - mautrix-telegram = mautrix-whatsapp; }; }; - config = let - unlocked = import (pkgs.runCommand "check-secret" { } - "set +e; grep -qI . ${../secret.nix}; echo $? > $out") == 0; - secretnix = import ../secret.nix; - secrets = if !unlocked || isNull secretnix then - builtins.trace "secret.nix locked, building without any secrets" - (mapAttrs (n: v: null) options.secrets) - else - secretnix; - in { inherit secrets; }; + + decrypt = name: cfg: + with cfg; { + "${name}-secrets" = rec { + + wantedBy = [ "multi-user.target" ]; + + requires = [ "user@1000.service" "gpg-setup.service" ]; + after = requires; + + preStart = '' + [[ -r '${encrypted}' ]] + mkdir -p '${builtins.dirOf decrypted}' + ''; + + script = '' + ${optionalString (pkgs.gnupg.version == "2.2.24") + "/run/wrappers/bin/sudo -u ${user} ${pkgs.gnupg}/bin/gpg --card-status" + # 2.2.24 is broken and needs this hack for yubi to work + } + + if cat '${encrypted}' | /run/wrappers/bin/sudo -u ${user} ${cfg.decrypt} > '${decrypted}.tmp'; then + mv -f '${decrypted}.tmp' '${decrypted}' + chown '${owner}' '${decrypted}' + chmod '${permissions}' '${decrypted}' + else + echo "Failed to decrypt the secret" + rm '${decrypted}.tmp' + fi + ''; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = "yes"; + }; + + unitConfig = { + ConditionPathExists = [ + "/run/user/${ + toString config.users.users.${user}.uid + }/gnupg/S.gpg-agent" + ]; + }; + + }; + }; + + addDependencies = name: cfg: + with cfg; + genAttrs services (service: rec { + requires = [ "${name}-secrets" ]; + after = requires; + }); + + gpg-setup = rec { + + wantedBy = [ "multi-user.target" ]; + + requires = [ "user@1000.service" ]; + after = requires; + + path = [ pkgs.gnupg ]; + + script = "echo fetch | gpg --card-edit --no-tty --command-fd=0"; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = "yes"; + User = "balsoft"; + }; + }; + + mkServices = name: cfg: [ (decrypt name cfg) (addDependencies name cfg) ]; +in { + options.secrets = lib.mkOption { type = attrsOf (submodule secret); }; + config.systemd.services = mkMerge ([{ inherit gpg-setup; }] + ++ concatLists (mapAttrsToList mkServices config.secrets)); + + config.home-manager.users.balsoft = { + systemd.user.services.pass-sync = { + Install.WantedBy = + [ "sway-session.target" ]; # Start when the gpg agent is ready + + Service = { + ExecStartPre = toString (pkgs.writeShellScript "clone-pass-repo" '' + set -euo pipefail + + ''); + ExecStart = toString (pkgs.writeShellScript "pass-sync" '' + set -euo pipefail + cd $HOME/.password-store + while ${pkgs.inotifyTools}/bin/inotifywait "$HOME/.password-store/.git" -r -e modify -e close_write -e move -e create -e delete; do + sleep 0.5 + ${pkgs.git}/bin/git push + done + ''); + }; + }; + wayland.windowManager.sway = { + config.startup = [{ + command = toString (pkgs.writeShellScript "activate-secrets" '' + set -euo pipefail + # Make sure card is available and unlocked + ${pkgs.gnupg}/bin/gpg --card-status + cat ${inputs.secrets}/email/balsoft@balsoft.ru.gpg | ${pkgs.gnupg}/bin/gpg --decrypt + systemctl restart '*-secrets.service' '*-envsubst.service' + if [ -d "$HOME/.password-store" ]; then + cd "$HOME/.password-store"; ${pkgs.git}/bin/git pull + else + ${pkgs.git}/bin/git clone ssh://git@github.com/balsoft/pass "$HOME/.password-store" + fi + ln -sf ${pkgs.writeShellScript "push" "${pkgs.git}/bin/git push origin master"} "$HOME/.password-store/.git/hooks/post-commit" + ''); + }]; + }; + }; } diff --git a/modules/users.nix b/modules/users.nix index 31d7b6f..b2515ff 100644 --- a/modules/users.nix +++ b/modules/users.nix @@ -30,8 +30,10 @@ systemd.services."user@" = { serviceConfig = { Restart = "always"; }; }; home-manager.users.balsoft.home.activation.yubi = { - data = - "[ -s /home/balsoft/.config/Yubico/u2f_keys ] || (pamu2fcfg > /home/balsoft/.config/Yubico/u2f_keys)"; + data = '' + mkdir -p .config/Yubico + [ -f /home/balsoft/.config/Yubico/u2f_keys ] || (pamu2fcfg > /home/balsoft/.config/Yubico/u2f_keys) + ''; after = [ "linkGeneration" ]; before = [ ]; }; @@ -55,11 +57,12 @@ environment.systemPackages = [ (pkgs.writeShellScriptBin "lock" '' + set -euo pipefail if [[ "$1" == this ]] then args="-s" else args="-san" fi - USER=balsoft ${pkgs.vlock}/bin/vlock "$args" + ${lib.optionalString (config.deviceSpecific.isLaptop) ''USER=balsoft ${pkgs.vlock}/bin/vlock "$args"''} '') ]; diff --git a/modules/workspace/fonts.nix b/modules/workspace/fonts.nix index 48d4185..412f445 100644 --- a/modules/workspace/fonts.nix +++ b/modules/workspace/fonts.nix @@ -9,7 +9,7 @@ material-icons ]; fontconfig = { - enable = true; + enable = lib.mkForce true; defaultFonts = { monospace = [ "IBM Plex Mono 13" ]; sansSerif = [ "IBM Plex Sans 13" ]; diff --git a/modules/workspace/i3blocks/default.nix b/modules/workspace/i3blocks/default.nix index b184d0b..39ae5b7 100644 --- a/modules/workspace/i3blocks/default.nix +++ b/modules/workspace/i3blocks/default.nix @@ -3,6 +3,11 @@ with import ../../../support.nix { inherit pkgs config lib; }; with lib; let scripts = import ./scripts pkgs config; in { + secrets.wage = { + owner = "balsoft:users"; + services = [ ]; + }; + home-manager.users.balsoft = { wayland.windowManager.sway.config.bars = [{ id = "default"; @@ -39,10 +44,10 @@ in { in '' interval=60 markup=pango - '' + genIniOrdered (optional (!isNull config.secrets.mail) (scr "email") + '' + genIniOrdered ([] + # (scr "email") ++ [ (scrint "weather" 600) (scr "emacs") (scr "nixos") ] - ++ optional (!isNull config.secrets.wage) (scrint "youtrack-wage" 3600) - ++ [ (scrint "music" 3) (scrint "sound" 1) ] ++ [ + ++ [ (scrint "youtrack-wage" 3600) (scrint "music" 3) (scrint "sound" 1) ] ++ [ (scrint "cpu" 5) (scrint "freq" 10) (scr "temperature") diff --git a/modules/workspace/i3blocks/scripts/youtrack-wage.nix b/modules/workspace/i3blocks/scripts/youtrack-wage.nix index c31ee75..5b08e62 100644 --- a/modules/workspace/i3blocks/scripts/youtrack-wage.nix +++ b/modules/workspace/i3blocks/scripts/youtrack-wage.nix @@ -5,17 +5,18 @@ in #!${bash}/bin/bash set -euo pipefail export PATH="$PATH:${yt-utilities}/bin:${ec}/bin:${libqalculate}/bin" + WAGE=$(cat ${config.secrets.wage.decrypted}) HOURS_MONTH=$(yt org local --since $(date +'%Y-%m-01') | tail -1) - MONEY_MONTH=$(qalc -t "($HOURS_MONTH) * (${config.secrets.wage})") + MONEY_MONTH=$(qalc -t "($HOURS_MONTH) * $WAGE") '' + (if config.deviceSpecific.bigScreen then '' HOURS_DAY=$(yt org local --since $(date +'%Y-%m-%d') | tail -1) HOURS_YEAR=$(yt org local --since $(date +'%Y-01-01') | tail -1) - MONEY_DAY=$(qalc -t "($HOURS_DAY) * (${config.secrets.wage})") - MONEY_YEAR=$(qalc -t "($HOURS_YEAR) * (${config.secrets.wage})") + MONEY_DAY=$(qalc -t "($HOURS_DAY) * $WAGE") + MONEY_YEAR=$(qalc -t "($HOURS_YEAR) * $WAGE") TASK=$(emacsclient --eval "org-mode-line-string" 2>/dev/null || echo -n none) if ! [[ "$TASK" == "none" ]]; then HOURS_TASK=$(echo "$TASK" | head -1 | cut -d\" -f 2 | cut -d\[ -f2 | cut -d\] -f1)h - MONEY_TASK=$(qalc -t -e "$HOURS_TASK * (${config.secrets.wage})" ) + MONEY_TASK=$(qalc -t -e "$HOURS_TASK * $WAGE" ) echo "$MONEY_TASK/$MONEY_DAY($HOURS_DAY)/$MONEY_MONTH($HOURS_MONTH)/$MONEY_YEAR" else echo "$MONEY_DAY($HOURS_DAY)/$MONEY_MONTH($HOURS_MONTH)/$MONEY_YEAR" diff --git a/modules/workspace/sway/default.nix b/modules/workspace/sway/default.nix index e212d57..896efbd 100755 --- a/modules/workspace/sway/default.nix +++ b/modules/workspace/sway/default.nix @@ -85,10 +85,6 @@ in { command = "${pkgs.mate.mate-polkit}/libexec/polkit-mate-authentication-agent-1"; } - { - command = - "${pkgs.keepassxc}/bin/keepassxc /home/balsoft/projects/nixos-config/misc/Passwords.kdbx"; - } { command = "${pkgs.spectral}/bin/spectral"; } { command = "${pkgs.xorg.xrdb}/bin/xrdb -merge ~/.Xresources"; } diff --git a/secret.nix b/secret.nix deleted file mode 100644 index 92408e0..0000000 Binary files a/secret.nix and /dev/null differ