@@ -79,6 +79,19 @@ in {
7979 for supported values.
8080 '';
8181 };
82+
83+ allowSystemControl = mkOption {
84+ type = types.bool;
85+ default = false;
86+ description = ''
87+ Whether to allow Moonraker to perform system-level operations.
88+
89+ Moonraker exposes APIs to perform system-level operations, such as
90+ reboot, shutdown, and management of systemd units. See the
91+ <link xlink:href="https://moonraker.readthedocs.io/en/latest/web_api/#machine-commands">documentation</link>
92+ for details on what clients are able to do.
93+ '';
94+ };
8295 };
8396 };
8497
@@ -86,6 +99,13 @@ in {
8699 warnings = optional (cfg.settings ? update_manager)
87100 ''Enabling update_manager is not supported on NixOS and will lead to non-removable warnings in some clients.'';
88101
102+ assertions = [
103+ {
104+ assertion = cfg.allowSystemControl -> config.security.polkit.enable;
105+ message = "services.moonraker.allowSystemControl requires polkit to be enabled (security.polkit.enable).";
106+ }
107+ ];
108+
89109 users.users = optionalAttrs (cfg.user == "moonraker") {
90110 moonraker = {
91111 group = cfg.group;
@@ -128,11 +148,31 @@ in {
128148 exec ${pkg}/bin/moonraker -c ${cfg.configDir}/moonraker-temp.cfg
129149 '';
130150
151+ # Needs `ip` command
152+ path = [ pkgs.iproute2 ];
153+
131154 serviceConfig = {
132155 WorkingDirectory = cfg.stateDir;
133156 Group = cfg.group;
134157 User = cfg.user;
135158 };
136159 };
160+
161+ security.polkit.extraConfig = lib.optionalString cfg.allowSystemControl ''
162+ // nixos/moonraker: Allow Moonraker to perform system-level operations
163+ //
164+ // This was enabled via services.moonraker.allowSystemControl.
165+ polkit.addRule(function(action, subject) {
166+ if ((action.id == "org.freedesktop.systemd1.manage-units" ||
167+ action.id == "org.freedesktop.login1.power-off" ||
168+ action.id == "org.freedesktop.login1.power-off-multiple-sessions" ||
169+ action.id == "org.freedesktop.login1.reboot" ||
170+ action.id == "org.freedesktop.login1.reboot-multiple-sessions" ||
171+ action.id.startsWith("org.freedesktop.packagekit.")) &&
172+ subject.user == "${cfg.user}") {
173+ return polkit.Result.YES;
174+ }
175+ });
176+ '';
137177 };
138178}