diff --git a/hosts/desktopnix/default.nix b/hosts/desktopnix/default.nix index 8b1f8f9..c339965 100644 --- a/hosts/desktopnix/default.nix +++ b/hosts/desktopnix/default.nix @@ -19,6 +19,7 @@ ../../modules/hardware/physical.nix ../../modules/hardware/pipewire.nix ../../modules/hardware/yubikey.nix + ../../modules/hardware/bluetooth.nix ../../modules/hardware/zfs.nix ../../modules/optional/streamdeck.nix diff --git a/hosts/elisabeth/guests.nix b/hosts/elisabeth/guests.nix index 02119c7..7974758 100644 --- a/hosts/elisabeth/guests.nix +++ b/hosts/elisabeth/guests.nix @@ -16,6 +16,7 @@ ttrssdomain = "rss.${config.secrets.secrets.global.domains.web}"; vaultwardendomain = "pw.${config.secrets.secrets.global.domains.web}"; spotifydomain = "spotify.${config.secrets.secrets.global.domains.web}"; + apispotifydomain = "api.spotify.${config.secrets.secrets.global.domains.web}"; ipOf = hostName: lib.net.cidr.host config.secrets.secrets.global.net.ips."${config.guests.${hostName}.nodeName}" config.secrets.secrets.global.net.privateSubnetv4; in { services.nginx = { @@ -179,6 +180,21 @@ in { extraConfig = '' ''; }; + upstreams.apispotify = { + servers."${ipOf "your_spotify"}:8080" = {}; + + extraConfig = '' + zone spotify 64k ; + keepalive 5 ; + ''; + }; + virtualHosts.${apispotifydomain} = { + forceSSL = true; + useACMEHost = "web"; + locations."/".proxyPass = "http://apispotify"; + extraConfig = '' + ''; + }; upstreams.nextcloud = { servers."${ipOf "nextcloud"}:80" = {}; diff --git a/modules/services/your_spotify.nix b/modules/services/your_spotify.nix index 7ac4b79..8bb7566 100644 --- a/modules/services/your_spotify.nix +++ b/modules/services/your_spotify.nix @@ -1,15 +1,18 @@ {config, ...}: { imports = [./your_spotify_m.nix]; age.secrets.spotify = { - inherit (config.services.your_spotify) user group; + owner = "your_spotify"; + mode = "440"; rekeyFile = ../../secrets/your_spotify.age; }; services.your_spotify = { enable = true; - config = { - clientEndpoint = "https://spotify.${config.secrets.secrets.global.domains.web}"; - apiEndpoint = "https://api.spotify.${config.secrets.secrets.global.domains.web}"; + settings = { + CLIENT_ENDPOINT = "https://spotify.${config.secrets.secrets.global.domains.web}"; + API_ENDPOINT = "https://api.spotify.${config.secrets.secrets.global.domains.web}"; }; + enableLocalDB = true; + enableNginxVirtualHost = true; environmentFile = config.age.secrets.spotify.path; }; environment.persistence."/persist".directories = [ diff --git a/modules/services/your_spotify_m.nix b/modules/services/your_spotify_m.nix index 90d6cd1..da8cc19 100644 --- a/modules/services/your_spotify_m.nix +++ b/modules/services/your_spotify_m.nix @@ -28,7 +28,7 @@ then boolToString value else toString value; }) - cfg.config; + cfg.settings; configFile = pkgs.writeText "your_spotify.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv)); in { @@ -44,20 +44,20 @@ in { clientPackage = mkOption { type = package; - default = cfg.package.client.override {inherit (cfg.config) apiEndpoint;}; + default = cfg.package.client.override {apiEndpoint = cfg.settings.API_ENDPOINT;}; description = "Client package to use."; }; settings = mkOption { type = types.submodule { - freeformType = types.attrOf types.str; + freeformType = types.attrsOf types.str; options = { - clientEndpoint = mkOption { + CLIENT_ENDPOINT = mkOption { type = str; description = "The endpoint of your web application"; example = "https://your_spotify.example.org"; }; - apiEndpoint = mkOption { + API_ENDPOINT = mkOption { type = str; description = '' The endpoint of your server @@ -170,20 +170,58 @@ in { EnvironmentFile = [configFile] ++ optional (cfg.environmentFile != null) cfg.environmentFile; ExecStartPre = "${pkgs.your_spotify}/bin/your_spotify_migrate"; ExecStart = "${pkgs.your_spotify}/bin/your_spotify_server"; + StateDirectory = "your_spotify"; LimitNOFILE = "1048576"; PrivateTmp = true; PrivateDevices = true; - ProtectHome = true; - ProtectSystem = "strict"; - StateDirectory = "your_spotify"; StateDirectoryMode = "0700"; Restart = "always"; + + # Hardening + CapabilityBoundingSet = ""; + LockPersonality = true; + MemoryDenyWriteExecute = true; + DevicePolicy = "closed"; + SupplementaryGroups = ["dialout"]; + #NoNewPrivileges = true; # Implied by DynamicUser + PrivateUsers = true; + #PrivateTmp = true; # Implied by DynamicUser + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = false; # breaks bwrap + ProtectKernelLogs = false; # breaks bwrap + ProtectKernelModules = true; + ProtectKernelTunables = false; # breaks bwrap + ProtectProc = "invisible"; + ProcSubset = "all"; # Using "pid" breaks bwrap + ProtectSystem = "strict"; + #RemoveIPC = true; # Implied by DynamicUser + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_NETLINK" + "AF_UNIX" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + #RestrictSUIDSGID = true; # Implied by DynamicUser + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "@mount" # Required by platformio for chroot + ]; + UMask = "0077"; }; wantedBy = ["multi-user.target"]; }; - services.nginx = { + services.nginx = mkIf cfg.enableNginxVirtualHost { enable = true; - virtualHosts.${cfg.clientEndpoint}.root = cfg.clientPackage; + virtualHosts.${cfg.settings.CLIENT_ENDPOINT} = { + locations."/".extraConfig = '' + try_files = "$uri $uri/ /index.html; + ''; + }; }; services.mongodb = mkIf cfg.enableLocalDB { enable = true; diff --git a/pkgs/your_spotify.nix b/pkgs/your_spotify.nix index 6c9171c..96035c2 100644 --- a/pkgs/your_spotify.nix +++ b/pkgs/your_spotify.nix @@ -5,7 +5,7 @@ makeWrapper, nodejs, lib, - apiEndpoint ? "localhost:8080", + callPackage, }: let version = "1.7.3"; src_o = fetchFromGitHub { @@ -14,33 +14,7 @@ rev = "refs/tags/${version}"; hash = "sha256-/0xKktywwGcqsuwLytWBJ3O6ADHg1nP6BdMRlkW5ErY="; }; - client = mkYarnPackage rec { - inherit version; - pname = "your_spotify_client"; - src = "${src_o}/client"; - offlineCache = fetchYarnDeps { - yarnLock = src + "/yarn.lock"; - hash = "sha256-9UfRVv7M9311lesnr19oThYnzB9cK23XNZejJY/Fd24="; - }; - postPatch = '' - substituteInPlace tsconfig.json --replace-quiet '"extends": "../tsconfig.json",' "" - ''; - buildPhase = '' - runHook preBuild - pushd ./deps/client_ts - yarn --offline run build - popd - runHook postBuild - ''; - nativeBuildInputs = [makeWrapper]; - installPhase = '' - mkdir -p $out - cp -r ./deps/client_ts/build/* $out - substituteInPlace $out/variables-template.js --replace-quiet '__API_ENDPOINT__' "${apiEndpoint}" - mv $out/variables-template.js $out/variables.js - ''; - doDist = false; - }; + client = callPackage ./your_spotify_client.nix {inherit src_o version;}; in mkYarnPackage rec { inherit version; diff --git a/pkgs/your_spotify_client.nix b/pkgs/your_spotify_client.nix new file mode 100644 index 0000000..c4fb8fc --- /dev/null +++ b/pkgs/your_spotify_client.nix @@ -0,0 +1,35 @@ +{ + mkYarnPackage, + makeWrapper, + fetchYarnDeps, + apiEndpoint ? "localhost:8080", + src_o, + version, +}: +mkYarnPackage rec { + inherit version; + pname = "your_spotify_client"; + src = "${src_o}/client"; + offlineCache = fetchYarnDeps { + yarnLock = src + "/yarn.lock"; + hash = "sha256-9UfRVv7M9311lesnr19oThYnzB9cK23XNZejJY/Fd24="; + }; + postPatch = '' + substituteInPlace tsconfig.json --replace-quiet '"extends": "../tsconfig.json",' "" + ''; + buildPhase = '' + runHook preBuild + pushd ./deps/client_ts + yarn --offline run build + popd + runHook postBuild + ''; + nativeBuildInputs = [makeWrapper]; + installPhase = '' + mkdir -p $out + cp -r ./deps/client_ts/build/* $out + substituteInPlace $out/variables-template.js --replace-quiet '__API_ENDPOINT__' "${apiEndpoint}" + mv $out/variables-template.js $out/variables.js + ''; + doDist = false; +} diff --git a/users/common/graphical/sway3.nix b/users/common/graphical/sway3.nix index 19d6000..edcf35c 100644 --- a/users/common/graphical/sway3.nix +++ b/users/common/graphical/sway3.nix @@ -40,7 +40,7 @@ let "2:d" = [ {class = "^firefox$";} ]; - "1:1" = [ + "2:2" = [ {class = "^spotify$";} ]; "3:u" = [