From 075668d1888c29bec6feae9a6a890fc4034bd9b3 Mon Sep 17 00:00:00 2001 From: server Date: Tue, 14 Apr 2026 11:26:44 +0200 Subject: [PATCH] Add client config export command --- README.md | 10 ++++++ docs/client-integration.md | 17 +++++++++ src/cli.cpp | 72 +++++++++++++++++++++++++++++++++++++- 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f964bc1..2a1e259 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ with. - `m2pack list` - `m2pack verify` - `m2pack extract` +- `m2pack export-client-config` ## Build @@ -68,6 +69,15 @@ Extract: --key keys/master.key ``` +Export a client config header for `m2dev-client-src/src/PackLib/M2PackKeys.h`: + +```bash +./build/m2pack export-client-config \ + --key keys/master.key \ + --public-key keys/signing.pub \ + --output /path/to/m2dev-client-src/src/PackLib/M2PackKeys.h +``` + ## Format summary - Single archive file with a fixed header diff --git a/docs/client-integration.md b/docs/client-integration.md index b917557..d4f4073 100644 --- a/docs/client-integration.md +++ b/docs/client-integration.md @@ -19,6 +19,23 @@ tool. - machine-bound cache - or a derived release secret +## Client key header + +For the current implementation, the client expects: + +- `src/PackLib/M2PackKeys.h` + +Generate it from the release key material with: + +```bash +m2pack export-client-config \ + --key keys/master.key \ + --public-key keys/signing.pub \ + --output /path/to/m2dev-client-src/src/PackLib/M2PackKeys.h +``` + +That keeps loader constants aligned with the archive builder. + ## Runtime validation Minimum validation: diff --git a/src/cli.cpp b/src/cli.cpp index 2182abd..0d1860f 100644 --- a/src/cli.cpp +++ b/src/cli.cpp @@ -102,7 +102,8 @@ void print_usage() << " build --input --output --key --sign-secret-key [--json]\n" << " list --archive [--json]\n" << " verify --archive [--public-key ] [--key ] [--json]\n" - << " extract --archive --output --key [--json]\n"; + << " extract --archive --output --key [--json]\n" + << " export-client-config --key --public-key --output [--json]\n"; } void command_keygen(const ParsedArgs& args) @@ -261,6 +262,70 @@ void command_extract(const ParsedArgs& args) std::cout << "Extracted " << archive.entries.size() << " files\n"; } +void command_export_client_config(const ParsedArgs& args) +{ + const auto master = load_hex_file(require_option(args, "key")); + const auto public_key = load_hex_file(require_option(args, "public-key")); + const auto output_path = require_option(args, "output"); + + if (master.size() != kAeadKeySize) + { + fail("Master key must be 32 bytes"); + } + + if (public_key.size() != crypto_sign_PUBLICKEYBYTES) + { + fail("Signing public key has invalid size"); + } + + auto render_array = [](const std::vector& bytes) { + std::ostringstream out; + for (std::size_t i = 0; i < bytes.size(); ++i) + { + if (i % 8 == 0) + { + out << "\n\t"; + } + out << "0x" << to_hex(&bytes[i], 1); + if (i + 1 != bytes.size()) + { + out << ", "; + } + } + out << "\n"; + return out.str(); + }; + + std::ostringstream header; + header + << "#pragma once\n\n" + << "#include \n" + << "#include \n\n" + << "// Generated by m2pack export-client-config.\n" + << "// Do not edit manually.\n\n" + << "constexpr std::array M2PACK_MASTER_KEY = {" + << render_array(master) + << "};\n\n" + << "constexpr std::array M2PACK_SIGN_PUBLIC_KEY = {" + << render_array(public_key) + << "};\n"; + + const auto text = header.str(); + write_file(output_path, std::vector(text.begin(), text.end())); + + if (args.json) + { + std::cout + << "{" + << "\"ok\":true," + << "\"output\":\"" << json_escape(output_path) << "\"" + << "}\n"; + return; + } + + std::cout << "Wrote client config to " << output_path << "\n"; +} + } // namespace int run_cli(int argc, char** argv) @@ -300,6 +365,11 @@ int run_cli(int argc, char** argv) command_extract(args); return 0; } + if (args.command == "export-client-config") + { + command_export_client_config(args); + return 0; + } if (args.command == "help" || args.command == "--help" || args.command == "-h") { print_usage();