1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.baget;
8
9 defaultConfig = {
10 "PackageDeletionBehavior" = "Unlist";
11 "AllowPackageOverwrites" = false;
12
13 "Database" = {
14 "Type" = "Sqlite";
15 "ConnectionString" = "Data Source=baget.db";
16 };
17
18 "Storage" = {
19 "Type" = "FileSystem";
20 "Path" = "";
21 };
22
23 "Search" = {
24 "Type" = "Database";
25 };
26
27 "Mirror" = {
28 "Enabled" = false;
29 "PackageSource" = "https://api.nuget.org/v3/index.json";
30 };
31
32 "Logging" = {
33 "IncludeScopes" = false;
34 "Debug" = {
35 "LogLevel" = {
36 "Default" = "Warning";
37 };
38 };
39 "Console" = {
40 "LogLevel" = {
41 "Microsoft.Hosting.Lifetime" = "Information";
42 "Default" = "Warning";
43 };
44 };
45 };
46 };
47
48 configAttrs = recursiveUpdate defaultConfig cfg.extraConfig;
49
50 configFormat = pkgs.formats.json {};
51 configFile = configFormat.generate "appsettings.json" configAttrs;
52
53in
54{
55 options.services.baget = {
56 enable = mkEnableOption (lib.mdDoc "BaGet NuGet-compatible server");
57
58 apiKeyFile = mkOption {
59 type = types.path;
60 example = "/root/baget.key";
61 description = lib.mdDoc ''
62 Private API key for BaGet.
63 '';
64 };
65
66 extraConfig = mkOption {
67 type = configFormat.type;
68 default = {};
69 example = {
70 "Database" = {
71 "Type" = "PostgreSql";
72 "ConnectionString" = "Server=/run/postgresql;Port=5432;";
73 };
74 };
75 defaultText = literalExpression ''
76 {
77 "PackageDeletionBehavior" = "Unlist";
78 "AllowPackageOverwrites" = false;
79
80 "Database" = {
81 "Type" = "Sqlite";
82 "ConnectionString" = "Data Source=baget.db";
83 };
84
85 "Storage" = {
86 "Type" = "FileSystem";
87 "Path" = "";
88 };
89
90 "Search" = {
91 "Type" = "Database";
92 };
93
94 "Mirror" = {
95 "Enabled" = false;
96 "PackageSource" = "https://api.nuget.org/v3/index.json";
97 };
98
99 "Logging" = {
100 "IncludeScopes" = false;
101 "Debug" = {
102 "LogLevel" = {
103 "Default" = "Warning";
104 };
105 };
106 "Console" = {
107 "LogLevel" = {
108 "Microsoft.Hosting.Lifetime" = "Information";
109 "Default" = "Warning";
110 };
111 };
112 };
113 }
114 '';
115 description = lib.mdDoc ''
116 Extra configuration options for BaGet. Refer to <https://loic-sharma.github.io/BaGet/configuration/> for details.
117 Default value is merged with values from here.
118 '';
119 };
120 };
121
122 # implementation
123
124 config = mkIf cfg.enable {
125
126 systemd.services.baget = {
127 description = "BaGet server";
128 wantedBy = [ "multi-user.target" ];
129 wants = [ "network-online.target" ];
130 after = [ "network.target" "network-online.target" ];
131 path = [ pkgs.jq ];
132 serviceConfig = {
133 WorkingDirectory = "/var/lib/baget";
134 DynamicUser = true;
135 StateDirectory = "baget";
136 StateDirectoryMode = "0700";
137 LoadCredential = "api_key:${cfg.apiKeyFile}";
138
139 CapabilityBoundingSet = "";
140 NoNewPrivileges = true;
141 PrivateDevices = true;
142 PrivateTmp = true;
143 PrivateUsers = true;
144 PrivateMounts = true;
145 ProtectHome = true;
146 ProtectClock = true;
147 ProtectProc = "noaccess";
148 ProcSubset = "pid";
149 ProtectKernelLogs = true;
150 ProtectKernelModules = true;
151 ProtectKernelTunables = true;
152 ProtectControlGroups = true;
153 ProtectHostname = true;
154 RestrictSUIDSGID = true;
155 RestrictRealtime = true;
156 RestrictNamespaces = true;
157 LockPersonality = true;
158 RemoveIPC = true;
159 RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
160 SystemCallFilter = [ "@system-service" "~@privileged" ];
161 };
162 script = ''
163 jq --slurpfile apiKeys <(jq -R . "$CREDENTIALS_DIRECTORY/api_key") '.ApiKey = $apiKeys[0]' ${configFile} > appsettings.json
164 ln -snf ${pkgs.baget}/lib/BaGet/wwwroot wwwroot
165 exec ${pkgs.baget}/bin/BaGet
166 '';
167 };
168
169 };
170}