Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion common/configuration.nix
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{lib, pkgs, ...}: {
imports = [ ./ssh.nix ./airsane ];
imports = [
./ssh.nix
./airsane
./homebox
];

time.timeZone = "Europe/Moscow";
i18n.defaultLocale = "en_US.UTF-8";
Expand Down
223 changes: 223 additions & 0 deletions common/homebox/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.homebox;
inherit (lib) types;
toString' = x: if builtins.isBool x then lib.boolToString x else toString x;
escapeSystemdArg = s: "\"${lib.escape [ "\"" ] s}\"";
attrsToArgs = lib.flip lib.pipe [
(lib.filterAttrs (_: x: x != null))
(lib.mapAttrs (_: toString'))
(lib.mapAttrsToList (name: value: "--${name}=${value}"))
];
in
{
options.services.homebox = {
enable = lib.mkEnableOption "homebox";
package = lib.mkPackageOption pkgs "homebox" { };
settings = {
mode = lib.mkOption {
default = "production";
type = types.enum [
"development"
"production"
];
example = "development";
};
web = {
port = lib.mkOption {
default = 7745;
type = types.port;
};
host = lib.mkOption {
default = null;
type = types.nullOr types.str;
};
max-upload-size = lib.mkOption {
default = 10;
type = types.ints.positive;
};
timeout = {
read = lib.mkOption {
default = 10;
type = types.ints.positive;
};
write = lib.mkOption {
default = 10;
type = types.ints.positive;
};
idle = lib.mkOption {
default = 30;
type = types.ints.positive;
};
};
};
allow-registration = lib.mkOption {
default = true;
type = types.bool;
example = false;
};
auto-increment-asset-id = lib.mkOption {
default = true;
type = types.bool;
example = false;
};
currency-config = lib.mkOption {
type = types.nullOr types.path;
default = null;
};
storage = lib.mkOption {
type = types.path;
default = "/var/lib/homebox/";
};
sqlite-url = lib.mkOption {
type = types.str;
default = "/var/lib/homebox/homebox.db?_fk=1";
};
log = {
level = lib.mkOption {
default = "info";
type = types.enum [
"trace"
"debug"
"info"
"warn"
"error"
"critical"
];
};
format = lib.mkOption {
default = "text";
type = types.enum [
"text"
"json"
];
};
};
mailer = {
enable = lib.mkEnableOption "homebox.mailer";
port = lib.mkOption {
default = 587;
type = types.port;
};
host = lib.mkOption { type = types.str; };
};
swagger = {
enable = lib.mkEnableOption "homebox.swagger";
host = lib.mkOption { default = "localhost"; };
port = lib.mkOption {
default = 7745;
type = types.port;
};
schema = lib.mkOption {
type = lib.enum [
"http"
"https"
];
};
};
debug = {
enable = lib.mkEnableOption "homebox.debug";
port = lib.mkOption {
default = 4000;
type = types.port;
};
};
};
environmentFiles = lib.mkOption {
type = with lib.types; listOf path;
default = [ ];
example = [ "/root/homebox.env" ];
description = lib.mdDoc ''
File to load environment variables
from. This is helpful for specifying secrets.
Example content of environmentFile:
```
[email protected]
HBOX_MAILER_PASSWORD=password
```
'';
};
};

config = lib.mkIf cfg.enable {
nixpkgs.overlays = [ (final: prev: { homebox = final.callPackage ./package.nix { }; }) ];
systemd.services = {
homebox = {
description = "Homebox Service";
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
serviceConfig = {
DynamicUser = true;
WorkingDirectory = "%S/homebox";
StateDirectory = "homebox";
StateDirectoryMode = "0700";
UMask = "0007";
ConfigurationDirectory = "homebox";
EnvironmentFile = cfg.environmentFiles;
ExecStart = lib.concatMapStringsSep " " escapeSystemdArg (
lib.singleton "${cfg.package}/bin/api"
++ attrsToArgs (
{
inherit (cfg.settings) mode;
web-port = cfg.settings.web.port;
web-host = cfg.settings.web.host;
web-max-upload-size = cfg.settings.web.max-upload-size;
storage-data = cfg.settings.storage;
storage-sqlite-url = cfg.settings.sqlite-url;
log-level = cfg.settings.log.level;
log-format = cfg.settings.log.format;
options-allow-registration = cfg.settings.allow-registration;
options-auto-increment-asset-id = cfg.settings.auto-increment-asset-id;
options-currency-config = cfg.settings.currency-config;
}
// lib.optionalAttrs cfg.settings.mailer.enable {
mailer-host = cfg.settings.mailer.host;
mailer-port = cfg.settings.mailer.port;
}
// lib.optionalAttrs cfg.settings.swagger.enable {
swagger-host = "${cfg.settings.swagger.host}:${cfg.settings.swagger.port}";
swagger-scheme = cfg.settings.swagger.schema;
}
// lib.optionalAttrs cfg.settings.debug.enable {
debug-enabled = cfg.settings.debug.enable;
debug-port = cfg.settings.debug.port;
}
)
);
Restart = "on-failure";
RestartSec = 15;
CapabilityBoundingSet = "";
# Security
NoNewPrivileges = true;
# Sandboxing
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateUsers = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [ "AF_UNIX AF_INET AF_INET6" ];
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
PrivateMounts = true;
# System Call Filtering
SystemCallArchitectures = "native";
SystemCallFilter = "~@clock @privileged @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @reboot @setuid @swap";
};
};
};
};
}
117 changes: 117 additions & 0 deletions common/homebox/package.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
{ lib
, buildGoModule
, fetchFromGitHub
, stdenvNoCC
, jq
, moreutils
, nodePackages
, stdenv
, esbuild
, cacert
}:
let
pname = "homebox";
version = "0.11.0";

src = fetchFromGitHub {
owner = "sysadminsmedia";
repo = "homebox";
rev = "v${version}";
hash = "sha256-Xbhk9zbtuYLxToiLcgZm0DPBma5KeLOH3Fi3va9oAAU=";
};

pnpm-deps = stdenvNoCC.mkDerivation {
pname = "${pname}-pnpm-deps";
src = "${src}/frontend";
inherit version;

nativeBuildInputs = [
jq
moreutils
nodePackages.pnpm
cacert
];

installPhase = ''
export HOME=$(mktemp -d)
pnpm config set store-dir $out
# use --ignore-script and --no-optional to avoid downloading binaries
# use --frozen-lockfile to avoid checking git deps
pnpm install --frozen-lockfile --no-optional --ignore-script

# Remove timestamp and sort the json files
rm -rf $out/v3/tmp
for f in $(find $out -name "*.json"); do
sed -i -E -e 's/"checkedAt":[0-9]+,//g' $f
jq --sort-keys . $f | sponge $f
done
'';

dontFixup = true;
outputHashMode = "recursive";
outputHash = "sha256-CZP3rGLTHgFErskllqV2KEt3qEIN17cA8P+XSWBps44=";
};

frontend = stdenv.mkDerivation {
pname = "${pname}-frontend";
src = "${src}/frontend";
inherit version;

nativeBuildInputs = [
nodePackages.pnpm
];

ESBUILD_BINARY_PATH = "${lib.getExe (esbuild.override {
buildGoModule = args: buildGoModule (args // rec {
version = "0.17.19";
src = fetchFromGitHub {
owner = "evanw";
repo = "esbuild";
rev = "v${version}";
hash = "sha256-PLC7OJLSOiDq4OjvrdfCawZPfbfuZix4Waopzrj8qsU=";
};
vendorHash = "sha256-+BfxCyg0KkDQpHt/wycy/8CTG6YBA/VJvJFhhzUnSiQ=";
});
})}";

preBuild = ''
export HOME=$(mktemp -d)
pnpm config set store-dir ${pnpm-deps}
pnpm install --offline --frozen-lockfile --no-optional --ignore-script --shamefully-hoist

chmod -R +w ./node_modules
patchShebangs node_modules
NUXT_TELEMETRY_DISABLED=1 pnpm build
'';

installPhase = ''
runHook preInstall

mv .output $out

runHook postInstall
'';
};
in
buildGoModule {
inherit pname version;
src = "${src}/backend";

vendorHash = "sha256-Ju4w7Q4xeh7zRLPfhjemEbt/6EOdnaBT3VtCnUCv+D0=";

passthru = { inherit frontend; };

preBuild = ''
mkdir -p app/api/static
cp -R ${frontend}/public app/api/static
'';

meta = with lib; {
description = "A inventory and organization system built for the Home User";
homepage = "https://homebox.sysadminsmedia.com";
license = licenses.agpl3Only;
maintainers = with maintainers; [ janik ];
mainProgram = "api";
platforms = platforms.all;
};
}
1 change: 1 addition & 0 deletions nodes/undef/configuration.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
./printing.nix
./jukebox.nix
./pipewire.nix
./homebox.nix
# inputs.tg-bot.nixosModule.x86_64-linux
# ./wg.nix
];
Expand Down
8 changes: 8 additions & 0 deletions nodes/undef/homebox.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{ ... }:
{
services.homebox = {
enable = true;
settings.log.format = "json";
settings.allow-registration = false;
};
}