add overlays, pkgs

This commit is contained in:
2023-07-13 13:09:17 +02:00
parent c7aef44265
commit e21a47a2b5
34 changed files with 8812 additions and 2 deletions

View File

@@ -0,0 +1,135 @@
{ stdenv
, lib
, bzip2
, fetchFromGitHub
, fetchurl
, fmt
, gettext
, inih
, installShellFiles
, libevdev
, meson
, ninja
, pam
, pkg-config
, python3
}:
let
data = let
baseurl = "https://github.com/davisking/dlib-models/raw/daf943f7819a3dda8aec4276754ef918dc26491f";
in {
"dlib_face_recognition_resnet_model_v1.dat" = fetchurl {
url = "${baseurl}/dlib_face_recognition_resnet_model_v1.dat.bz2";
sha256 = "0fjm265l1fz5zdzx5n5yphl0v0vfajyw50ffamc4cd74848gdcdb";
};
"mmod_human_face_detector.dat" = fetchurl {
url = "${baseurl}/mmod_human_face_detector.dat.bz2";
sha256 = "117wv582nsn585am2n9mg5q830qnn8skjr1yxgaiihcjy109x7nv";
};
"shape_predictor_5_face_landmarks.dat" = fetchurl {
url = "${baseurl}/shape_predictor_5_face_landmarks.dat.bz2";
sha256 = "0wm4bbwnja7ik7r28pv00qrl3i1h6811zkgnjfvzv7jwpyz7ny3f";
};
};
py = python3.withPackages (p: [
p.face_recognition
(p.opencv4.override { enableGtk3 = true; })
]);
in
stdenv.mkDerivation {
pname = "howdy";
version = "unstable-2023-02-28";
src = fetchFromGitHub {
owner = "boltgolt";
repo = "howdy";
rev = "e881cc25935c7d39a074e9701a06b1fce96cc185";
hash = "sha256-BHS1J0SUNbCeAnTXrOQCtBJTaSYa5jtYYtTgfycv7VM=";
};
patches = [
# Change directory with configuration from `/etc` to `/var/lib`, since the service is expected to modify it.
./howdy.patch
];
postPatch =
let
howdypath = "${placeholder "out"}/lib/security/howdy";
in
''
substituteInPlace howdy/src/cli/add.py --replace "@pkgdatadir@" "${howdypath}"
substituteInPlace howdy/src/cli/config.py --replace '/bin/nano' 'nano'
substituteInPlace howdy/src/cli/test.py --replace "@pkgdatadir@" "${howdypath}"
substituteInPlace howdy/src/pam/main.cc \
--replace "python3" "${py}/bin/python" \
--replace "/lib/security/howdy/compare.py" "${howdypath}/compare.py"
substituteInPlace howdy/src/compare.py \
--replace "/lib/security/howdy" "${howdypath}" \
--replace "@pkgdatadir@" "${howdypath}"
'';
nativeBuildInputs = [
bzip2
installShellFiles
meson
ninja
pkg-config
];
buildInputs = [
fmt
gettext
inih
libevdev
pam
py
];
# build howdy_pam
preConfigure = ''
cd howdy/src/pam
# works around hardcoded install_dir: '/lib/security'.
# See https://github.com/boltgolt/howdy/blob/30728a6d3634479c24ffd4e094c34a30bbb43058/howdy/src/pam/meson.build#L22
export DESTDIR=$out
'';
postInstall =
let
libDir = "$out/lib/security/howdy";
inherit (lib) mapAttrsToList concatStrings;
in
''
# done with howdy_pam, go back to source root
cd ../../../..
mkdir -p $out/share/licenses/howdy
install -Dm644 LICENSE $out/share/licenses/howdy/LICENSE
rm -rf howdy/src/pam
mkdir -p ${libDir}
cp -r howdy/src/* ${libDir}
rm -rf ${libDir}/pam-config ${libDir}/dlib-data/*
${concatStrings (mapAttrsToList (n: v: ''
bzip2 -dc ${v} > ${libDir}/dlib-data/${n}
'') data)}
mkdir -p $out/bin
ln -s ${libDir}/cli.py $out/bin/howdy
mkdir -p "$out/share/bash-completion/completions"
installShellCompletion --bash howdy/src/autocomplete/howdy
'';
meta = {
description = "Windows Hello style facial authentication for Linux";
homepage = "https://github.com/boltgolt/howdy";
license = lib.licenses.mit;
platforms = lib.platforms.linux;
maintainers = with lib.maintainers; [ fufexan ];
};
}

View File

@@ -0,0 +1,78 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.howdy;
howdy = pkgs.callPackage ./howdy.nix { };
pam_python = pkgs.callPackage ./pam-python.nix { };
# `dark_threshold` is required for X1 Carbon 7th to work
configINI = pkgs.runCommand "config.ini" { } ''
cat ${cfg.package}/lib/security/howdy/config.ini > $out
substituteInPlace $out --replace 'device_path = none' 'device_path = ${cfg.device}'
substituteInPlace $out --replace 'dark_threshold = 50' 'dark_threshold = ${
toString cfg.dark-threshold
}'
substituteInPlace $out --replace 'certainty = 3.5' 'certainty = ${
toString cfg.certainty
}'
'';
pam-rule = pkgs.lib.mkDefault (pkgs.lib.mkBefore
"auth sufficient ${pam_python}/lib/security/pam_python.so ${config.services.howdy.package}/lib/security/howdy/pam.py");
in {
options = {
services.howdy = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable howdy and PAM module for face recognition.
'';
};
package = mkOption {
type = types.package;
default = howdy;
defaultText = "howdy";
description = ''
Howdy package to use.
'';
};
device = mkOption {
type = types.path;
default = "/dev/video0";
description = ''
Device file connected to the IR sensor.
'';
};
certainty = mkOption {
type = types.int;
default = 4;
description = ''
The certainty of the detected face belonging to the user of the account. On a scale from 1 to 10, values above 5 are not recommended.
'';
};
dark-threshold = mkOption {
type = types.int;
default = 50;
description = ''
Because of flashing IR emitters, some frames can be completely unlit. Skip the frame if the lowest 1/8 of the histogram is above this percentage of the total. The lower this setting is, the more dark frames are ignored.
'';
};
};
};
config = mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
environment.etc."howdy/config.ini".source = configINI;
security.pam.services = {
sudo.text = pam-rule; # Sudo
login.text = pam-rule; # User login
polkit-1.text = pam-rule; # PolKit
};
};
}

135
utils/pkgs/howdy/howdy.nix Normal file
View File

@@ -0,0 +1,135 @@
{ stdenv
, lib
, bzip2
, fetchFromGitHub
, fetchurl
, fmt
, gettext
, inih
, installShellFiles
, libevdev
, meson
, ninja
, pam
, pkg-config
, python3
}:
let
data = let
baseurl = "https://github.com/davisking/dlib-models/raw/daf943f7819a3dda8aec4276754ef918dc26491f";
in {
"dlib_face_recognition_resnet_model_v1.dat" = fetchurl {
url = "${baseurl}/dlib_face_recognition_resnet_model_v1.dat.bz2";
sha256 = "0fjm265l1fz5zdzx5n5yphl0v0vfajyw50ffamc4cd74848gdcdb";
};
"mmod_human_face_detector.dat" = fetchurl {
url = "${baseurl}/mmod_human_face_detector.dat.bz2";
sha256 = "117wv582nsn585am2n9mg5q830qnn8skjr1yxgaiihcjy109x7nv";
};
"shape_predictor_5_face_landmarks.dat" = fetchurl {
url = "${baseurl}/shape_predictor_5_face_landmarks.dat.bz2";
sha256 = "0wm4bbwnja7ik7r28pv00qrl3i1h6811zkgnjfvzv7jwpyz7ny3f";
};
};
py = python3.withPackages (p: [
p.face_recognition
(p.opencv4.override { enableGtk3 = true; })
]);
in
stdenv.mkDerivation {
pname = "howdy";
version = "unstable-2023-02-28";
src = fetchFromGitHub {
owner = "boltgolt";
repo = "howdy";
rev = "e881cc25935c7d39a074e9701a06b1fce96cc185";
hash = "sha256-BHS1J0SUNbCeAnTXrOQCtBJTaSYa5jtYYtTgfycv7VM=";
};
patches = [
# Change directory with configuration from `/etc` to `/var/lib`, since the service is expected to modify it.
./howdy.patch
];
postPatch =
let
howdypath = "${placeholder "out"}/lib/security/howdy";
in
''
substituteInPlace howdy/src/cli/add.py --replace "@pkgdatadir@" "${howdypath}"
substituteInPlace howdy/src/cli/config.py --replace '/bin/nano' 'nano'
substituteInPlace howdy/src/cli/test.py --replace "@pkgdatadir@" "${howdypath}"
substituteInPlace howdy/src/pam/main.cc \
--replace "python3" "${py}/bin/python" \
--replace "/lib/security/howdy/compare.py" "${howdypath}/compare.py"
substituteInPlace howdy/src/compare.py \
--replace "/lib/security/howdy" "${howdypath}" \
--replace "@pkgdatadir@" "${howdypath}"
'';
nativeBuildInputs = [
bzip2
installShellFiles
meson
ninja
pkg-config
];
buildInputs = [
fmt
gettext
inih
libevdev
pam
py
];
# build howdy_pam
preConfigure = ''
cd howdy/src/pam
# works around hardcoded install_dir: '/lib/security'.
# See https://github.com/boltgolt/howdy/blob/30728a6d3634479c24ffd4e094c34a30bbb43058/howdy/src/pam/meson.build#L22
export DESTDIR=$out
'';
postInstall =
let
libDir = "$out/lib/security/howdy";
inherit (lib) mapAttrsToList concatStrings;
in
''
# done with howdy_pam, go back to source root
cd ../../../..
mkdir -p $out/share/licenses/howdy
install -Dm644 LICENSE $out/share/licenses/howdy/LICENSE
rm -rf howdy/src/pam
mkdir -p ${libDir}
cp -r howdy/src/* ${libDir}
rm -rf ${libDir}/pam-config ${libDir}/dlib-data/*
${concatStrings (mapAttrsToList (n: v: ''
bzip2 -dc ${v} > ${libDir}/dlib-data/${n}
'') data)}
mkdir -p $out/bin
ln -s ${libDir}/cli.py $out/bin/howdy
mkdir -p "$out/share/bash-completion/completions"
installShellCompletion --bash howdy/src/autocomplete/howdy
'';
meta = {
description = "Windows Hello style facial authentication for Linux";
homepage = "https://github.com/boltgolt/howdy";
license = lib.licenses.mit;
platforms = lib.platforms.linux;
maintainers = with lib.maintainers; [ fufexan ];
};
}

View File

@@ -0,0 +1,155 @@
diff --git a/howdy/src/cli/add.py b/howdy/src/cli/add.py
index 8951e31..4f793d7 100644
--- a/howdy/src/cli/add.py
+++ b/howdy/src/cli/add.py
@@ -30,9 +30,9 @@ import cv2
config_path = "/etc/howdy"
# Test if at lest 1 of the data files is there and abort if it's not
-if not os.path.isfile(config_path + "/dlib-data/shape_predictor_5_face_landmarks.dat"):
+if not os.path.isfile("@pkgdatadir@/dlib-data/shape_predictor_5_face_landmarks.dat"):
print(_("Data files have not been downloaded, please run the following commands:"))
- print("\n\tcd " + config_path + "/dlib-data")
+ print("\n\tcd " + "@pkgdatadir@/dlib-data")
print("\tsudo ./install.sh\n")
sys.exit(1)
@@ -42,23 +42,23 @@ config.read(config_path + "/config.ini")
use_cnn = config.getboolean("core", "use_cnn", fallback=False)
if use_cnn:
- face_detector = dlib.cnn_face_detection_model_v1(config_path + "/dlib-data/mmod_human_face_detector.dat")
+ face_detector = dlib.cnn_face_detection_model_v1("@pkgdatadir@/dlib-data/mmod_human_face_detector.dat")
else:
face_detector = dlib.get_frontal_face_detector()
-pose_predictor = dlib.shape_predictor(config_path + "/dlib-data/shape_predictor_5_face_landmarks.dat")
-face_encoder = dlib.face_recognition_model_v1(config_path + "/dlib-data/dlib_face_recognition_resnet_model_v1.dat")
+pose_predictor = dlib.shape_predictor("@pkgdatadir@/dlib-data/shape_predictor_5_face_landmarks.dat")
+face_encoder = dlib.face_recognition_model_v1("@pkgdatadir@/dlib-data/dlib_face_recognition_resnet_model_v1.dat")
user = builtins.howdy_user
# The permanent file to store the encoded model in
-enc_file = config_path + "/models/" + user + ".dat"
+enc_file = "/var/lib/howdy/models/" + user + ".dat"
# Known encodings
encodings = []
# Make the ./models folder if it doesn't already exist
-if not os.path.exists(config_path + "/models"):
+if not os.path.exists("/var/lib/howdy/models"):
print(_("No face model folder found, creating one"))
- os.makedirs(config_path + "/models")
+ os.makedirs("/var/lib/howdy/models")
# To try read a premade encodings file if it exists
try:
diff --git a/howdy/src/cli/clear.py b/howdy/src/cli/clear.py
index 6fa5f3e..fc7676c 100644
--- a/howdy/src/cli/clear.py
+++ b/howdy/src/cli/clear.py
@@ -8,7 +8,7 @@ import builtins
from i18n import _
# Get the full path to this file
-path = "/etc/howdy/models"
+path = "/var/lib/howdy/models"
# Get the passed user
user = builtins.howdy_user
diff --git a/howdy/src/cli/list.py b/howdy/src/cli/list.py
index 3532e9f..b9e2a31 100644
--- a/howdy/src/cli/list.py
+++ b/howdy/src/cli/list.py
@@ -10,7 +10,7 @@ import builtins
from i18n import _
# Get the absolute path and the username
-path = "/etc/howdy"
+path = "/var/lib/howdy"
user = builtins.howdy_user
# Check if the models file has been created yet
diff --git a/howdy/src/cli/remove.py b/howdy/src/cli/remove.py
index 6321e0b..7c13d79 100644
--- a/howdy/src/cli/remove.py
+++ b/howdy/src/cli/remove.py
@@ -9,7 +9,7 @@ import builtins
from i18n import _
# Get the absolute path and the username
-path = "/etc/howdy"
+path = "/var/lib/howdy"
user = builtins.howdy_user
# Check if enough arguments have been passed
diff --git a/howdy/src/cli/test.py b/howdy/src/cli/test.py
index d54929a..fa45500 100644
--- a/howdy/src/cli/test.py
+++ b/howdy/src/cli/test.py
@@ -59,20 +59,20 @@ use_cnn = config.getboolean('core', 'use_cnn', fallback=False)
if use_cnn:
face_detector = dlib.cnn_face_detection_model_v1(
- path + "/dlib-data/mmod_human_face_detector.dat"
+ "@pkgdatadir@/dlib-data/mmod_human_face_detector.dat"
)
else:
face_detector = dlib.get_frontal_face_detector()
-pose_predictor = dlib.shape_predictor(path + "/dlib-data/shape_predictor_5_face_landmarks.dat")
-face_encoder = dlib.face_recognition_model_v1(path + "/dlib-data/dlib_face_recognition_resnet_model_v1.dat")
+pose_predictor = dlib.shape_predictor("@pkgdatadir@/dlib-data/shape_predictor_5_face_landmarks.dat")
+face_encoder = dlib.face_recognition_model_v1("@pkgdatadir@/dlib-data/dlib_face_recognition_resnet_model_v1.dat")
encodings = []
models = None
try:
user = builtins.howdy_user
- models = json.load(open(path + "/models/" + user + ".dat"))
+ models = json.load(open("/var/lib/howdy/models/" + user + ".dat"))
for model in models:
encodings += model["data"]
diff --git a/howdy/src/compare.py b/howdy/src/compare.py
index be19464..86a8d8f 100644
--- a/howdy/src/compare.py
+++ b/howdy/src/compare.py
@@ -48,22 +48,22 @@ def init_detector(lock):
global face_detector, pose_predictor, face_encoder
# Test if at lest 1 of the data files is there and abort if it's not
- if not os.path.isfile(PATH + "/dlib-data/shape_predictor_5_face_landmarks.dat"):
+ if not os.path.isfile("@pkgdatadir@/dlib-data/shape_predictor_5_face_landmarks.dat"):
print(_("Data files have not been downloaded, please run the following commands:"))
- print("\n\tcd " + PATH + "/dlib-data")
+ print("\n\tcd " + "@pkgdatadir@/dlib-data")
print("\tsudo ./install.sh\n")
lock.release()
exit(1)
# Use the CNN detector if enabled
if use_cnn:
- face_detector = dlib.cnn_face_detection_model_v1(PATH + "/dlib-data/mmod_human_face_detector.dat")
+ face_detector = dlib.cnn_face_detection_model_v1("@pkgdatadir@/dlib-data/mmod_human_face_detector.dat")
else:
face_detector = dlib.get_frontal_face_detector()
# Start the others regardless
- pose_predictor = dlib.shape_predictor(PATH + "/dlib-data/shape_predictor_5_face_landmarks.dat")
- face_encoder = dlib.face_recognition_model_v1(PATH + "/dlib-data/dlib_face_recognition_resnet_model_v1.dat")
+ pose_predictor = dlib.shape_predictor("@pkgdatadir@/dlib-data/shape_predictor_5_face_landmarks.dat")
+ face_encoder = dlib.face_recognition_model_v1("@pkgdatadir@/dlib-data/dlib_face_recognition_resnet_model_v1.dat")
# Note the time it took to initialize detectors
timings["ll"] = time.time() - timings["ll"]
@@ -129,7 +129,7 @@ face_encoder = None
# Try to load the face model from the models folder
try:
- models = json.load(open(PATH + "/models/" + user + ".dat"))
+ models = json.load(open("/var/lib/howdy/models/" + user + ".dat"))
for model in models:
encodings += model["data"]

View File

@@ -0,0 +1,28 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.ir-toggle;
ir_toggle = pkgs.callPackage ./ir-toggle.nix { };
in {
options = {
services.ir-toggle = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable Chicony IR Emitter toggler.
'';
};
};
};
config = mkIf cfg.enable {
# Udev rules to start it on boot.
environment.systemPackages = [ ir_toggle ];
# Re-toggle the IR emitter after the sleep so that it could work perfectly
powerManagement.resumeCommands =
"${ir_toggle}/bin/chicony-ir-toggle on";
services.udev.packages = [ ir_toggle ];
};
}

View File

@@ -0,0 +1,17 @@
{ stdenv, fetchFromGitHub, cmake }:
stdenv.mkDerivation rec {
name = "chicony-ir-toggle";
src = fetchFromGitHub {
owner = "PetePriority";
repo = name;
rev = "5758112ae7f502035d48f24123347ba37cdbdb34";
sha256 = "1ihxkvhjbryhw5xjnw5a36f5w8nn4lnf07dzmzi6jzrn5ax131hw";
};
nativeBuildInputs = [ cmake ];
preInstall = ''
substituteInPlace ../CMakeLists.txt --replace /lib $out/lib
'';
}

View File

@@ -0,0 +1,17 @@
{ stdenv, python2, python2Packages, fetchurl, pam }:
let outPath = placeholder "out";
in stdenv.mkDerivation rec {
pname = "pam-python";
version = "1.0.7";
src = fetchurl {
url =
"https://downloads.sourceforge.net/project/pam-python/pam-python-1.0.7-1/pam-python-1.0.7.tar.gz";
sha256 = "01vylk8vmzsvxf0iwn2nizwkhdzk0vpyqh5m1rybh0sv6pz75kln";
};
buildInputs = [ python2 python2Packages.sphinx pam ];
preBuild = ''
patchShebangs .
substituteInPlace src/Makefile --replace '-Werror' '-O -Werror=cpp'
'';
makeFlags = [ "PREFIX=${outPath}" "LIBDIR=${outPath}/lib/security" ];
}