rails/activesupport/test/encrypted_file_test.rb
2023-10-13 19:26:47 +00:00

172 lines
4.7 KiB
Ruby

# frozen_string_literal: true
require_relative "abstract_unit"
require "active_support/core_ext/object/with"
require "active_support/encrypted_file"
class EncryptedFileTest < ActiveSupport::TestCase
setup do
@original_env_content_key = ENV["CONTENT_KEY"]
ENV["CONTENT_KEY"] = nil
@content = "One little fox jumped over the hedge"
@tmpdir = Dir.mktmpdir("encrypted-file-test-")
@content_path = File.join(@tmpdir, "content.txt.enc")
@key = ActiveSupport::EncryptedFile.generate_key
@key_path = File.join(@tmpdir, "content.txt.key")
File.write(@key_path, @key)
@encrypted_file = encrypted_file(@content_path)
end
teardown do
FileUtils.rm_rf @content_path
FileUtils.rm_rf @key_path
FileUtils.rm_rf @tmpdir
ENV["CONTENT_KEY"] = @original_env_content_key
end
test "reading content by env key" do
FileUtils.rm_rf @key_path
ENV["CONTENT_KEY"] = @key
@encrypted_file.write @content
assert_equal @content, @encrypted_file.read
end
test "reading content by key file" do
@encrypted_file.write(@content)
assert_equal @content, @encrypted_file.read
end
test "change content by key file" do
@encrypted_file.write(@content)
@encrypted_file.change do |file|
file.write(file.read + " and went by the lake")
end
assert_equal "#{@content} and went by the lake", @encrypted_file.read
end
test "change sets restricted permissions" do
@encrypted_file.write(@content)
@encrypted_file.change do |file|
assert_predicate file, :owned?
assert_equal "100600", file.stat.mode.to_s(8), "Incorrect mode for #{file}"
end
end
test "raise MissingKeyError when key is missing" do
assert_raise ActiveSupport::EncryptedFile::MissingKeyError do
encrypted_file(@content_path, key_path: "", env_key: "").read
end
end
test "raise MissingKeyError when env key is blank" do
FileUtils.rm_rf @key_path
ENV["CONTENT_KEY"] = ""
raised = assert_raise ActiveSupport::EncryptedFile::MissingKeyError do
@encrypted_file.write @content
@encrypted_file.read
end
assert_match(/Missing encryption key to decrypt file/, raised.message)
end
test "key can be added after MissingKeyError raised" do
FileUtils.rm_rf @key_path
assert_raise ActiveSupport::EncryptedFile::MissingKeyError do
@encrypted_file.key
end
File.write(@key_path, @key)
assert_nothing_raised do
assert_equal @key, @encrypted_file.key
end
end
test "key? is true when key file exists" do
assert_predicate @encrypted_file, :key?
end
test "key? is true when env key is present" do
FileUtils.rm_rf @key_path
ENV["CONTENT_KEY"] = @key
assert_predicate @encrypted_file, :key?
end
test "key? is false and does not raise when the key is missing" do
FileUtils.rm_rf @key_path
assert_nothing_raised do
assert_not @encrypted_file.key?
end
end
test "raise InvalidKeyLengthError when key is too short" do
File.write(@key_path, ActiveSupport::EncryptedFile.generate_key[0..-2])
assert_raise ActiveSupport::EncryptedFile::InvalidKeyLengthError do
@encrypted_file.write(@content)
end
end
test "raise InvalidKeyLengthError when key is too long" do
File.write(@key_path, ActiveSupport::EncryptedFile.generate_key + "0")
assert_raise ActiveSupport::EncryptedFile::InvalidKeyLengthError do
@encrypted_file.write(@content)
end
end
test "respects existing content_path symlink" do
@encrypted_file.write(@content)
symlink_path = File.join(@tmpdir, "content_symlink.txt.enc")
File.symlink(@encrypted_file.content_path, symlink_path)
encrypted_file(symlink_path).write(@content)
assert File.symlink?(symlink_path)
assert_equal @content, @encrypted_file.read
ensure
FileUtils.rm_rf symlink_path
end
test "creates new content_path symlink if it's dead" do
symlink_path = File.join(@tmpdir, "content_symlink.txt.enc")
File.symlink(@content_path, symlink_path)
encrypted_file(symlink_path).write(@content)
assert File.exist?(@content_path)
assert_equal @content, @encrypted_file.read
ensure
FileUtils.rm_rf symlink_path
end
test "can read encrypted file after changing default_serializer" do
ActiveSupport::Messages::Codec.with(default_serializer: :marshal) do
encrypted_file(@content_path).write(@content)
end
ActiveSupport::Messages::Codec.with(default_serializer: :json) do
assert_equal @content, encrypted_file(@content_path).read
end
end
private
def encrypted_file(content_path, key_path: @key_path, env_key: "CONTENT_KEY")
ActiveSupport::EncryptedFile.new(content_path: @content_path, key_path: key_path,
env_key: env_key, raise_if_missing_key: true)
end
end