Finally switch to new secret management system

This commit is contained in:
Alexander Bantyev 2021-01-11 17:09:34 +03:00
parent fd0ab95c95
commit e9a30398db
Signed by: balsoft
GPG Key ID: E081FF12ADCB4AD5
23 changed files with 544 additions and 170 deletions

28
flake.lock generated
View File

@ -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": {

View File

@ -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: {

View File

@ -0,0 +1,3 @@
{
}

View File

@ -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" ];
}

Binary file not shown.

View File

@ -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
];
};
};

View File

@ -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 <balsoft@balsoft.ru>;";
@ -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;
};
}

View File

@ -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 = ''
#

View File

@ -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;

View File

@ -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

View File

@ -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;
};
};
};
}

View File

@ -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 = ''

View File

@ -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;

View File

@ -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";
}

View File

@ -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;

View File

@ -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));
}

View File

@ -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"
'');
}];
};
};
}

View File

@ -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"''}
'')
];

View File

@ -9,7 +9,7 @@
material-icons
];
fontconfig = {
enable = true;
enable = lib.mkForce true;
defaultFonts = {
monospace = [ "IBM Plex Mono 13" ];
sansSerif = [ "IBM Plex Sans 13" ];

View File

@ -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")

View File

@ -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"

View File

@ -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"; }

Binary file not shown.