From 19b60de3f2c65f19ed741fb27bfb071c7cae58d4 Mon Sep 17 00:00:00 2001 From: cinereal Date: Mon, 9 Jun 2025 22:22:25 +0200 Subject: [PATCH] escape json --- flake.nix | 2 +- lib.nix | 20 +++++++++++++------- pkgs/nix_templater/replace.py | 4 +++- tests/json.nix | 7 +++++-- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/flake.nix b/flake.nix index 9e4af24..3ead877 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,6 @@ { inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; - outputs = { nixpkgs, ... }@self: let + outputs = { nixpkgs, ... }: let supportedArchitectures = [ "aarch64-darwin" "aarch64-linux" diff --git a/lib.nix b/lib.nix index 9bf4642..c5c815e 100644 --- a/lib.nix +++ b/lib.nix @@ -1,4 +1,10 @@ { pkgs, lib, nix_templater }: +let + escapeJson = { + "\"" = ''\"''; + "\\" = ''\\''; + }; +in rec { # placeholder to be substituted with the content of a secret file fileContents = file: { @@ -7,12 +13,12 @@ rec { }; # make a template with placeholders - templateText = { name, text, outPath }: + templateText = { name, text, outPath, translations ? {} }: pkgs.runCommand name { textBeforeTemplate = text; script = '' #!/bin/sh - ${nix_templater}/bin/nix_templater ${builtins.placeholder "out"}/template ${builtins.placeholder "nix_template"} "${outPath}" + ${nix_templater}/bin/nix_templater ${builtins.placeholder "out"}/template ${builtins.placeholder "nix_template"} "${outPath}" '${lib.strings.toJSON translations}' ''; passAsFile = [ "script" "textBeforeTemplate" ]; } '' @@ -22,14 +28,14 @@ rec { chmod +x $out/bin/${name} ''; - templateGenerator = generator: { name, value, outPath }: templateText { - inherit name outPath; + templateGenerator = translations: generator: { name, value, outPath }: templateText { + inherit name outPath translations; text = generator value; }; - templateJsonWith = options: templateGenerator (lib.generators.toJSON options); - templateYamlWith = options: templateGenerator (lib.generators.toYAML options); # just json - templateIniWith = options: templateGenerator (lib.generators.toINI options); + templateJsonWith = options: templateGenerator escapeJson (lib.generators.toJSON options); + templateYamlWith = options: templateGenerator escapeJson (lib.generators.toYAML options); # just json + templateIniWith = options: templateGenerator escapeJson (lib.generators.toINI options); templateJson = templateJsonWith { }; templateYaml = templateYamlWith { }; templateIni = templateIniWith { }; diff --git a/pkgs/nix_templater/replace.py b/pkgs/nix_templater/replace.py index 50ff7c5..bb38e77 100644 --- a/pkgs/nix_templater/replace.py +++ b/pkgs/nix_templater/replace.py @@ -1,10 +1,12 @@ # replace occurrences of a magic string in a template file +from json import loads import sys from pathlib import Path template_file = sys.argv[1] magic_string = sys.argv[2] outfile = sys.argv[3] +translations = loads(sys.argv[4]) if len(sys.argv) >= 4 else {} if Path(outfile).exists(): print(f"{outfile} already exists, aborting") @@ -26,7 +28,7 @@ while True: ] output += template_bytes[loc : loc + magic_start] # TODO handle errors better here - output += Path(magic_file.decode()).read_bytes() + output += Path(magic_file.decode()).read_bytes().decode().translate(str.maketrans(translations)).encode() loc = loc + magic_start + magic_end + len(magic_string) + 1 Path(outfile).write_bytes(output) diff --git a/tests/json.nix b/tests/json.nix index 0c5eeed..28a3ed4 100644 --- a/tests/json.nix +++ b/tests/json.nix @@ -1,9 +1,10 @@ # test injecting a secret into a json template { legacyPackages, system, nixpkgs }: let - secret_file = (nixpkgs.legacyPackages.${system}.writeText "secret" "secret"); + hostPkgs = nixpkgs.legacyPackages.${system}; + secret_file = hostPkgs.writeText "secret" "secret\\needing\"escaping"; in (nixpkgs.lib.nixos.runTest { - hostPkgs = nixpkgs.legacyPackages.${system}; + inherit hostPkgs; name = "nix_templates"; nodes.machine = {pkgs, ...}: { @@ -33,6 +34,8 @@ in (nixpkgs.lib.nixos.runTest { start_all() print(machine.execute("uname -a")) machine.wait_for_unit("multi-user.target") + print(machine.succeed("cat /test")) print(machine.succeed("cat /test | grep -q secret")) + print(machine.succeed("cat /test | ${hostPkgs.jq}/bin/jq")) ''; })