From 2562c39884bcd5c919fe09058825043ce14e3a31 Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 6 Mar 2024 15:48:10 +0100 Subject: [PATCH 1/4] maintainers: add patrickdag --- maintainers/maintainer-list.nix | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index 789da06a6adc798..7690f276cf71d2c 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -15482,6 +15482,15 @@ githubId = 69802930; name = "patka"; }; + patrickdag = { + email = "patrick-nixos@failmail.dev"; + github = "PatrickDaG"; + githubId = 58092422; + name = "Patrick"; + keys = [{ + fingerprint = "5E4C 3D74 80C2 35FE 2F0B D23F 7DD6 A72E C899 617D"; + }]; + }; patricksjackson = { email = "patrick@jackson.dev"; github = "patricksjackson"; From 86feff1d442f4fca39512d8f686f43e8edad4372 Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 6 Mar 2024 16:49:40 +0100 Subject: [PATCH 2/4] your_spotify: init at 1.10.1 --- pkgs/by-name/yo/your_spotify/client.nix | 58 ++++++++++++++++ pkgs/by-name/yo/your_spotify/package.json | 10 +++ pkgs/by-name/yo/your_spotify/package.nix | 85 +++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 pkgs/by-name/yo/your_spotify/client.nix create mode 100644 pkgs/by-name/yo/your_spotify/package.json create mode 100644 pkgs/by-name/yo/your_spotify/package.nix diff --git a/pkgs/by-name/yo/your_spotify/client.nix b/pkgs/by-name/yo/your_spotify/client.nix new file mode 100644 index 000000000000000..420498821bf93ac --- /dev/null +++ b/pkgs/by-name/yo/your_spotify/client.nix @@ -0,0 +1,58 @@ +{ + apiEndpoint ? "http://localhost:3000", + fetchYarnDeps, + your_spotify, + mkYarnPackage, + fixup-yarn-lock, + src, + version, + yarn, +}: +mkYarnPackage rec { + inherit version src; + pname = "your_spotify_client"; + name = "your_spotify_client-${version}"; + packageJSON = ./package.json; + offlineCache = fetchYarnDeps { + yarnLock = src + "/yarn.lock"; + hash = "sha256-5SgknaRVzgO2Dzc8MhAaM8UERWMv+PrItzevoWHbWnA="; + }; + configurePhase = '' + runHook preConfigure + + export HOME=$(mktemp -d) + yarn config --offline set yarn-offline-mirror $offlineCache + fixup-yarn-lock yarn.lock + yarn install --offline --frozen-lockfile --ignore-platform --ignore-scripts --no-progress --non-interactive + patchShebangs node_modules/ + + runHook postConfigure + ''; + buildPhase = '' + runHook preBuild + pushd ./apps/client/ + yarn --offline run build + export API_ENDPOINT="${apiEndpoint}" + substituteInPlace scripts/run/variables.sh --replace-quiet '/app/apps/client/' "./" + + chmod +x ./scripts/run/variables.sh + patchShebangs --build ./scripts/run/variables.sh + + ./scripts/run/variables.sh + + popd + runHook postBuild + ''; + nativeBuildInputs = [yarn fixup-yarn-lock]; + + installPhase = '' + runHook preInstall + mkdir -p $out + cp -r ./apps/client/build/* $out + runHook postInstall + ''; + doDist = false; + meta = { + inherit (your_spotify.meta) homepage changelog description license maintainers; + }; +} diff --git a/pkgs/by-name/yo/your_spotify/package.json b/pkgs/by-name/yo/your_spotify/package.json new file mode 100644 index 000000000000000..8c10988ffb6d2ce --- /dev/null +++ b/pkgs/by-name/yo/your_spotify/package.json @@ -0,0 +1,10 @@ +{ + "name": "@your_spotify/root", + "version": "1.10.1", + "repository": "git@github.com:Yooooomi/your_spotify.git", + "author": "Timothee ", + "private": true, + "workspaces": [ + "apps/*" + ] +} diff --git a/pkgs/by-name/yo/your_spotify/package.nix b/pkgs/by-name/yo/your_spotify/package.nix new file mode 100644 index 000000000000000..0296b9d22c0285e --- /dev/null +++ b/pkgs/by-name/yo/your_spotify/package.nix @@ -0,0 +1,85 @@ +{ + callPackage, + fetchFromGitHub, + fetchYarnDeps, + lib, + makeWrapper, + mkYarnPackage, + nodejs, + fixup-yarn-lock, + yarn, +}: let + version = "1.10.1"; + src = fetchFromGitHub { + owner = "Yooooomi"; + repo = "your_spotify"; + rev = "refs/tags/${version}"; + hash = "sha256-e82j2blGxQLWAlBNuAnFvlD9vwMk4/mRI0Vf7vuaPA0="; + }; + client = callPackage ./client.nix {inherit src version;}; +in + mkYarnPackage rec { + inherit version src; + pname = "your_spotify_server"; + name = "your_spotify_server-${version}"; + packageJSON = ./package.json; + offlineCache = fetchYarnDeps { + yarnLock = src + "/yarn.lock"; + hash = "sha256-5SgknaRVzgO2Dzc8MhAaM8UERWMv+PrItzevoWHbWnA="; + }; + + configurePhase = '' + runHook preConfigure + + export HOME=$(mktemp -d) + yarn config --offline set yarn-offline-mirror $offlineCache + fixup-yarn-lock yarn.lock + + runHook postConfigure + ''; + + buildPhase = '' + runHook preBuild + + yarn install --offline --frozen-lockfile --ignore-platform --ignore-scripts --no-progress --non-interactive + patchShebangs node_modules/ + + pushd ./apps/server/ + yarn --offline run build + popd + + rm -r node_modules + export NODE_ENV="production" + yarn install --offline --frozen-lockfile --ignore-platform --ignore-scripts --no-progress --non-interactive + patchShebangs node_modules/ + + runHook postBuild + ''; + nativeBuildInputs = [makeWrapper yarn fixup-yarn-lock]; + installPhase = '' + runHook preInstall + + mkdir -p $out/share/your_spotify + cp -r node_modules $out/share/your_spotify/node_modules + cp -r ./apps/server/{lib,package.json} $out + mkdir -p $out/bin + makeWrapper ${lib.escapeShellArg (lib.getExe nodejs)} "$out/bin/your_spotify_migrate" \ + --add-flags "$out/lib/migrations.js" --set NODE_PATH "$out/share/your_spotify/node_modules" + makeWrapper ${lib.escapeShellArg (lib.getExe nodejs)} "$out/bin/your_spotify_server" \ + --add-flags "$out/lib/index.js" --set NODE_PATH "$out/share/your_spotify/node_modules" + + runHook postInstall + ''; + doDist = false; + passthru = { + inherit client; + }; + meta = with lib; { + homepage = "https://github.com/Yooooomi/your_spotify"; + changelog = "https://github.com/Yooooomi/your_spotify/releases/tag/${version}"; + description = "Self-hosted application that tracks what you listen and offers you a dashboard to explore statistics about it"; + license = licenses.gpl3Only; + maintainers = with maintainers; [patrickdag]; + mainProgram = "your_spotify_server"; + }; + } From 77a6460e741a0d7ef22e2382573e32771c7911ca Mon Sep 17 00:00:00 2001 From: Patrick Date: Sat, 13 Apr 2024 10:58:52 +0200 Subject: [PATCH 3/4] nixos/your_spotify: init --- .../manual/release-notes/rl-2405.section.md | 2 + nixos/modules/module-list.nix | 1 + .../services/web-apps/your_spotify.nix | 191 ++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 nixos/modules/services/web-apps/your_spotify.nix diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index 489474468466cad..d6b8ffe8609fa96 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -187,6 +187,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m - [xdg-terminal-exec](https://github.com/Vladimir-csp/xdg-terminal-exec), the proposed Default Terminal Execution Specification. +- [your_spotify](https://github.com/Yooooomi/your_spotify), a self hosted Spotify tracking dashboard. Available as [services.your_spotify](#opt-services.your_spotify.enable) + - [RustDesk](https://rustdesk.com), a full-featured open source remote control alternative for self-hosting and security with minimal configuration. Alternative to TeamViewer. Available as [services.rustdesk-server](#opt-services.rustdesk-server.enable). - [Scrutiny](https://github.com/AnalogJ/scrutiny), a S.M.A.R.T monitoring tool for hard disks with a web frontend. Available as [services.scrutiny](#opt-services.scrutiny.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index a92ae32d06fa241..b14b83a8119ac66 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1431,6 +1431,7 @@ ./services/web-apps/windmill.nix ./services/web-apps/wordpress.nix ./services/web-apps/writefreely.nix + ./services/web-apps/your_spotify.nix ./services/web-apps/youtrack.nix ./services/web-apps/zabbix.nix ./services/web-apps/zitadel.nix diff --git a/nixos/modules/services/web-apps/your_spotify.nix b/nixos/modules/services/web-apps/your_spotify.nix new file mode 100644 index 000000000000000..3eb2ffef4f9338c --- /dev/null +++ b/nixos/modules/services/web-apps/your_spotify.nix @@ -0,0 +1,191 @@ +{ + pkgs, + config, + lib, + ... +}: let + inherit + (lib) + boolToString + concatMapAttrs + concatStrings + isBool + mapAttrsToList + mkEnableOption + mkIf + mkOption + mkPackageOption + optionalAttrs + types + mkDefault + ; + cfg = config.services.your_spotify; + + configEnv = concatMapAttrs (name: value: + optionalAttrs (value != null) { + ${name} = + if isBool value + then boolToString value + else toString value; + }) + cfg.settings; + + configFile = pkgs.writeText "your_spotify.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv)); +in { + options.services.your_spotify = let + inherit (types) nullOr port str path package; + in { + enable = mkEnableOption "your_spotify"; + + enableLocalDB = mkEnableOption "a local mongodb instance"; + nginxVirtualHost = mkOption { + type = nullOr str; + default = null; + description = '' + If set creates an nginx virtual host for the client. + In most cases this should be the CLIENT_ENDPOINT without + protocol prefix. + ''; + }; + + package = mkPackageOption pkgs "your_spotify" {}; + + clientPackage = mkOption { + type = package; + description = "Client package to use."; + }; + + spotifySecretFile = mkOption { + type = path; + description = '' + A file containing the secret key of your Spotify application. + Refer to: [Creating the Spotify Application](https://github.com/Yooooomi/your_spotify#creating-the-spotify-application). + ''; + }; + + settings = mkOption { + description = '' + Your Spotify Configuration. Refer to [Your Spotify](https://github.com/Yooooomi/your_spotify) for definitions and values. + ''; + example = lib.literalExpression '' + { + CLIENT_ENDPOINT = "https://example.com"; + API_ENDPOINT = "https://api.example.com"; + SPOTIFY_PUBLIC = "spotify_client_id"; + } + ''; + type = types.submodule { + freeformType = types.attrsOf types.str; + options = { + CLIENT_ENDPOINT = mkOption { + type = str; + description = '' + The endpoint of your web application. + Has to include a protocol Prefix (e.g. `http://`) + ''; + example = "https://your_spotify.example.org"; + }; + API_ENDPOINT = mkOption { + type = str; + description = '' + The endpoint of your server + This api has to be reachable from the device you use the website from not from the server. + This means that for example you may need two nginx virtual hosts if you want to expose this on the + internet. + Has to include a protocol Prefix (e.g. `http://`) + ''; + example = "https://localhost:3000"; + }; + SPOTIFY_PUBLIC = mkOption { + type = str; + description = '' + The public client ID of your Spotify application. + Refer to: [Creating the Spotify Application](https://github.com/Yooooomi/your_spotify#creating-the-spotify-application) + ''; + }; + MONGO_ENDPOINT = mkOption { + type = str; + description = ''The endpoint of the Mongo database.''; + default = "mongodb://localhost:27017/your_spotify"; + }; + PORT = mkOption { + type = port; + description = "The port of the api server"; + default = 3000; + }; + }; + }; + }; + }; + + config = mkIf cfg.enable { + services.your_spotify.clientPackage = mkDefault (cfg.package.client.override {apiEndpoint = cfg.settings.API_ENDPOINT;}); + systemd.services.your_spotify = { + after = ["network.target"]; + script = '' + export SPOTIFY_SECRET=$(< "$CREDENTIALS_DIRECTORY/SPOTIFY_SECRET") + ${lib.getExe' cfg.package "your_spotify_migrate"} + exec ${lib.getExe cfg.package} + ''; + serviceConfig = { + User = "your_spotify"; + Group = "your_spotify"; + DynamicUser = true; + EnvironmentFile = [configFile]; + StateDirectory = "your_spotify"; + LimitNOFILE = "1048576"; + PrivateTmp = true; + PrivateDevices = true; + StateDirectoryMode = "0700"; + Restart = "always"; + + LoadCredential = ["SPOTIFY_SECRET:${cfg.spotifySecretFile}"]; + + # Hardening + CapabilityBoundingSet = ""; + LockPersonality = true; + #MemoryDenyWriteExecute = true; # Leads to coredump because V8 does JIT + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProcSubset = "pid"; + ProtectSystem = "strict"; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_NETLINK" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "@pkey" + ]; + UMask = "0077"; + }; + wantedBy = ["multi-user.target"]; + }; + services.nginx = mkIf (cfg.nginxVirtualHost != null) { + enable = true; + virtualHosts.${cfg.nginxVirtualHost} = { + root = cfg.clientPackage; + locations."/".extraConfig = '' + add_header Content-Security-Policy "frame-ancestors 'none';" ; + add_header X-Content-Type-Options "nosniff" ; + try_files = $uri $uri/ /index.html ; + ''; + }; + }; + services.mongodb = mkIf cfg.enableLocalDB { + enable = true; + }; + }; + meta.maintainers = with lib.maintainers; [patrickdag]; +} From 05b36f060da279563ab7097c299a40e9ecfc39f6 Mon Sep 17 00:00:00 2001 From: Patrick Date: Sat, 13 Apr 2024 10:59:11 +0200 Subject: [PATCH 4/4] nixosTests.your_spotify: init --- nixos/tests/all-tests.nix | 1 + nixos/tests/your_spotify.nix | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 nixos/tests/your_spotify.nix diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 3f3a99a83fee071..c6ec2474e605242 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1042,6 +1042,7 @@ in { yabar = handleTest ./yabar.nix {}; ydotool = handleTest ./ydotool.nix {}; yggdrasil = handleTest ./yggdrasil.nix {}; + your_spotify = handleTest ./your_spotify.nix {}; zammad = handleTest ./zammad.nix {}; zeronet-conservancy = handleTest ./zeronet-conservancy.nix {}; zfs = handleTest ./zfs.nix {}; diff --git a/nixos/tests/your_spotify.nix b/nixos/tests/your_spotify.nix new file mode 100644 index 000000000000000..a1fa0e459a8e167 --- /dev/null +++ b/nixos/tests/your_spotify.nix @@ -0,0 +1,33 @@ +import ./make-test-python.nix ({pkgs, ...}: { + name = "your_spotify"; + meta = with pkgs.lib.maintainers; { + maintainers = [patrickdag]; + }; + + nodes.machine = { + services.your_spotify = { + enable = true; + spotifySecretFile = pkgs.writeText "spotifySecretFile" "deadbeef"; + settings = { + CLIENT_ENDPOINT = "http://localhost"; + API_ENDPOINT = "http://localhost:3000"; + SPOTIFY_PUBLIC = "beefdead"; + }; + enableLocalDB = true; + nginxVirtualHost = "localhost"; + }; + }; + + testScript = '' + machine.wait_for_unit("your_spotify.service") + + machine.wait_for_open_port(3000) + machine.wait_for_open_port(80) + + out = machine.succeed("curl --fail -X GET 'http://localhost:3000/'") + assert "Hello !" in out + + out = machine.succeed("curl --fail -X GET 'http://localhost:80/'") + assert "Your Spotify" in out + ''; +})