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)
  tmp_file = "#{File.basename(path)}.#{Process.pid}"
  tmp_path = File.join(Dir.tmpdir, tmp_file)
  IO.binwrite(tmp_path, contents)
  yield tmp_path
  updated_contents = IO.binread(tmp_path)
  write(updated_contents) if updated_contents != contents
ensure
  FileUtils.rm(tmp_path) if File.exist?(tmp_path)
end