From 3fd3ca2b106d2451f997d3f0538bc3717d6d94e2 Mon Sep 17 00:00:00 2001 From: Spencer Brower Date: Tue, 28 Apr 2026 18:03:06 -0400 Subject: [PATCH] feat: Created own age wrapper. --- build.zig.zon | 2 + fixtures/encrypted-example.db.age | Bin 0 -> 8404 bytes fixtures/hello-world.age | 5 + fixtures/hello-world.txt | 1 + fixtures/insecure-test-key | 7 ++ fixtures/insecure-test-key.pub | 1 + flake.nix | 3 +- src/age.zig | 133 +++++++++++++++++++++++++++ src/db.zig | 50 ++++++++++ zig-vendor/age-ffi/zig/build.zig | 7 +- zig-vendor/age-ffi/zig/build.zig.zon | 9 ++ 11 files changed, 213 insertions(+), 5 deletions(-) create mode 100644 fixtures/encrypted-example.db.age create mode 100644 fixtures/hello-world.age create mode 100644 fixtures/hello-world.txt create mode 100644 fixtures/insecure-test-key create mode 100644 fixtures/insecure-test-key.pub create mode 100644 src/age.zig create mode 100644 zig-vendor/age-ffi/zig/build.zig.zon diff --git a/build.zig.zon b/build.zig.zon index 9f30ffd..11880fe 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -32,7 +32,9 @@ // Once all dependencies are fetched, `zig build` no longer requires // internet connectivity. .dependencies = .{ + // .age = .{ .path = "zig-vendor/age-ffi/zig" }, .sqlite = .{ .path = "zig-vendor/zig-sqlite" }, + // See `zig fetch --save ` for a command-line interface for adding dependencies. //.example = .{ // // When updating this field to a new URL, be sure to delete the corresponding diff --git a/fixtures/encrypted-example.db.age b/fixtures/encrypted-example.db.age new file mode 100644 index 0000000000000000000000000000000000000000..7a66592311c0c829dbc8742095a811c5d7e4ed76 GIT binary patch literal 8404 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 YzZ(DEO=nNeYVN&X9B68rCOqLX0NcAeumAu6 literal 0 HcmV?d00001 diff --git a/fixtures/hello-world.age b/fixtures/hello-world.age new file mode 100644 index 0000000..681af94 --- /dev/null +++ b/fixtures/hello-world.age @@ -0,0 +1,5 @@ +age-encryption.org/v1 +-> ssh-ed25519 Boe0UQ 2ngx7jSJ8/yuAzTgeiiCTYZRSkBCeJfaHTL0u7k6ziU +0XmEy0bOTeW1MF9ev32n4xISPDl9UQNHzEB0vsZHDuU +--- UV7IjWFCCg79Pf3T9vUWBxT4MhgeARWp6E+LK9tMy1g +uNo2Z݅++Yy:@' NxP \ No newline at end of file diff --git a/fixtures/hello-world.txt b/fixtures/hello-world.txt new file mode 100644 index 0000000..8ab686e --- /dev/null +++ b/fixtures/hello-world.txt @@ -0,0 +1 @@ +Hello, World! diff --git a/fixtures/insecure-test-key b/fixtures/insecure-test-key new file mode 100644 index 0000000..0f85442 --- /dev/null +++ b/fixtures/insecure-test-key @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACCbll0MJper9prPwGn2wwikH3hTByL8tlzmhViuvfrryAAAAJCkxfzapMX8 +2gAAAAtzc2gtZWQyNTUxOQAAACCbll0MJper9prPwGn2wwikH3hTByL8tlzmhViuvfrryA +AAAEDXQExhs89b3fjqJHkhuo9QX4JEjXiEC+vSnCAYc8OxcpuWXQwml6v2ms/AafbDCKQf +eFMHIvy2XOaFWK69+uvIAAAACnNwZW5jZXJAZncBAgM= +-----END OPENSSH PRIVATE KEY----- diff --git a/fixtures/insecure-test-key.pub b/fixtures/insecure-test-key.pub new file mode 100644 index 0000000..8f8eb26 --- /dev/null +++ b/fixtures/insecure-test-key.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJuWXQwml6v2ms/AafbDCKQfeFMHIvy2XOaFWK69+uvI spencer@fw diff --git a/flake.nix b/flake.nix index e9b788c..c38d0a5 100644 --- a/flake.nix +++ b/flake.nix @@ -104,8 +104,9 @@ unstable.ols # Build tools - zip + age unstable.cargo + zip opencode diff --git a/src/age.zig b/src/age.zig new file mode 100644 index 0000000..f934173 --- /dev/null +++ b/src/age.zig @@ -0,0 +1,133 @@ +const std = @import("std"); + +/// Returns the decrypted contents of the file. +/// Caller is responsible for freeing the memory. +pub fn decrypt( + io: std.Io, + gpa: std.mem.Allocator, + private_key: []const u8, + input_path: []const u8, + output_path: []const u8, +) !void { + const result = try std.process.run(gpa, io, .{ + .argv = &.{ + "age", + "-d", + "-i", + private_key, + "-o", + output_path, + input_path, + }, + }); + defer gpa.free(result.stderr); + defer gpa.free(result.stdout); + + if (result.stdout.len > 0) { + std.debug.print("stdout: \"{s}\"\n", .{result.stdout}); + unreachable; + } + + if (result.stderr.len > 0) { + std.debug.print("stderr: \"{s}\"\n", .{result.stderr}); + unreachable; + } +} + +/// Returns the encrypted contents of the file. +/// Caller is responsible for freeing the memory. +pub fn encrypt( + io: std.Io, + gpa: std.mem.Allocator, + public_key: []const u8, + input_path: []const u8, + output_path: []const u8, +) !void { + const result = try std.process.run(gpa, io, .{ + .argv = &.{ + "age", + "-e", + "-R", + public_key, + "-o", + output_path, + input_path, + }, + }); + defer gpa.free(result.stderr); + defer gpa.free(result.stdout); + + if (result.stdout.len > 0) { + std.debug.print("stdout: \"{s}\"\n", .{result.stdout}); + unreachable; + } + + if (result.stderr.len > 0) { + std.debug.print("stderr: \"{s}\"\n", .{result.stderr}); + unreachable; + } +} + +test "sample file can be decrypted" { + const io = std.testing.io; + const gpa = std.testing.allocator; + + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + + const dir_path = try tmp.dir.realPathFileAlloc(io, ".", gpa); + defer gpa.free(dir_path); + + const output_path = try std.fs.path.join(gpa, &.{ dir_path, "got.txt" }); + defer gpa.free(output_path); + + try decrypt( + io, + gpa, + "./fixtures/insecure-test-key", + "./fixtures/hello-world.age", + output_path, + ); + + const contents = try tmp.dir.readFileAlloc(io, output_path, gpa, .unlimited); + defer gpa.free(contents); + + try std.testing.expectEqualSlices(u8, "Hello, World!\n", contents); +} + +test "sample file can be encrypted" { + const io = std.testing.io; + const gpa = std.testing.allocator; + + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + + const dir_path = try tmp.dir.realPathFileAlloc(io, ".", gpa); + defer gpa.free(dir_path); + + const output_path = try std.fs.path.join(gpa, &.{ dir_path, "hello-world.age" }); + defer gpa.free(output_path); + + try encrypt( + io, + gpa, + "./fixtures/insecure-test-key.pub", + "./fixtures/hello-world.txt", + output_path, + ); + + const got = try tmp.dir.readFileAlloc(io, output_path, gpa, .unlimited); + defer gpa.free(got); + + const want = try std.Io.Dir.cwd().readFileAlloc( + io, + "./fixtures/hello-world.age", + gpa, + .unlimited, + ); + + const contents = try tmp.dir.readFileAlloc(io, output_path, gpa, .unlimited); + defer gpa.free(contents); + + try std.testing.expectEqualSlices(u8, want, got); +} diff --git a/src/db.zig b/src/db.zig index eb70c4f..da1b749 100644 --- a/src/db.zig +++ b/src/db.zig @@ -1,6 +1,12 @@ const std = @import("std"); const sqlite = @import("sqlite"); +const age = @import("age.zig"); + +test { + std.testing.refAllDecls(@import("age.zig")); +} + test "simple database can be opened" { var db = try sqlite.Db.init(.{ .mode = sqlite.Db.Mode{ .File = "./fixtures/example.db" }, @@ -24,3 +30,47 @@ test "simple database can be opened" { return error.TestUnexpectedResult; } } + +test "encrypted database can be opened" { + const io = std.testing.io; + const gpa = std.testing.allocator; + + var tmp = std.testing.tmpDir(.{}); + defer tmp.cleanup(); + + const dir_path = try tmp.dir.realPathFileAlloc(io, ".", gpa); + defer gpa.free(dir_path); + + const decrypted_path = try std.fs.path.joinZ(gpa, &.{ dir_path, "example.db" }); + defer gpa.free(decrypted_path); + + try age.decrypt( + io, + gpa, + "./fixtures/insecure-test-key", + "./fixtures/encrypted-example.db.age", + decrypted_path, + ); + + var db = try sqlite.Db.init(.{ + .mode = sqlite.Db.Mode{ .File = decrypted_path }, + .open_flags = .{ + .write = false, + .create = false, + }, + .threading_mode = .MultiThread, + }); + + var stmt = try db.prepare("SELECT * FROM hello"); + defer stmt.deinit(); + + const alloc = std.testing.allocator; + + if (try stmt.oneAlloc(struct { text: []const u8 }, alloc, .{}, .{})) |got| { + defer alloc.free(got.text); + + try std.testing.expectEqualSlices(u8, "world!", got.text); + } else { + return error.TestUnexpectedResult; + } +} diff --git a/zig-vendor/age-ffi/zig/build.zig b/zig-vendor/age-ffi/zig/build.zig index a5968b3..8ea270a 100644 --- a/zig-vendor/age-ffi/zig/build.zig +++ b/zig-vendor/age-ffi/zig/build.zig @@ -25,9 +25,8 @@ pub fn build(b: *std.Build) void { // Link the Rust static library // Assumes the library has been built with: cargo build --release example.root_module.addLibraryPath(b.path("../target/release")); - example.root_module.linkSystemLibrary("age_ffi", .{}); - - // example.root_module.linkLibC(); + example.root_module.linkSystemLibrary("age_ffi", .{ .needed = true }); + // example.linkLibC(); // Install the example b.installArtifact(example); @@ -80,7 +79,7 @@ pub fn build(b: *std.Build) void { tests.root_module.addImport("age", age_module); tests.root_module.addLibraryPath(b.path("../target/release")); - tests.root_module.linkSystemLibrary("age_ffi", .{}); + tests.root_module.linkSystemLibrary("age_ffi", .{ .needed = true }); // tests.linkLibC(); tests.step.dependOn(&cargo_build.step); diff --git a/zig-vendor/age-ffi/zig/build.zig.zon b/zig-vendor/age-ffi/zig/build.zig.zon new file mode 100644 index 0000000..237128d --- /dev/null +++ b/zig-vendor/age-ffi/zig/build.zig.zon @@ -0,0 +1,9 @@ +.{ + .name = .age, + .version = "0.1.0", + .fingerprint = 0xa13010b27f1528d3, + .minimum_zig_version = "0.14.0", + .paths = .{ + "zig", + }, +}