lib/kms_encrypted.rb in kms_encrypted-0.1.0 vs lib/kms_encrypted.rb in kms_encrypted-0.1.1
- old
+ new
@@ -6,46 +6,66 @@
def self.kms
@kms ||= Aws::KMS::Client.new
end
module Model
- def has_kms_key(key_id)
+ def has_kms_key(key_id, name: nil)
raise ArgumentError, "Missing key id" unless key_id
+ key_method = name ? "kms_key_#{name}" : "kms_key"
+
class_eval do
- class << self
- attr_accessor :kms_key_id
- end
- self.kms_key_id = key_id
+ define_method(key_method) do
+ instance_var = "@#{key_method}"
- def kms_key
- unless @kms_key
- key_id = self.class.kms_key_id
- context = respond_to?(:kms_encryption_context) ? kms_encryption_context : {}
+ unless instance_variable_get(instance_var)
+ key_column = "encrypted_#{key_method}"
+ context_method = name ? "kms_encryption_context_#{name}" : "kms_encryption_context"
+ context = respond_to?(context_method) ? send(context_method) : {}
default_encoding = "m"
- unless encrypted_kms_key
+ unless send(key_column)
resp = KmsEncrypted.kms.generate_data_key(
key_id: key_id,
encryption_context: context,
key_spec: "AES_256"
)
- @kms_key = resp.plaintext
ciphertext = resp.ciphertext_blob
- self.encrypted_kms_key = [resp.ciphertext_blob].pack(default_encoding)
+ instance_variable_set(instance_var, resp.plaintext)
+ self.send("#{key_column}=", [resp.ciphertext_blob].pack(default_encoding))
end
- unless @kms_key
- ciphertext = encrypted_kms_key.unpack(default_encoding).first
+ unless instance_variable_get(instance_var)
+ ciphertext = send(key_column).unpack(default_encoding).first
resp = KmsEncrypted.kms.decrypt(
ciphertext_blob: ciphertext,
encryption_context: context
)
- @kms_key = resp.plaintext
+ instance_variable_set(instance_var, resp.plaintext)
end
end
- @kms_key
+ instance_variable_get(instance_var)
+ end
+
+ define_method("rotate_#{key_method}!") do
+ # decrypt
+ plaintext_attributes = {}
+ self.class.encrypted_attributes.select { |_, v| v[:key] == key_method.to_sym }.keys.each do |key|
+ plaintext_attributes[key] = send(key)
+ end
+
+ # reset key
+ instance_variable_set("@#{key_method}", nil)
+ send("encrypted_#{key_method}=", nil)
+
+ # encrypt again
+ plaintext_attributes.each do |attr, value|
+ send("#{attr}=", value)
+ end
+
+ # update atomically
+ save!
end
end
end
end
end