mirror of
https://github.com/ilyakooo0/nixpkgs.git
synced 2025-01-01 16:34:15 +03:00
keyd: add keyd service and test
The keyd package already exists, but without a systemd service. Keyd requires write access to /var/run to create its socket. Currently the directory it uses can be changed with an environment variable, but the keyd repo state suggests that this may turn into a compile-time option. with that set, and some supplementary groups added, we can run the service under DynamicUser. Co-authored-by: pennae <82953136+pennae@users.noreply.github.com>
This commit is contained in:
parent
a747c1d841
commit
296e7f92cd
@ -59,6 +59,8 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||
|
||||
- [QDMR](https://dm3mat.darc.de/qdmr/), a GUI application and command line tool for programming DMR radios [programs.qdmr](#opt-programs.qdmr.enable)
|
||||
|
||||
- [keyd](https://github.com/rvaiya/keyd), a key remapping daemon for linux. Available as [services.keyd](#opt-services.keyd.enable).
|
||||
|
||||
- [v2rayA](https://v2raya.org), a Linux web GUI client of Project V which supports V2Ray, Xray, SS, SSR, Trojan and Pingtunnel. Available as [services.v2raya](options.html#opt-services.v2raya.enable).
|
||||
|
||||
- [ulogd](https://www.netfilter.org/projects/ulogd/index.html), a userspace logging daemon for netfilter/iptables related logging. Available as [services.ulogd](options.html#opt-services.ulogd.enable).
|
||||
|
@ -511,6 +511,7 @@
|
||||
./services/hardware/usbmuxd.nix
|
||||
./services/hardware/usbrelayd.nix
|
||||
./services/hardware/vdr.nix
|
||||
./services/hardware/keyd.nix
|
||||
./services/home-automation/evcc.nix
|
||||
./services/home-automation/home-assistant.nix
|
||||
./services/home-automation/zigbee2mqtt.nix
|
||||
|
112
nixos/modules/services/hardware/keyd.nix
Normal file
112
nixos/modules/services/hardware/keyd.nix
Normal file
@ -0,0 +1,112 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.services.keyd;
|
||||
settingsFormat = pkgs.formats.ini { };
|
||||
in
|
||||
{
|
||||
options = {
|
||||
services.keyd = {
|
||||
enable = mkEnableOption (lib.mdDoc "keyd, a key remapping daemon");
|
||||
|
||||
ids = mkOption {
|
||||
type = types.listOf types.string;
|
||||
default = [ "*" ];
|
||||
example = [ "*" "-0123:0456" ];
|
||||
description = lib.mdDoc ''
|
||||
Device identifiers, as shown by {manpage}`keyd(1)`.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
type = settingsFormat.type;
|
||||
default = { };
|
||||
example = {
|
||||
main = {
|
||||
capslock = "overload(control, esc)";
|
||||
rightalt = "layer(rightalt)";
|
||||
};
|
||||
|
||||
rightalt = {
|
||||
j = "down";
|
||||
k = "up";
|
||||
h = "left";
|
||||
l = "right";
|
||||
};
|
||||
};
|
||||
description = lib.mdDoc ''
|
||||
Configuration, except `ids` section, that is written to {file}`/etc/keyd/default.conf`.
|
||||
See <https://github.com/rvaiya/keyd> how to configure.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.etc."keyd/default.conf".source = pkgs.runCommand "default.conf"
|
||||
{
|
||||
ids = ''
|
||||
[ids]
|
||||
${concatStringsSep "\n" cfg.ids}
|
||||
'';
|
||||
passAsFile = [ "ids" ];
|
||||
} ''
|
||||
cat $idsPath <(echo) ${settingsFormat.generate "keyd-main.conf" cfg.settings} >$out
|
||||
'';
|
||||
|
||||
hardware.uinput.enable = lib.mkDefault true;
|
||||
|
||||
systemd.services.keyd = {
|
||||
description = "Keyd remapping daemon";
|
||||
documentation = [ "man:keyd(1)" ];
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
restartTriggers = [
|
||||
config.environment.etc."keyd/default.conf".source
|
||||
];
|
||||
|
||||
# this is configurable in 2.4.2, later versions seem to remove this option.
|
||||
# post-2.4.2 may need to set makeFlags in the derivation:
|
||||
#
|
||||
# makeFlags = [ "SOCKET_PATH/run/keyd/keyd.socket" ];
|
||||
environment.KEYD_SOCKET = "/run/keyd/keyd.sock";
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.keyd}/bin/keyd";
|
||||
Restart = "always";
|
||||
|
||||
DynamicUser = true;
|
||||
SupplementaryGroups = [
|
||||
config.users.groups.input.name
|
||||
config.users.groups.uinput.name
|
||||
];
|
||||
|
||||
RuntimeDirectory = "keyd";
|
||||
|
||||
# Hardening
|
||||
CapabilityBoundingSet = "";
|
||||
DeviceAllow = [
|
||||
"char-input rw"
|
||||
"/dev/uinput rw"
|
||||
];
|
||||
ProtectClock = true;
|
||||
PrivateNetwork = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
PrivateUsers = true;
|
||||
PrivateMounts = true;
|
||||
RestrictNamespaces = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectControlGroups = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
RestrictRealtime = true;
|
||||
LockPersonality = true;
|
||||
ProtectProc = "noaccess";
|
||||
UMask = "0077";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -346,6 +346,7 @@ in {
|
||||
keter = handleTest ./keter.nix {};
|
||||
kexec = handleTest ./kexec.nix {};
|
||||
keycloak = discoverTests (import ./keycloak.nix);
|
||||
keyd = handleTest ./keyd.nix {};
|
||||
keymap = handleTest ./keymap.nix {};
|
||||
knot = handleTest ./knot.nix {};
|
||||
komga = handleTest ./komga.nix {};
|
||||
|
82
nixos/tests/keyd.nix
Normal file
82
nixos/tests/keyd.nix
Normal file
@ -0,0 +1,82 @@
|
||||
# The test template is taken from the `./keymap.nix`
|
||||
{ system ? builtins.currentSystem
|
||||
, config ? { }
|
||||
, pkgs ? import ../.. { inherit system config; }
|
||||
}:
|
||||
|
||||
with import ../lib/testing-python.nix { inherit system pkgs; };
|
||||
|
||||
let
|
||||
readyFile = "/tmp/readerReady";
|
||||
resultFile = "/tmp/readerResult";
|
||||
|
||||
testReader = pkgs.writeScript "test-input-reader" ''
|
||||
rm -f ${resultFile} ${resultFile}.tmp
|
||||
logger "testReader: START: Waiting for $1 characters, expecting '$2'."
|
||||
touch ${readyFile}
|
||||
read -r -N $1 chars
|
||||
rm -f ${readyFile}
|
||||
if [ "$chars" == "$2" ]; then
|
||||
logger -s "testReader: PASS: Got '$2' as expected." 2>${resultFile}.tmp
|
||||
else
|
||||
logger -s "testReader: FAIL: Expected '$2' but got '$chars'." 2>${resultFile}.tmp
|
||||
fi
|
||||
# rename after the file is written to prevent a race condition
|
||||
mv ${resultFile}.tmp ${resultFile}
|
||||
'';
|
||||
|
||||
|
||||
mkKeyboardTest = name: { settings, test }: with pkgs.lib; makeTest {
|
||||
inherit name;
|
||||
|
||||
nodes.machine = {
|
||||
services.keyd = {
|
||||
enable = true;
|
||||
inherit settings;
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
import shlex
|
||||
|
||||
machine.wait_for_unit("keyd.service")
|
||||
|
||||
def run_test_case(cmd, test_case_name, inputs, expected):
|
||||
with subtest(test_case_name):
|
||||
assert len(inputs) == len(expected)
|
||||
machine.execute("rm -f ${readyFile} ${resultFile}")
|
||||
# set up process that expects all the keys to be entered
|
||||
machine.succeed(
|
||||
"{} {} {} {} >&2 &".format(
|
||||
cmd,
|
||||
"${testReader}",
|
||||
len(inputs),
|
||||
shlex.quote("".join(expected)),
|
||||
)
|
||||
)
|
||||
# wait for reader to be ready
|
||||
machine.wait_for_file("${readyFile}")
|
||||
# send all keys
|
||||
for key in inputs:
|
||||
machine.send_key(key)
|
||||
# wait for result and check
|
||||
machine.wait_for_file("${resultFile}")
|
||||
machine.succeed("grep -q 'PASS:' ${resultFile}")
|
||||
test = ${builtins.toJSON test}
|
||||
run_test_case("openvt -sw --", "${name}", test["press"], test["expect"])
|
||||
'';
|
||||
};
|
||||
|
||||
in
|
||||
pkgs.lib.mapAttrs mkKeyboardTest {
|
||||
swap-ab_and_ctrl-as-shift = {
|
||||
test.press = [ "a" "ctrl-b" "c" ];
|
||||
test.expect = [ "b" "A" "c" ];
|
||||
|
||||
settings.main = {
|
||||
"a" = "b";
|
||||
"b" = "a";
|
||||
"control" = "oneshot(shift)";
|
||||
};
|
||||
};
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
, systemd
|
||||
, runtimeShell
|
||||
, python3
|
||||
, nixosTests
|
||||
}:
|
||||
|
||||
let
|
||||
@ -59,11 +60,16 @@ stdenv.mkDerivation rec {
|
||||
|
||||
enableParallelBuilding = true;
|
||||
|
||||
# post-2.4.2 may need this to unbreak the test
|
||||
# makeFlags = [ "SOCKET_PATH/run/keyd/keyd.socket" ];
|
||||
|
||||
postInstall = ''
|
||||
ln -sf ${lib.getExe appMap} $out/bin/${appMap.pname}
|
||||
rm -rf $out/etc
|
||||
'';
|
||||
|
||||
passthru.tests.keyd = nixosTests.keyd;
|
||||
|
||||
meta = with lib; {
|
||||
description = "A key remapping daemon for linux.";
|
||||
license = licenses.mit;
|
||||
|
Loading…
Reference in New Issue
Block a user