Class: ActiveSupport::EncryptedFile
Relationships & Source Files | |
Namespace Children | |
Exceptions:
| |
Extension / Inclusion / Inheritance Descendants | |
Subclasses:
|
|
Inherits: | Object |
Defined in: | activesupport/lib/active_support/encrypted_file.rb |
Constant Summary
-
CIPHER =
# File 'activesupport/lib/active_support/encrypted_file.rb', line 29"aes-128-gcm"
Class Method Summary
- .generate_key
- .new(content_path:, key_path:, env_key:, raise_if_missing_key:) ⇒ EncryptedFile constructor
- .expected_key_length Internal use only
Instance Attribute Summary
- #content_path readonly
- #env_key readonly
- #key readonly
-
#key? ⇒ Boolean
readonly
Returns truthy if #key is truthy.
- #key_path readonly
- #raise_if_missing_key readonly
Instance Method Summary
- #change(&block)
-
#read
Reads the file and returns the decrypted content.
- #write(contents)
- #check_key_length private
- #decrypt(contents) private
- #encrypt(contents) private
- #encryptor private
- #handle_missing_key private
- #read_env_key private
- #read_key_file private
- #writing(contents) private
Constructor Details
.new(content_path:, key_path:, env_key:, raise_if_missing_key:) ⇒ EncryptedFile
# File 'activesupport/lib/active_support/encrypted_file.rb', line 42
def initialize(content_path:, key_path:, env_key:, raise_if_missing_key:) @content_path = Pathname.new(content_path).yield_self { |path| path.symlink? ? path.realpath : path } @key_path = Pathname.new(key_path) @env_key, @raise_if_missing_key = env_key, raise_if_missing_key end
Class Method Details
.expected_key_length
# File 'activesupport/lib/active_support/encrypted_file.rb', line 35
def self.expected_key_length # :nodoc: @expected_key_length ||= generate_key.length end
.generate_key
[ GitHub ]# File 'activesupport/lib/active_support/encrypted_file.rb', line 31
def self.generate_key SecureRandom.hex(ActiveSupport::MessageEncryptor.key_len(CIPHER)) end
Instance Attribute Details
#content_path (readonly)
[ GitHub ]# File 'activesupport/lib/active_support/encrypted_file.rb', line 40
attr_reader :content_path, :key_path, :env_key, :raise_if_missing_key
#env_key (readonly)
[ GitHub ]# File 'activesupport/lib/active_support/encrypted_file.rb', line 40
attr_reader :content_path, :key_path, :env_key, :raise_if_missing_key
#key (readonly)
Returns the encryption key, first trying the environment variable specified by #env_key, then trying the key file specified by #key_path. If #raise_if_missing_key is true, raises EncryptedFile::MissingKeyError
if the environment variable is not set and the key file does not exist.
# File 'activesupport/lib/active_support/encrypted_file.rb', line 52
def key read_env_key || read_key_file || handle_missing_key end
#key? ⇒ Boolean
(readonly)
Returns truthy if #key is truthy. Returns falsy otherwise. Unlike #key, does not raise EncryptedFile::MissingKeyError
when #raise_if_missing_key is true.
# File 'activesupport/lib/active_support/encrypted_file.rb', line 58
def key? read_env_key || read_key_file end
#key_path (readonly)
[ GitHub ]# File 'activesupport/lib/active_support/encrypted_file.rb', line 40
attr_reader :content_path, :key_path, :env_key, :raise_if_missing_key
#raise_if_missing_key (readonly)
[ GitHub ]# File 'activesupport/lib/active_support/encrypted_file.rb', line 40
attr_reader :content_path, :key_path, :env_key, :raise_if_missing_key
Instance Method Details
#change(&block)
[ GitHub ]#check_key_length (private)
# File 'activesupport/lib/active_support/encrypted_file.rb', line 129
def check_key_length raise InvalidKeyLengthError if key&.length != self.class.expected_key_length end
#decrypt(contents) (private)
[ GitHub ]# File 'activesupport/lib/active_support/encrypted_file.rb', line 108
def decrypt(contents) encryptor.decrypt_and_verify contents end
#encrypt(contents) (private)
[ GitHub ]# File 'activesupport/lib/active_support/encrypted_file.rb', line 103
def encrypt(contents) check_key_length encryptor.encrypt_and_sign contents end
#encryptor (private)
[ GitHub ]# File 'activesupport/lib/active_support/encrypted_file.rb', line 112
def encryptor @encryptor ||= ActiveSupport::MessageEncryptor.new([ key ].pack("H*"), cipher: CIPHER, serializer: Marshal) end
#handle_missing_key (private)
# File 'activesupport/lib/active_support/encrypted_file.rb', line 125
def handle_missing_key raise MissingKeyError.new(key_path: key_path, env_key: env_key) if raise_if_missing_key end
#read
Reads the file and returns the decrypted content.
Raises:
-
EncryptedFile::MissingKeyError
if the key is missing and #raise_if_missing_key is true. -
EncryptedFile::MissingContentError
if the encrypted file does not exist or otherwise if the key is missing. -
MessageEncryptor::InvalidMessage
if the content cannot be decrypted or verified.
# File 'activesupport/lib/active_support/encrypted_file.rb', line 70
def read if !key.nil? && content_path.exist? decrypt content_path.binread.strip else raise MissingContentError, content_path end end
#read_env_key (private)
[ GitHub ]# File 'activesupport/lib/active_support/encrypted_file.rb', line 117
def read_env_key ENV[env_key].presence end
#read_key_file (private)
[ GitHub ]#write(contents)
[ GitHub ]# File 'activesupport/lib/active_support/encrypted_file.rb', line 78
def write(contents) IO.binwrite "#{content_path}.tmp", encrypt(contents) FileUtils.mv "#{content_path}.tmp", content_path end
#writing(contents) (private)
[ GitHub ]# File 'activesupport/lib/active_support/encrypted_file.rb', line 89
def writing(contents) Tempfile.create(["", "-" + content_path.basename.to_s.chomp(".enc")]) 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