feat(grocy): barcode buddy

This commit is contained in:
arcnmx 2024-03-22 07:49:54 -07:00
parent a157150956
commit dc0c84c0a0
13 changed files with 391 additions and 1 deletions

18
flake.lock generated
View file

@ -21,6 +21,23 @@
"type": "github"
}
},
"barcodebuddy": {
"flake": false,
"locked": {
"lastModified": 1694536720,
"narHash": "sha256-98trW1WFtQOZX/mMNc3wQL5sxU6fupI6ukCp5zZsw+Q=",
"owner": "Forceu",
"repo": "barcodebuddy",
"rev": "55bbc03d873d637b0aa8282468c0fc3f9da39776",
"type": "github"
},
"original": {
"owner": "Forceu",
"ref": "v1.8.1.7",
"repo": "barcodebuddy",
"type": "github"
}
},
"ci": {
"flake": false,
"locked": {
@ -187,6 +204,7 @@
"root": {
"inputs": {
"arcexprs": "arcexprs",
"barcodebuddy": "barcodebuddy",
"ci": "ci",
"deploy-rs": "deploy-rs",
"flake-compat": "flake-compat",

View file

@ -58,6 +58,10 @@
flakelib.follows = "flakelib";
};
};
barcodebuddy = {
url = "github:Forceu/barcodebuddy/v1.8.1.7";
flake = false;
};
};
nixConfig = {
extra-substituters = [

View file

@ -0,0 +1,168 @@
{ config, lib, pkgs, ... }: let
inherit (lib.options) mkOption mkEnableOption mkPackageOption;
inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault mkOverride;
inherit (lib.attrsets) mapAttrs mapAttrs' nameValuePair;
inherit (lib.lists) isList optional imap0;
inherit (lib.strings) concatStringsSep;
mkAlmostOptionDefault = mkOverride 1250;
mapOptionDefaults = mapAttrs (_: mkOptionDefault);
cfg = config.services.barcodebuddy;
toEnvName = key: "BBUDDY_" + key;
toEnvValue = value:
if value == true then "true"
else if value == false then "false"
else if isList value then concatStringsSep ";" (imap0 (i: v: "${toString i}=${toEnvValue v}") value)
else toString value;
toEnvPair = key: value: nameValuePair (toEnvName key) (toEnvValue value);
toPhpEnvPair = key: value: nameValuePair (toEnvName key) ''"${toEnvValue value}"'';
in {
options.services.barcodebuddy = with lib.types; {
enable = mkEnableOption "Barcode Buddy";
package = mkPackageOption pkgs "barcodebuddy" { };
phpPackageUnwrapped = mkPackageOption pkgs "php83" { };
hostName = mkOption {
type = str;
};
dataDir = mkOption {
type = path;
default = "/var/lib/barcodebuddy";
};
databasePath = mkOption {
type = path;
default = "${cfg.dataDir}/barcodebuddy.db";
};
authDatabasePath = mkOption {
type = path;
default = "${cfg.dataDir}/users.db";
};
reverseProxy = {
enable = mkEnableOption "reverse proxy";
trustedAddresses = mkOption {
type = listOf str;
default = [ "127.0.0.1" "::1" ];
};
};
redis = {
enable = mkEnableOption "redis cache";
server = mkOption {
type = nullOr str;
default = null;
description = "services.redis.servers";
};
ip = mkOption {
type = str;
};
port = mkOption {
type = port;
};
password = mkOption {
type = nullOr str;
default = null;
};
/* TODO: passwordFile = mkOption {
type = nullOr path;
default = null;
};*/
};
settings = mkOption {
type = attrsOf (oneOf [ str bool int (listOf str) ]);
description = "https://github.com/Forceu/barcodebuddy/blob/master/config-dist.php";
};
nginxPhpConfig = mkOption {
type = lines;
};
};
config = let
bbuddyConfig.services.barcodebuddy = {
settings = let
defaults = mapOptionDefaults {
PORT_WEBSOCKET_SERVER = 47631;
SEARCH_ENGINE = "https://google.com/search?q=";
${if cfg.reverseProxy.enable then "TRUSTED_PROXIES" else null} = cfg.reverseProxy.trustedAddresses;
DISABLE_AUTHENTICATION = false;
DATABASE_PATH = cfg.databasePath;
AUTHDB_PATH = cfg.authDatabasePath;
CONFIG_PATH = "${pkgs.writeText "barcodebuddy.conf.php" ""}";
};
redis = mapOptionDefaults {
USE_REDIS = cfg.redis.enable;
REDIS_IP = cfg.redis.ip;
REDIS_PORT = cfg.redis.port;
REDIS_PW = toString cfg.redis.password;
};
in mkMerge [ defaults (mkIf cfg.redis.enable redis) ];
nginxPhpConfig = mkMerge [
''
include ${config.services.nginx.package}/conf/fastcgi.conf;
fastcgi_pass unix:${config.services.phpfpm.pools.barcodebuddy.socket};
fastcgi_read_timeout 80s;
''
(mkIf cfg.reverseProxy.enable ''
fastcgi_pass_header "X-Accel-Buffering";
'')
];
redis = let
redis = config.services.redis.servers.${cfg.redis.server};
in mkIf (cfg.redis.server != null) {
enable = mkAlmostOptionDefault redis.enable;
ip = mkOptionDefault (if redis.bind == null then "localhost" else redis.bind);
port = mkIf (redis.port != 0) (mkOptionDefault redis.port);
password = mkAlmostOptionDefault redis.requirePass;
# TODO: passwordFile = mkAlmostOptionDefault redis.requirePassFile;
};
};
conf.users.users.barcodebuddy = {
isSystemUser = true;
inherit (config.services.nginx) group;
};
conf.systemd.tmpfiles.rules = [
"d ${cfg.dataDir} - barcodebuddy nginx - -"
];
conf.services.phpfpm.pools.barcodebuddy = {
user = "barcodebuddy";
inherit (config.services.nginx) group;
phpPackage = cfg.phpPackageUnwrapped.withExtensions ({ enabled, all }: [
all.curl
all.mbstring
all.sqlite3
all.pdo
all.pdo_sqlite
all.sockets
all.gettext
] ++ optional cfg.redis.enable all.redis);
settings = mapOptionDefaults {
"pm.max_children" = 10;
"pm" = "dynamic";
"php_admin_value[error_log]" = "stderr";
"php_admin_flag[log_errors]" = true;
"listen.owner" = config.services.nginx.user;
"catch_workers_output" = true;
"pm.start_servers" = 1;
"pm.min_spare_servers" = 1;
"pm.max_spare_servers" = 2;
"pm.max_requests" = 10;
};
phpEnv = mapAttrs' toPhpEnvPair cfg.settings;
};
# https://github.com/Forceu/barcodebuddy/blob/master/example/nginxConfiguration.conf
conf.services.nginx = {
enable = mkDefault true;
virtualHosts."${cfg.hostName}" = {
root = "${cfg.package}";
locations = {
"~ \\.php$".extraConfig = cfg.nginxPhpConfig;
};
extraConfig = ''
index index.php index.html index.htm;
'';
};
};
in mkMerge [ bbuddyConfig (mkIf cfg.enable conf) ];
}

View file

@ -19,7 +19,7 @@ in {
};
grocy'local = {
inherit name;
ssl.cert.copyFromVhost = "zigbee2mqtt";
ssl.cert.copyFromVhost = "grocy";
local.enable = mkDefault true;
locations."/" = mkIf (!grocy.enable) {
proxyPass = mkDefault (if grocy.enable

38
nixos/barcodebuddy.nix Normal file
View file

@ -0,0 +1,38 @@
{config, lib, ...}: let
inherit (lib.modules) mkDefault;
inherit (config.services) nginx;
cfg = config.services.barcodebuddy;
in {
config.services.barcodebuddy = {
enable = mkDefault true;
hostName = mkDefault "barcodebuddy";
reverseProxy.enable = mkDefault true;
settings = {
EXTERNAL_GROCY_URL = "https://grocy.${config.networking.domain}";
DISABLE_AUTHENTICATION = true;
};
nginxPhpConfig = ''
include ${config.sops.secrets.barcodebuddy-fastcgi-params.path};
'';
};
config.services.nginx.virtualHosts.barcodebuddy = {
vouch = {
enable = true;
requireAuth = false;
};
name.shortServer = mkDefault "bbuddy";
locations = {
"= /api/index.php" = {
vouch.requireAuth = false;
extraConfig = cfg.nginxPhpConfig;
};
"~ \\.php$" = {
vouch.requireAuth = true;
};
};
};
config.sops.secrets.barcodebuddy-fastcgi-params = {
sopsFile = mkDefault ./secrets/barcodebuddy.yaml;
owner = mkDefault nginx.user;
};
}

View file

@ -2,6 +2,7 @@
nixpkgs = {
overlays = [
inputs.arcexprs.overlays.default
(import ../../overlays/barcodebuddy.nix)
(import ../../overlays/samba.nix)
(import ../../overlays/nginx.nix)
];

View file

@ -0,0 +1,120 @@
barcodebuddy-fastcgi-params: ENC[AES256_GCM,data:Ja1gkFypwLgdQyJWQljtkcmlJ4nKw8CACXIe9CXQduwv2wZdiAZcoulX6+kjPxHLMsdTuvWFbVY4GfBVWh6LmySLgR6tIwmNiNg7ncgVEQbeTK75HQFWviVDu13GjYQU7YCBB438gX2X2aPHb25EcLU6UQgzHyCetO6nG9/T9OhKmmS0UUXCG1JykWQqfHPpjddydRYw08ZseZHhcyPzXAwdoJZsgVs1KhbvCUuMJctCfFEwCesYXcGM6eTPg9N8+hqAa13ijkQ8NzmamUau45pmrRbUJOm+OXi0TjO8KYIkQg7bua64oO3DegzFmeFeqnSAmlIcvZw=,iv:tI+RtXAWKbx3jQ1QfuCcoEoXPq9oze0QjrwQ5mcDe0U=,tag:Fa8fODz6hQu09yaf3HyqXg==,type:str]
sops:
shamir_threshold: 1
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age12ze362pu5mza6ef9akrptr7hfe4auaqul4rkta7kyy2tnrstqensgmujeq
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvYVJGSFBRRnNnN0VFY3hj
elBraEpLWjhBZnhNWFpSU2w2bWo0YUpFQ0RvCkJNSUVucHRQYnViQnlyQi85c2NN
MEIyTjRCV2lFOFU5UmRPT1BZeUtNeGMKLS0tIDBVRVV0K1hOeVZOZWZxNzZGeVZ2
b1NZMDNvNnBkU012NERxODRGWUhGeEEKYU1FtcFfOEVAyHd4kPJQTHSjIrghZJRx
Y56m4F4ZLUjHTdW67t0B6n8HMxkd9FkPMNcdevXjo1EJje7OkTFPbQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age176uyyyk7veqnzmm8xzwfhf0u23m6hm02cldlfkldunqe6std0gcq6lg057
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPeDJsSDBJSU5QeDZzWGRG
VjVsSW9xNU1NSVRLYzlqMWdrYllMeTV1eVY0ClBVOUt0VzkvYVFHY2pvYjNLOWRU
bXIySGtvckRlbzZ0dWFIYWpsUlpsYXcKLS0tIGk3bTFYYm4veHU5WVM3RmlHSlZG
SU5ZSklscGp4VTBBSnFMMWp4Q2RoSG8KZs+4ZqdkbxljhlqXShO3hazTBYyMZpR6
7kFuV3SA/NawP+1rRunB68PG2OgZAsOdEMghQcDjvXUCDPnolVWElg==
-----END AGE ENCRYPTED FILE-----
- recipient: age15hmlkd9p5rladsjzpmvrh6u34xvggu9mzdsdxdj3ms43tltxeuhq4g7g9k
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjTHFDcHpBcFEvUDg5TEg4
QVdCNG9xeUViQ3AyOGxyYWJudVNzZFNxWmpJCjVsa0FzSzNyTmsrRXRESXhpMi9v
WHZ2RERMQUNoc0h1R0hFRkRkK29yRUkKLS0tIDdKdHlZUGVXM0ZQNnZ0Sk11clZ1
ajRGNWRvZ2FjV215dUcxZjM1Y3U1L2MK2F3SM/aDXAxBYMySZcBxTstYEQ6fU9lg
SSsH2QX6XkHsC8LExGzEW/OPSAf7tfxKmGiMM/YHmKo0XkthjMdw5Q==
-----END AGE ENCRYPTED FILE-----
- recipient: age10t6kc5069cyky929vvxk8aznqyxpkx3k5h5rmlyz83xtjmr22ahqe8mzes
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKSnBMSGJtWHZyNHZEVzdo
M1VtNU9lcWViZnFjT0FFMHltMFdEL0R0Mm5VCnBZb0ljcHNpSVY5em5sN3lJc0dx
QXZuM3BONzVzcUtOb3hVbGF5MFJlT00KLS0tIGp2YmZ4MUVWc01ESjhsSll1UWFo
eVU2TGs3QzhOcU00UjhQWjBZU1VDeUkK/E/ff/ZTOmMmxhwAbAA1K/HOXGx9bhdE
HD079kH0nAD4+lBA2lzDz8CDKVOU0QNratxZwOJd4yZUm917We4kQA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1a2quf2ekkj94ygu7wgvhrvh44fwn32c0l2cwvgvjh23wst90s54szdsvgr
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3M2FydGVtVFlQdVFWd25C
NHE4emhCU2pxRmYreG9HQU8vUmFSSXZEZEdZCnRzQnhGZjllUGZFdmhuRHNxWXJz
Sk9saDVrRjAyanpuZ21oZlNWeGNMZncKLS0tIEx3M21tTjR6UXhlcHE4VG56NllH
WG5uOVA4bmhjaWFpTmtLRXpRSTN5YjAKHb1ztknE6la54ffLnRGM4ellP5vmvSI+
SkaXCjzArtbvIDFHL3bp8mpMN6qLpLUgPsI2a2KsED+pX3dcyBNqzA==
-----END AGE ENCRYPTED FILE-----
- recipient: age16klpkaut5759dut8mdm3jn0rnp8w6kxyvs9n6ntqrdsayjtd7upqlvw489
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1dUpWOGZub0JtMjhNd2Uv
WkJRaEhsaVlpMDM1alFHT1JZakVKakozcWo0ClV0NmgydWZyazE2WFBEU05HUlpq
amJiMXpnZG0rNkNjSllrZkZ2cE95bXMKLS0tIEw4cnI2bWNyTncwT3RRQ3JTVTN3
NzMxS2lHcUJHUE51WmNWNlRSQ2hoaE0KMrBo1vqsWBK0j90+xqGKUktfaxzFnfQe
mUzZZGJBr+wQlPiv2WzlD0eYu4KLy+JxibY6bSIj0bFynO9Z5VsSNQ==
-----END AGE ENCRYPTED FILE-----
- recipient: age13qgddr326g5je0fpq2r3k940vsr3fh9nlvl9xtcxk3xg2x0k3vsq7pvzaj
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBYc0lORWVBQ29NUnJwWWtp
RXo2ejZubFJhL0JES0QrZzZMR05GVGpPWXhFCnh0SUdveWYwTmdQcGNhZnE4anNi
VXM0OWhtSEl6Vm1VYW9Pd0c5SHV3VHcKLS0tIFdNNjc3Vk9qS3FVd0tFaWxvSjFL
U2tCd2U0MWd5L0pIM21GRi9zM1NZWkkKRxMlIlsx6B5ygAVPqawyRG5vfnz/kuPJ
YxNkh3aUkvaIagnMZ/bzjNYV7y6cnBl4M3rzrvHncR0zp9/6QH4jbA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1ktmx2szedfnpe5xumnzs8vkk0ffqgga6ved3drtksg9pye6ndsnsnqq488
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMUUpVbm40THgwS0IyeE14
RjV3aDAyZk9tSjF0Rk4vUzdhMnBnUmxsaUFzCkZKOGxWdGcrYmlPTmI2dVBIOVhG
RXBzMlF5WTlsZlhCQmo1cHdYRmJ5OFkKLS0tIDl1bzRLWnk0aUdHM2hQSUVqNmMw
YVp2UnlUeVVuMjE1L0VsdEJQdmtlQWcKwuFHmj4KpUk/LGxKu2sHOmN8QsuiZat+
p4FswX4i4PDPmZAHYLt69MJIKUDlm3iN/A5Hfa6mX6R4NZjryNdD2w==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-03-22T15:15:33Z"
mac: ENC[AES256_GCM,data:N4NB3pSZsh8HTSp14/rj4kZ1dGvJzlP9j6uk9ZciCtNFsEmPLSSojdJfzULUvpbZv+emJHHgXCKORCtJ6xZ0Zn+8u2q/nvEiWQITMl00yeRz2SNanCumtXmT+YdMI0PEK6WnLJSyiq/qr5GQIzYKWZgJRaj7hiu/eTdpglTfZUo=,iv:ybOhB5ZFvdSEyewqVBtXAW5b5i9tUJBAk1GdycRwkMY=,tag:Pl7jQhHmKj8yhQDUyoZHFg==,type:str]
pgp:
- created_at: "2024-03-22T14:22:11Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMA82M54yws73UARAAqF6X9la78YtUjZntDu6j/s/A7+uNO5vIGRwUBathX4K4
BQR9JRHMLiloAQCwGMjYUQBcGBlkTYZDh5ToN15YgaU7OLkcPKqWWkNHrmuhhbha
HoUVrznU3iqsN4ZyQ7d8Z2WcgulkRO07hiEks8F21Vzdu6r+pU4F4+A+SqnlyfRQ
jGiOO1OBmxeYUGbthOcW1wxFByYd+uUKnY+59U/eJxWIXgKhIPbdPPcPdMGF+P46
OuLdK8fHMY50lzfn/fa8IlKAM95bsvwxH8PfGKShQCQde1va3xcB+N9uoJvTFZ9t
PkmDd7iFKlbN2SGmxI4pBlHanvJ94eB8afGH96aTIQj700vMH95oTvKKnSJWZvUz
U1a3pRsnxSqgQ+Dont8VxrhlRyHw3z7GCOE0+Jhau7xY6hN8KpT16gSGAZ5FZ8zs
sXkeZcAf5vJPpLsrxIU9XEHY7+zzMyAYOw2MfuMOQhJR9UDlV+gjetIy3CcW6qAR
rBg05xJ2Nt6MUNuWdjcMkemME8uJN9a4rn6GkG80h4K4OBnr2+YYWH76bleTkAGx
aie2XzURPE/xhDBFAXXUGycgd2h1vLt6cDqgDvmLVUssVCdbZszX31vGabA+/dlX
eTdNRsseQC4j9HaTECIFDDvQzWGl3vpFD0EGgvQt8U6Q3xCgXfEOrxP2th/ogE3S
XgHz/dGQpfMgvNdYoQ2uYBB6i4k14z7u6sQOPsc6hYTUqaQfx7VH+ji7Pgx9OG0G
UlkEpWG8brPffzkz+OcrgH8lm+9+E51z/dzdEDSUa1zMyvD1iXr1eXUUDt8sUbA=
=TG+W
-----END PGP MESSAGE-----
fp: CD8CE78CB0B3BDD4
- created_at: "2024-03-22T14:22:11Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQEMA2W9MER3HLb7AQf+NBCAbsV4DtDVLUAzlb2Z49Fi4tZlEBbcf/vg8fvoS2Y7
uGjlkp/t5fc2YoZuZ8gWbzAg2Y4mIs0NgeLcZffAzcZAOOZ24qRYdnIwHNnqR0Ca
dSqbYbcXO3yGMDDsSFjcL7l9O/YqR+WntwJBPuhfjVuJ0lNXXYg6r0hVyfVQmAv5
x0xLuYttTxCSy4iDfStpTpeiQTFTrqFccBVZZJiIG9TyqQZNRXnrCKXvwZ49nxVE
vGMyf6bVPXhqEDjwJ534HvV3AGovwPt8t8OE4ohnau5VVwpqF0U+Jn8tvmvFti5B
T6BMtPBkDvSEk+rk7qv4Ak/GwooJ4PgCwVuVVXGXCNJeAUuK5g38Q14p3lBFOt7W
u9xhH7c/FsPTAHz221OUi5AXfIZIFsgQVcu2JyzlzgzIC66tzOf2mUrhWRmVD+NY
CyfrZcE3N4C7392MTqFnemJtbYDOJ+YRW7pCMzEoBQ==
=z+BG
-----END PGP MESSAGE-----
fp: 65BD3044771CB6FB
unencrypted_suffix: _unencrypted
version: 3.8.1

View file

@ -0,0 +1,4 @@
final: prev: let
in {
barcodebuddy = final.callPackage ../packages/barcodebuddy.nix { };
}

View file

@ -7,7 +7,9 @@
overlays = [
inputs.deploy-rs.overlay
inputs.arcexprs.overlays.default
(import ./barcodebuddy.nix)
(import ./samba.nix)
(import ./nginx.nix)
(final: prev: {
jemalloc =
if final.hostPlatform != "aarch64-darwin"

28
packages/barcodebuddy.nix Normal file
View file

@ -0,0 +1,28 @@
{
stdenvNoCC,
fetchFromGitHub,
lib,
...
}: let
inherit (lib.strings) removePrefix;
lock = builtins.fromJSON (builtins.readFile ../flake.lock);
inherit (lock.nodes) barcodebuddy;
in stdenvNoCC.mkDerivation {
pname = "barcodebuddy";
version = removePrefix "v" barcodebuddy.original.ref;
src = fetchFromGitHub {
inherit (barcodebuddy.locked) repo owner rev;
sha256 = barcodebuddy.locked.narHash;
};
skipConfigure = true;
skipBuild = true;
installPhase = ''
runHook preInstall
install -d $out
cp -ar api/ incl/ locales/ menu/ plugins/ *.php $out/
runHook postInstall
'';
}

View file

@ -57,6 +57,10 @@ in {
host = nginx.virtualHosts.grocy.serverName;
inherit hostName;
})
(ingressForNginx {
host = nginx.virtualHosts.barcodebuddy.serverName;
inherit hostName;
})
(ingressForHass {inherit hostName;})
];
};

View file

@ -22,6 +22,7 @@ in {
nixos.zigbee2mqtt
nixos.syncplay
nixos.grocy
nixos.barcodebuddy
./cloudflared.nix
];
@ -29,6 +30,7 @@ in {
virtualHosts = {
zigbee2mqtt.proxied.enable = "cloudflared";
grocy.proxied.enable = "cloudflared";
barcodebuddy.proxied.enable = "cloudflared";
};
};

View file

@ -103,6 +103,7 @@ module "tewi" {
"id",
"z2m",
"grocy",
"bbuddy",
]
}