12{ lib }:3let4 inherit (lib.trivial) isFunction functionArgs;5 inherit (lib.options) mkOption mergeOneOption;6 inherit (lib.modules) mkOverride;7 inherit (lib.types)8 listOf9 submodule10 attrsOf11 mkOptionType12 ;13 inherit (lib.strings) optionalString hasPrefix removePrefix;14in15rec {16 types = {17 overlay = mkOptionType {18 name = "nixpkgs-overlay";19 description = "nixpkgs overlay";20 check = {21 __functor = _self: isFunction;22 isV2MergeCoherent = true;23 };24 merge = mergeOneOption;25 };26 listOfOverlay = listOf types.overlay;2728 mkHostsType = module: attrsOf (submodule module);29 mkDataType = module: submodule module;30 };3132 options = {33 mkHostsOption =34 module:35 mkOption {36 type = types.mkHostsType module;37 };38 mkDataOption =39 module:40 mkOption {41 type = types.mkDataType module;42 };43 };4445 inherit (options) mkHostsOption;4647 modules = {48 495051 mkFleetDefault = mkOverride 999;52 535455 mkFleetGeneratorDefault = mkOverride 1001;56 };5758 inherit (modules) mkFleetDefault mkFleetGeneratorDefault;5960 secrets = {6162 6364656667686970717273 mkPassword =74 {75 size ? 32,76 }:77 (78 {79 coreutils,80 mkSecretGenerator,81 }:82 mkSecretGenerator {83 script = ''84 mkdir $out85 gh generate password -o $out/secret --size ${toString size}86 '';87 parts.secret.encrypted = true;88 }89 );9091 9293949596979899100101102103104 mkEd25519 =105 {106 noEmbedPublic ? false,107 encoding ? null,108 }:109 (110 { mkSecretGenerator }:111 mkSecretGenerator {112 script = ''113 mkdir $out114 gh generate ed25519 -p $out/public -s $out/secret \115 ${optionalString noEmbedPublic "--no-embed-public"} \116 ${optionalString (encoding != null) "--encoding=${encoding}"}117 '';118 parts.secret.encrypted = true;119 parts.public.encrypted = false;120 }121 );122123 124125126127128129130131132133134 mkX25519 =135 {136 encoding ? null,137 }:138 (139 { mkSecretGenerator }:140 mkSecretGenerator {141 script = ''142 mkdir $out143 gh generate x25519 -p $out/public -s $out/secret \144 ${optionalString (encoding != null) "--encoding=${encoding}"}145 '';146147 parts.secret.encrypted = true;148 parts.public.encrypted = false;149 }150 );151152 mkAskPass =153 {154 prompt ? "Secret value",155 part ? "secret",156 }:157 (158 {159 kdePackages,160 mkImpureSecretGenerator,161 }:162 mkImpureSecretGenerator {163 script = ''164 mkdir $out165 ${kdePackages.kdialog}/bin/kdialog --inputbox "${prompt}" | gh private -o $out/${part}166 '';167168 parts.${part}.encrypted = true;169 }170 );171172 mkAskFile =173 {174 header ? "",175 part ? "secret",176 }:177 (178 {179 kdePackages,180 coreutils,181 mkImpureSecretGenerator,182 }:183 mkImpureSecretGenerator {184 script = ''185 mkdir $out186 tmpfile=$(${coreutils}/bin/mktemp)187 trap "${coreutils}/bin/rm -f $tmpfile" EXIT188 cat > "$tmpfile" <<'HEADER'189 ${header}190 HEADER191 ${kdePackages.kate}/bin/kate --startanon --new --block "$tmpfile"192 gh private -o $out/${part} < "$tmpfile"193 '';194195 parts.${part}.encrypted = true;196 }197 );198199 mkAskEnv =200 {201 header ? "",202 variables ? [ ],203 part ? "secret",204 }:205 mkAskFile {206 inherit part;207 header = builtins.concatStringsSep "\n" (208 (map (l: "# ${l}") (lib.splitString "\n" header))209 ++ (map (v: "${v}=") variables)210 );211 };212213 214215216217218219220221222223 mkRsa =224 {225 size ? 4096,226 }:227 (228 {229 openssl,230 mkSecretGenerator,231 }:232 mkSecretGenerator {233 script = ''234 mkdir $out235236 ${openssl}/bin/openssl genrsa -out rsa_private.key ${toString size}237 ${openssl}/bin/openssl rsa -in rsa_private.key -pubout -out rsa_public.key238239 cat rsa_private.key | gh private -o $out/secret240 cat rsa_public.key | gh public -o $out/public241 '';242243 parts.secret.encrypted = true;244 parts.public.encrypted = false;245 }246 );247248 249250251252253254255256257258259260261262 mkBytes =263 {264 count ? 32,265 encoding,266 noNuls ? false,267 }:268 (269 { mkSecretGenerator }:270 mkSecretGenerator {271 script = ''272 mkdir $out273 gh generate bytes --count=${toString count} --encoding=${encoding} -o $out/secret \274 ${optionalString noNuls "--no-nuls"}275 '';276 parts.secret.encrypted = true;277 }278 );279 280281282 mkHexBytes =283 {284 count ? 32,285 }:286 mkBytes {287 inherit count;288 encoding = "hex";289 };290 291292293 mkBase64Bytes =294 {295 count ? 32,296 }:297 mkBytes {298 inherit count;299 encoding = "base64";300 };301302 303 304 305 };306307 inherit (secrets)308 mkPassword309 mkEd25519310 mkX25519311 mkRsa312 mkBytes313 mkHexBytes314 mkBase64Bytes315 mkAskPass316 mkAskFile317 mkAskEnv318 ;319320 strings =321 let322 plaintextPrefix = "<PLAINTEXT>";323 plaintextNewlinePrefix = "<PLAINTEXT-NL>";324 in325 {326 327328329 decodeRawSecret =330 raw:331 if hasPrefix plaintextPrefix raw then332 removePrefix plaintextPrefix raw333 else if hasPrefix plaintextNewlinePrefix raw then334 removePrefix plaintextNewlinePrefix raw335 else336 throw "decodeRawSecret only works with plaintext-encoded secret public parts, got ${raw}";337 };338339 inherit (strings) decodeRawSecret;340}