···
folderDevices = folder.devices;
62
-
if builtins.isList folderDevices then
65
-
if builtins.isString device then { deviceId = cfg.settings.devices.${device}.id; } else device
67
-
else if builtins.isAttrs folderDevices then
69
-
deviceName: deviceValue: deviceValue // { deviceId = cfg.settings.devices.${deviceName}.id; }
72
-
throw "Invalid type for devices in folder '${folderName}'; expected list or attrset.";
64
+
if builtins.isString device then
65
+
{ deviceId = cfg.settings.devices.${device}.id; }
66
+
else if builtins.isAttrs device then
67
+
{ deviceId = cfg.settings.devices.${device.name}.id; } // device
69
+
throw "Invalid type for devices in folder '${folderName}'; expected list or attrset."
) (filterAttrs (_: folder: folder.enable) cfg.settings.folders);
···
145
-
isSecret = attr: value: builtins.isString value && attr == "encryptionPassword";
149
-
if builtins.isAttrs value then
150
-
# Attribute set: process each attribute
151
-
builtins.mapAttrs (name: val: resolveSecrets name val) value
152
-
else if builtins.isList value then
153
-
# List: process each element
154
-
map (item: resolveSecrets "" item) value
155
-
else if isSecret attr value then
156
-
# String that looks like a path: replace with placeholder
158
-
varName = "secret_${builtins.hashString "sha256" value}";
162
-
# Other types: return as is
165
-
# Function to collect all file paths from the configuration
168
-
if builtins.isAttrs value then
169
-
concatMap (name: collectPaths name value.${name}) (builtins.attrNames value)
170
-
else if builtins.isList value then
171
-
concatMap (name: collectPaths "" name) value
172
-
else if isSecret attr value then
177
-
# Function to generate variable assignments for the secrets
178
-
generateSecretVars =
180
-
concatStringsSep "\n" (
143
+
jsonPreSecretsFile = pkgs.writeTextFile {
144
+
name = "${conf_type}-${new_cfg.id}-conf-pre-secrets.json";
145
+
text = builtins.toJSON new_cfg;
147
+
injectSecretsJqCmd =
149
+
# There are no secrets in `devs`, so no massaging needed.
150
+
"devs" = "${jq} .";
184
-
varName = "secret_${builtins.hashString "sha256" path}";
154
+
devicesWithSecrets = lib.pipe folder.devices [
155
+
(lib.filter (device: (builtins.isAttrs device) && device ? encryptionPasswordFile))
157
+
deviceId = device.deviceId;
158
+
variableName = "secret_${builtins.hashString "sha256" device.encryptionPasswordFile}";
159
+
secretPath = device.encryptionPasswordFile;
162
+
# At this point, `jsonPreSecretsFile` looks something like this:
168
+
# "deviceId": "id1",
169
+
# "encryptionPasswordFile": "/etc/bar-encryption-password",
175
+
# We now generate a `jq` command that can replace those
176
+
# `encryptionPasswordFile`s with `encryptionPassword`.
177
+
# The `jq` command ends up looking like this:
179
+
# jq --rawfile secret_DEADBEEF /etc/bar-encryption-password '
181
+
# if .deviceId == "id1" then
182
+
# del(.encryptionPasswordFile) |
183
+
# .encryptionPassword = $secret_DEADBEEF
189
+
jqUpdates = map (device: ''
191
+
if .deviceId == "${device.deviceId}" then
192
+
del(.encryptionPasswordFile) |
193
+
.encryptionPassword = ''$${device.variableName}
198
+
'') devicesWithSecrets;
200
+
device: "--rawfile ${device.variableName} ${lib.escapeShellArg device.secretPath}"
201
+
) devicesWithSecrets;
187
-
if [ ! -r ${path} ]; then
188
-
echo "${path} does not exist"
191
-
${varName}=$(<${path})
196
-
resolved_cfg = resolveSecrets "" new_cfg;
197
-
secretPaths = collectPaths "" new_cfg;
198
-
secretVarsScript = generateSecretVars secretPaths;
200
-
jsonString = builtins.toJSON resolved_cfg;
201
-
escapedJson = builtins.replaceStrings [ "\"" ] [ "\\\"" ] jsonString;
203
+
"${jq} ${lib.concatStringsSep " " jqRawFiles} ${
204
+
lib.escapeShellArg (lib.concatStringsSep "|" ([ "." ] ++ jqUpdates))
204
-
${secretVarsScript}
206
-
curl -d "${escapedJson}" -X POST ${s.baseAddress}
210
+
${injectSecretsJqCmd} ${jsonPreSecretsFile} | curl --json @- -X POST ${s.baseAddress}
(lib.concatStringsSep "\n")
···
516
-
type = types.oneOf [
517
-
(types.listOf types.str)
520
+
type = types.listOf (
freeformType = settingsFormat.type;
524
-
encryptionPassword = mkOption {
525
-
type = types.nullOr types.str;
532
+
The name of a device defined in the
533
+
[devices](#opt-services.syncthing.settings.devices)
537
+
encryptionPasswordFile = mkOption {
538
+
type = types.nullOr (
Path to encryption password. If set, the file will be read during
···
The devices this folder should be shared with. Each device must
be defined in the [devices](#opt-services.syncthing.settings.devices) option.
542
-
Either a list of strings, or an attribute set, where keys are defined in the
543
-
[devices](#opt-services.syncthing.settings.devices) option, and values are
544
-
device configurations.
560
+
A list of either strings or attribute sets, where values
561
+
are device names or device configurations.