123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- using Invercargill;
- using InvercargillJson;
- namespace Binman {
- public errordomain ManifestError {
- KEY_MISMATCH,
- INVALID_SIGNATURE
- }
- public class ManifestFile {
- public File file { get; private set; }
-
- public ManifestHeader read_header() throws Error {
- return new JsonlInputStream(get_stream())
- .as_property_groups()
- .try_map_with<ManifestHeader>(ManifestHeader.get_mapper())
- .first()
- .unwrap();
- }
- public Attempts<ManifestEntry> get_entries() throws Error {
- return new JsonlInputStream(get_stream())
- .as_property_groups()
- .skip(1)
- .until(o => o.has("signature"))
- .try_map_with<ManifestEntry>(ManifestEntry.get_mapper());
- }
- public bool verify_signature() throws Error {
- var stream = new DataInputStream(get_stream());
- var checksum = new Checksum(ChecksumType.SHA512);
- ManifestSignature signature;
- ManifestHeader header = null;
- while (true) {
- var line = stream.read_line();
- var obj = new JsonElement.from_string(line).as<JsonObject>();
- // Don't include signature object in checksum
- if(obj.has("signature")) {
- signature = ManifestSignature.get_mapper().materialise(obj);
- break;
- }
- checksum.update(line.data, line.data.length);
- if(header == null) {
- header = ManifestHeader.get_mapper().materialise(obj);
- }
- }
- // Calculate checksum
- var checksum_bytes = new uint8[ChecksumType.SHA512.get_length()];
- size_t size = checksum_bytes.length;
- checksum.get_digest(checksum_bytes, ref size);
- // Verify signature
- var signed_checksum = Sodium.Asymmetric.Signing.verify(signature.signature.to_array(), header.key.to_array());
- return new BinaryData.from_byte_array(signed_checksum).equals(new BinaryData.from_byte_array(checksum_bytes));
- }
- private InputStream get_stream() throws Error {
- var decompressor = new ZlibDecompressor(ZlibCompressorFormat.GZIP);
- return new ConverterInputStream(file.read(), decompressor);
- }
- public ManifestFile(File file) {
- this.file = file;
- }
- public ManifestFile.from_name(string name, ApplicationType type, BinaryData? key = null) throws Error {
- this.file = File.new_build_filename("/var/binman", name, ApplicationType.get_mapper().map_from(type));
- if(!this.file.query_exists()) {
- throw new FileError.NOENT("Could not find the specified manifest");
- }
- if(key != null && !read_header().key.equals(key)) {
- throw new ManifestError.KEY_MISMATCH("The key in the manifest file does not match the key expected");
- }
- }
- }
- public class ManifestHeader {
- public string name { get; set; }
- public string description { get; set; }
- public int serial { get; set; }
- public string post_exec { get; set; }
- public BinaryData key { get; set; }
- public Vector<string> remotes { get; set; }
- public static PropertyMapper<ManifestHeader> get_mapper() {
- return PropertyMapper.build_for<ManifestHeader>(cfg => {
- cfg.map<string>("name", o => o.name, (o, v) => o.name = v);
- cfg.map<string>("desc", o => o.description, (o, v) => o.description = v);
- cfg.map<int>("serial", o => o.serial, (o, v) => o.serial = v);
- cfg.map<string>("post-exec", o => o.post_exec, (o, v) => o.post_exec = v);
- cfg.map<string>("key", o => o.key.to_base64(), (o, v) => o.key = new BinaryData.from_base64(v));
- cfg.map_many<string>("remotes", o => o.remotes, (o, v) => o.remotes = v.to_vector());
- cfg.set_constructor(() => new ManifestHeader());
- });
- }
- }
- public class ManifestEntry {
- public string path { get; set; }
- public int user { get; set; }
- public int group { get; set; }
- public Posix.mode_t mode { get; set; }
- public string? target { get; set; }
- public string? licence { get; set; }
- public ManifestFileDescriptor? binary { get; set; }
- public ManifestFileDescriptor? source { get; set; }
- public static PropertyMapper<ManifestEntry> get_mapper() {
- return PropertyMapper.build_for<ManifestEntry>(cfg => cfg
- .map<string>("path", o => o.path, (o, v) => o.path = v)
- .map<int>("uid", o => o.user, (o, v) => o.user = v)
- .map<int>("gid", o => o.group, (o, v) => o.group = v)
- .map<int>("mod", o => (int)o.mode, (o, v) => o.mode = v)
- .map<string?>("target", o => o.target, (o, v) => o.target = v, false)
- .map<string?>("licence", o => o.licence, (o, v) => o.licence = v, false)
- .map_properties_with<ManifestFileDescriptor?>("bin", o => o.binary, (o, v) => o.binary = v, ManifestFileDescriptor.get_mapper(), false)
- .map_properties_with<ManifestFileDescriptor?>("ccs", o => o.source, (o, v) => o.source = v, ManifestFileDescriptor.get_mapper(), false)
- .set_constructor(() => new ManifestEntry())
- );
- }
- }
- public class ManifestFileDescriptor {
- public BinaryData checksum { get; set; }
- public uint64 size { get; set; }
- public string remote_path { get; set; }
- public static PropertyMapper<ManifestFileDescriptor> get_mapper() {
- return PropertyMapper.build_for<ManifestFileDescriptor>(cfg => cfg
- .map<string>("checksum", o => o.checksum.to_base64(), (o, v) => o.checksum = new BinaryData.from_base64(v))
- .map<uint64?>("size", o => o.size, (o, v) => o.size = v)
- .map<string>("path", o => o.remote_path, (o, v) => o.remote_path = v)
- .set_constructor(() => new ManifestFileDescriptor())
- );
- }
- }
- public class ManifestSignature {
- public BinaryData signature { get; set; }
- public static PropertyMapper<ManifestSignature> get_mapper() {
- return PropertyMapper.build_for<ManifestSignature>(cfg => cfg
- .map<string>("signature", o => o.signature.to_base64(), (o, v) => o.signature = new BinaryData.from_base64(v))
- .set_constructor(() => new ManifestSignature())
- );
- }
- }
- }
|