lib/longleaf/services/metadata_deserializer.rb in longleaf-0.1.0 vs lib/longleaf/services/metadata_deserializer.rb in longleaf-0.2.0.pre.1

- old
+ new

@@ -1,28 +1,30 @@ require 'yaml' -require_relative '../models/metadata_record' -require_relative '../models/md_fields' -require_relative '../errors' +require 'longleaf/models/metadata_record' +require 'longleaf/models/md_fields' +require 'longleaf/errors' +require 'longleaf/logging' -# Service which deserializes metadata files into MetadataRecord objects module Longleaf + # Service which deserializes metadata files into MetadataRecord objects class MetadataDeserializer - MDF = Longleaf::MDFields + extend Longleaf::Logging + MDF ||= MDFields # Deserialize a file into a MetadataRecord object # # @param file_path [String] path of the file to read. Required. # @param format [String] format the file is stored in. Default is 'yaml'. - def self.deserialize(file_path:, format: 'yaml') + def self.deserialize(file_path:, format: 'yaml', digest_algs: []) case format when 'yaml' - md = from_yaml(file_path) + md = from_yaml(file_path, digest_algs) else raise ArgumentError.new('Invalid deserialization format #{format} specified') end - if !md || !md.key?(MDF::DATA) || !md.key?(MDF::SERVICES) + if !md || !md.is_a?(Hash) || !md.key?(MDF::DATA) || !md.key?(MDF::SERVICES) raise Longleaf::MetadataError.new("Invalid metadata file, did not contain data or services fields: #{file_path}") end data = Hash.new.merge(md[MDF::DATA]) # Extract reserved properties for submission as separate parameters @@ -59,10 +61,45 @@ checksums: checksums, file_size: file_size, last_modified: last_modified) end - def self.from_yaml(file_path) - YAML.load_file(file_path) + # Load configuration a yaml encoded configuration file + def self.from_yaml(file_path, digest_algs) + File.open(file_path, 'r:bom|utf-8') do |f| + contents = f.read + + verify_digests(file_path, contents, digest_algs) + + YAML.load(contents) + end + end + + def self.verify_digests(file_path, contents, digest_algs) + return if digest_algs.nil? || digest_algs.empty? + + digest_algs.each do |alg| + if file_path.respond_to?(:path) + path = file_path.path + else + path = file_path + end + digest_path = "#{path}.#{alg}" + unless File.exist?(digest_path) + logger.warn("Missing expected #{alg} digest for #{path}") + next + end + + digest = DigestHelper::start_digest(alg) + result = digest.hexdigest(contents) + existing_digest = IO.read(digest_path) + + if result == existing_digest + logger.info("Metadata fixity check using algorithm '#{alg}' succeeded for file #{path}") + else + raise ChecksumMismatchError.new("Metadata digest of type #{alg} did not match the contents of #{path}:" \ + + " expected #{existing_digest}, calculated #{result}") + end + end end end end \ No newline at end of file