Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pack_build.hpp
Go to the documentation of this file.
1#pragma once
2
3// Build a signable swap-pack manifest from a UX bundle directory: walk the files,
4// hash each, and infer the least-privilege capability set from the bundle's JS so
5// the developer does not hand-maintain it. The result is an UNSIGNED manifest ready
6// for the signing step to confirm + sign.
7
11
12#include <algorithm>
13#include <cstdint>
14#include <filesystem>
15#include <fstream>
16#include <string>
17#include <vector>
18
19namespace pulp::format::reload {
20
22 bool ok = false;
23 std::string error;
25};
26
27inline std::string pack_read_all_bytes(const std::filesystem::path& p) {
28 std::ifstream in(p, std::ios::binary);
29 return std::string((std::istreambuf_iterator<char>(in)),
30 std::istreambuf_iterator<char>());
31}
32
37inline PackBuildResult build_signable_manifest(const std::filesystem::path& bundle_dir,
38 const std::string& plugin_id,
39 std::uint64_t pack_version,
40 const std::string& update_channel) {
41 namespace fs = std::filesystem;
43 std::error_code ec;
44 if (!fs::is_directory(bundle_dir, ec) || ec) {
45 r.error = "bundle is not a directory: " + bundle_dir.string();
46 return r;
47 }
48
49 std::vector<fs::path> files;
50 for (auto it = fs::recursive_directory_iterator(bundle_dir, ec);
51 !ec && it != fs::recursive_directory_iterator(); it.increment(ec)) {
52 if (it->is_symlink()) {
53 r.error = "bundle contains a symlink: " + it->path().string();
54 return r;
55 }
56 if (it->is_regular_file()) files.push_back(it->path());
57 }
58 if (files.empty()) {
59 r.error = "bundle has no files: " + bundle_dir.string();
60 return r;
61 }
62 std::sort(files.begin(), files.end());
63
65 m.id = plugin_id + "@" + std::to_string(pack_version);
66 m.plugin_id = plugin_id;
67 m.pack_version = pack_version;
68 m.pack_type = SwapPackKind::UiScript;
69 m.update_channel = update_channel;
70
71 std::string all_js;
72 for (const auto& f : files) {
73 const std::string bytes = pack_read_all_bytes(f);
74 std::string rel = fs::relative(f, bundle_dir, ec).generic_string();
75 SwapPackFile pf;
76 pf.path = rel;
79 m.files.push_back(std::move(pf));
80 const auto ext = f.extension().string();
81 if (ext == ".js" || ext == ".mjs") { all_js += bytes; all_js += '\n'; }
82 }
83
84 m.declared_capabilities = view::infer_capability_names_from_js(all_js);
85 r.ok = true;
86 r.manifest = std::move(m);
87 return r;
88}
89
90} // namespace pulp::format::reload
Definition build_fingerprint.hpp:23
PackBuildResult build_signable_manifest(const std::filesystem::path &bundle_dir, const std::string &plugin_id, std::uint64_t pack_version, const std::string &update_channel)
Walk bundle_dir, hash each regular file into a manifest entry (path relative to the bundle root,...
Definition pack_build.hpp:37
std::string pack_read_all_bytes(const std::filesystem::path &p)
Definition pack_build.hpp:27
@ UiScript
Definition swap_pack.hpp:37
std::string sha256_hex(const uint8_t *data, size_t size)
Compute SHA-256 hash as hex string (64 chars).
std::vector< std::string > infer_capability_names_from_js(std::string_view js_source)
The capability NAMES a scripted UI needs, sorted + de-duplicated — ready to drop into a manifest's de...
Definition reload_autocaps.hpp:99
Definition pack_build.hpp:21
bool ok
Definition pack_build.hpp:22
std::string error
Definition pack_build.hpp:23
SwapPackManifest manifest
Definition pack_build.hpp:24
Definition swap_pack.hpp:60
std::string sha256_hex
expected lowercase hex SHA-256 of the file bytes
Definition swap_pack.hpp:62
std::string path
path relative to the pack root
Definition swap_pack.hpp:61
SwapPackKind kind
Definition swap_pack.hpp:63
Definition swap_pack.hpp:66
Sealed swap-pack manifest + per-file integrity.