Module: BarkestCore::EncryptedFields
- Defined in:
- lib/barkest_core/concerns/encrypted_fields.rb
Overview
Adds helper methods to the model to allow easy manipulation of fields stored as encrypted values.
The encryption password is specified in secrets.yml
.
For a class MyNamespace::MyClass you can specify the encryption password using my_namespace_my_class
or my_class
keys in the appropriate section of secrets.yml
.
If no specific encryption password is provided, then secret_key_base
is used instead.
Class Method Summary collapse
-
.included(base) ⇒ Object
:nodoc:.
Class Method Details
.included(base) ⇒ Object
:nodoc:
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/barkest_core/concerns/encrypted_fields.rb', line 18 def self.included(base) base.class_eval do private def self.crypto_password @crypto_password ||= begin klass = self.class.name.to_s.underscore if klass.include?('/') Rails.application.secrets[klass.gsub('/','_').to_sym] || Rails.application.secrets[klass.rpartition('/')[2].to_sym] || Rails.application.secrets[:secret_key_base] else Rails.application.secrets[klass.to_sym] || Rails.application.secrets[:secret_key_base] end end end def self.crypto_cipher @crypto_cipher ||= EncryptedStrings::SymmetricCipher.new(password: crypto_password) end def self.decrypt_value(value) return nil if value.nil? return '' if value == '' crypto_cipher.decrypt(value) end public ## # Encrypts a value using this model's key. # # Will not encrypt nil or empty strings. def self.encrypt_value(value) return nil if value.nil? return '' if value == '' crypto_cipher.encrypt(value) end protected ## # Defines methods to allow accessing an encrypted field easily. # # Simplest usage: # encrypted_field :encrypted_field_name # # Detailed usage: # encrypted_field :encrypted => :encrypted_field_name, # :decrypted => :field_name, # :read_only => false # # In both usages, the model will receive two new methods: # def field_name # ... # end # # def field_name=(value) # ... # end # # If you specify :read_only => true, then only one method will be defined: # def field_name # ... # end # # Raises a StandardError if the attribute names cannot be determined or if the # encrypted attribute is not defined. # def self.encrypted_field( = {}) unless .is_a?(Hash) attr_name = .to_s if attr_name[0...10] == 'encrypted_' || attr_name[0...4] == 'enc_' || attr_name[-4..-1] == '_enc' || attr_name[-10..-1] == '_encrypted' = { encrypted: attr_name } else = { decrypted: attr_name } end end raise StandardError.new('Options must contain either :decrypted or :encrypted key.') if [:encrypted].blank? && [:decrypted].blank? if [:encrypted].blank? attr_name = [:decrypted] %W(encrypted_#{attr_name} enc_#{attr_name} #{attr_name}_enc #{attr_name}_encrypted).each do |attr| if method_defined?(attr) || columns.find{|a| a.name == attr} [:encrypted] = attr end end elsif [:decrypted].blank? attr_name = [:encrypted] if attr_name[0...10] == 'encrypted_' || attr_name[0...4] == 'enc_' [:decrypted] = attr_name.partition('_')[2] elsif attr_name[-4..-1] == '_enc' || attr_name[-10..-1] == '_encrypted' [:decrypted] = attr_name.rpartition('_')[0] end end raise StandardError.new("Cannot locate encrypted attribute with #{[:decrypted]} as the decypted attribute name.") if [:encrypted].blank? raise StandardError.new("Cannot determine decrypted attribute name with #{[:encrypted]} as the encrypted attribute.") if [:decrypted].blank? define_method [:decrypted].to_sym do self.class.decrypt_value send([:encrypted]) end unless [:read_only] define_method :"#{[:decrypted]}=" do |value| send "#{[:encrypted]}=", self.class.encrypt_value(value) end end end ## # Encrypts a value and returns the result in base64 encoding. def encrypt(value) self.class.encrypt_value(value) end ## # Decodes a base64 value and returns the decrypted value. def decrypt(value) self.class.decrypt_value(value) end end end |