class Rails::Secrets

:nodoc:
Greatly inspired by Ara T. Howard’s magnificent sekrets gem. 😘

def decrypt(data)

def decrypt(data)
  encryptor.decrypt_and_verify(data)
end

def encrypt(data)

def encrypt(data)
  encryptor.encrypt_and_sign(data)
end

def encryptor

def encryptor
  @encryptor ||= ActiveSupport::MessageEncryptor.new([ key ].pack("H*"), cipher: @cipher)
end

def handle_missing_key

def handle_missing_key
  raise MissingKeyError
end

def key

def key
  ENV["RAILS_MASTER_KEY"] || read_key_file || handle_missing_key
end

def key_path

def key_path
  @root.join("config", "secrets.yml.key")
end

def parse(paths, env:)

def parse(paths, env:)
  paths.each_with_object(Hash.new) do |path, all_secrets|
    require "erb"
    source = ERB.new(preprocess(path)).result
    secrets = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(source) : YAML.load(source)
    secrets ||= {}
    all_secrets.merge!(secrets["shared"].deep_symbolize_keys) if secrets["shared"]
    all_secrets.merge!(secrets[env].deep_symbolize_keys) if secrets[env]
  end
end

def path

def path
  @root.join("config", "secrets.yml.enc").to_s
end

def preprocess(path)

def preprocess(path)
  if path.end_with?(".enc")
    decrypt(IO.binread(path))
  else
    IO.read(path)
  end
end

def read

def read
  decrypt(IO.binread(path))
end

def read_for_editing(&block)

def read_for_editing(&block)
  writing(read, &block)
end

def read_key_file

def read_key_file
  if File.exist?(key_path)
    IO.binread(key_path).strip
  end
end

def write(contents)

def write(contents)
  IO.binwrite("#{path}.tmp", encrypt(contents))
  FileUtils.mv("#{path}.tmp", path)
end

def writing(contents)

def writing(contents)
  file_name = "#{File.basename(path)}.#{Process.pid}"
  Tempfile.create(["", "-" + file_name]) do |tmp_file|
    tmp_path = Pathname.new(tmp_file)
    tmp_path.binwrite contents
    yield tmp_path
    updated_contents = tmp_path.binread
    write(updated_contents) if updated_contents != contents
  end
end