2022-08-29 13:48:40 +02:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.programs.rust-motd;
|
|
|
|
format = pkgs.formats.toml { };
|
2023-09-21 00:05:35 +02:00
|
|
|
|
|
|
|
orderedSections = listToAttrs
|
|
|
|
(imap0
|
|
|
|
(i: items@{ sectionHeader, ... }: nameValuePair "env${toString i}" {
|
|
|
|
${sectionHeader} = removeAttrs items [ "priority" "sectionHeader" ];
|
|
|
|
})
|
|
|
|
(sortProperties (mapAttrsToList (k: v: v // { sectionHeader = k; }) cfg.settings)));
|
|
|
|
|
|
|
|
# Order the sections in the TOML according to the `priority` field.
|
|
|
|
# This is done by
|
|
|
|
# * creating an attribute set with keys `env0`/`env1`/.../`envN`
|
|
|
|
# where `env0` contains the first section and `envN` the last
|
|
|
|
# (in the form of `{ sectionName = { /* ... */ }}`)
|
|
|
|
# * the declarations of `env0` to `envN` in ascending order are
|
|
|
|
# concatenated with `jq`. Now we have a JSON representation of
|
|
|
|
# the config in the correct order.
|
|
|
|
# * this is piped to `json2toml` to get the correct format for rust-motd.
|
|
|
|
motdConf = pkgs.runCommand "motd.conf"
|
|
|
|
(orderedSections // {
|
|
|
|
__structuredAttrs = true;
|
|
|
|
nativeBuildInputs = [ pkgs.remarshal pkgs.jq ];
|
|
|
|
})
|
|
|
|
''
|
|
|
|
cat "$NIX_BUILD_TOP"/.attrs.json \
|
|
|
|
| jq '${concatMapStringsSep " + " (key: ''."${key}"'') (attrNames orderedSections)}' \
|
|
|
|
| json2toml /dev/stdin "$out"
|
|
|
|
'';
|
2022-08-29 13:48:40 +02:00
|
|
|
in {
|
|
|
|
options.programs.rust-motd = {
|
2022-09-01 19:44:36 +02:00
|
|
|
enable = mkEnableOption (lib.mdDoc "rust-motd");
|
2022-08-29 13:48:40 +02:00
|
|
|
enableMotdInSSHD = mkOption {
|
|
|
|
default = true;
|
|
|
|
type = types.bool;
|
|
|
|
description = mdDoc ''
|
|
|
|
Whether to let `openssh` print the
|
|
|
|
result when entering a new `ssh`-session.
|
|
|
|
By default either nothing or a static file defined via
|
|
|
|
[](#opt-users.motd) is printed. Because of that,
|
|
|
|
the latter option is incompatible with this module.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
refreshInterval = mkOption {
|
|
|
|
default = "*:0/5";
|
|
|
|
type = types.str;
|
|
|
|
description = mdDoc ''
|
|
|
|
Interval in which the {manpage}`motd(5)` file is refreshed.
|
|
|
|
For possible formats, please refer to {manpage}`systemd.time(7)`.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
settings = mkOption {
|
2023-09-21 00:05:35 +02:00
|
|
|
type = types.attrsOf (types.submodule {
|
2022-08-29 13:48:40 +02:00
|
|
|
freeformType = format.type;
|
2023-09-21 00:05:35 +02:00
|
|
|
options.priority = mkOption {
|
|
|
|
type = types.int;
|
|
|
|
default = modules.defaultOrderPriority;
|
|
|
|
description = mdDoc ''
|
|
|
|
In `rust-motd`, the order of the sections in TOML correlates to the order
|
|
|
|
of the items displayed in the resulting `motd`. Attributes in Nix are
|
|
|
|
ordered alphabetically, e.g. `banner` would always be before `uptime`.
|
|
|
|
|
|
|
|
To change that, this option can be used. The lower this number is, the higher
|
|
|
|
is the priority and the more a section is at the top of the message.
|
|
|
|
|
|
|
|
For instance
|
|
|
|
|
|
|
|
```nix
|
|
|
|
{
|
|
|
|
banner.command = "hostname | figlet -f slant";
|
|
|
|
uptime = {
|
|
|
|
prefix = "Up";
|
|
|
|
priority = 0;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
would make the `uptime` appear before the banner.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
});
|
2022-08-29 13:48:40 +02:00
|
|
|
description = mdDoc ''
|
|
|
|
Settings on what to generate. Please read the
|
|
|
|
[upstream documentation](https://github.com/rust-motd/rust-motd/blob/main/README.md#configuration)
|
|
|
|
for further information.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
assertions = [
|
|
|
|
{ assertion = config.users.motd == null;
|
|
|
|
message = ''
|
|
|
|
`programs.rust-motd` is incompatible with `users.motd`!
|
|
|
|
'';
|
|
|
|
}
|
|
|
|
];
|
|
|
|
systemd.services.rust-motd = {
|
|
|
|
path = with pkgs; [ bash ];
|
|
|
|
documentation = [ "https://github.com/rust-motd/rust-motd/blob/v${pkgs.rust-motd.version}/README.md" ];
|
|
|
|
description = "motd generator";
|
2023-09-20 22:16:03 +02:00
|
|
|
wantedBy = [ "multi-user.target" ];
|
2022-08-29 13:48:40 +02:00
|
|
|
serviceConfig = {
|
|
|
|
ExecStart = "${pkgs.writeShellScript "update-motd" ''
|
2023-09-21 00:05:35 +02:00
|
|
|
${pkgs.rust-motd}/bin/rust-motd ${motdConf} > motd
|
2022-08-29 13:48:40 +02:00
|
|
|
''}";
|
|
|
|
CapabilityBoundingSet = [ "" ];
|
|
|
|
LockPersonality = true;
|
|
|
|
MemoryDenyWriteExecute = true;
|
|
|
|
NoNewPrivileges = true;
|
|
|
|
PrivateDevices = true;
|
|
|
|
PrivateTmp = true;
|
|
|
|
ProtectClock = true;
|
|
|
|
ProtectControlGroups = true;
|
|
|
|
ProtectHome = true;
|
|
|
|
ProtectHostname = true;
|
|
|
|
ProtectKernelModules = true;
|
|
|
|
ProtectKernelLogs = true;
|
|
|
|
ProtectKernelTunables = true;
|
|
|
|
ProtectSystem = "full";
|
|
|
|
StateDirectory = "rust-motd";
|
2022-09-18 23:17:50 +02:00
|
|
|
RestrictAddressFamilies = [ "AF_UNIX" ];
|
2022-08-29 13:48:40 +02:00
|
|
|
RestrictNamespaces = true;
|
|
|
|
RestrictRealtime = true;
|
|
|
|
RestrictSUIDSGID = true;
|
|
|
|
RemoveIPC = true;
|
|
|
|
WorkingDirectory = "/var/lib/rust-motd";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
systemd.timers.rust-motd = {
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
timerConfig.OnCalendar = cfg.refreshInterval;
|
|
|
|
};
|
|
|
|
security.pam.services.sshd.text = mkIf cfg.enableMotdInSSHD (mkDefault (mkAfter ''
|
|
|
|
session optional ${pkgs.pam}/lib/security/pam_motd.so motd=/var/lib/rust-motd/motd
|
|
|
|
''));
|
|
|
|
services.openssh.extraConfig = mkIf (cfg.settings ? last_login && cfg.settings.last_login != {}) ''
|
|
|
|
PrintLastLog no
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
meta.maintainers = with maintainers; [ ma27 ];
|
|
|
|
}
|