require "yaml" require "digest" module Picop class SourceFile attr_reader :file_path, :content METADATA_PATTERN = /^\s*#\s*@META_START\n(.*?)^\s*#\s*@META_END/m def initialize(file_path) @file_path = file_path @content = File.read(file_path) end def metadata @metadata ||= begin return {} unless content =~ METADATA_PATTERN yaml_content = $1.lines.map do |line| line.sub(/^\s*#\s?/, '').rstrip end.join("\n") YAML.safe_load(yaml_content) end end def file_content = content.sub(/^\s*#\s*@META_START\n.*?^\s*#\s*@META_END\n*/m, '') def checksum = "sha256:#{Digest::SHA256.hexdigest(file_content)}" def show = puts(metadata.merge({checksum: checksum})) def save = File.write(file_path, content) def add_metadata(metadata_hash) yaml_content = metadata_hash.to_yaml.strip metadata_block = [ "# @META_START", yaml_content.lines.map { |line| "# #{line}" }.join, "# @META_END" ].join("\n") if content =~ METADATA_PATTERN @content = content.sub(METADATA_PATTERN, metadata_block) else @content = [metadata_block, content].join("\n\n") end end def sign hash = checksum meta = metadata || {} return puts "File already signed" if meta['content_checksum'] == hash meta['content_checksum'] = "#{hash}" add_metadata(meta) save end def verify return false unless metadata.key? 'content_checksum' checksum == metadata['content_checksum'] end end end