Module: Claude::Extensions

Defined in:
lib/claude/extensions.rb

Instance Method Summary collapse

Instance Method Details

#attr_encrypt(*attrs) ⇒ Object

An alias to encrypt that lets you encrypt multiple attributes at once.

If only one attribute is given, it acts exactly like encrypt does.

When multiple attributes are given, you can still give options. However, the :attr and :attr_iv options will be the same for all the attributes.

class Card < ActiveRecord::Base
  attr_encrypt :pin, :pan
end


81
82
83
84
85
86
87
# File 'lib/claude/extensions.rb', line 81

def attr_encrypt(*attrs)
  options = attrs.extract_options!

  attrs.each do |attr|
    encrypt attr, options
  end
end

#encrypt(attr, options = {}) ⇒ Object

Encrypt the value stored at attr when persisting the value in the underlying database.

To encrypt an attr we need to have two extra columns named:

* encrypted_attr    - Used internally to store the encrypted value.
* encrypted_attr_iv - Used internally to encrypt the value above.

Note that attr is dynamic here. If you wanna encrypt the attribute pin:

class Card < ActiveRecord::Base
  encrypt :pin
end

The expected columns will be named encrypted_pin and encrypted_pin_iv.

Encrypt will generate two new instance methods: attr and attr=. Those are dynamic and compute its value based of encrypted_attr and decrypted_attr.

attr decrypt the value from the encrypted_attr. attr= encrypts the value that is passed to it and saves it to encrypted_attr.

Most of the time, you won’t need to call encrypted_attr and encrypted_attr_iv manually. Consider them an implementation detail.

You can pass the following options:

* :attr    - The name of the internal encrypted column.
             Defaults to "encrypted_#{attr}".)

* :attr_iv - The name of the internal initialization vector column.
             Defaults to "encrypted_#{attr}_iv".

* :secret  - The secret used to encrypt the attribute.
             Defaults to config.secret_roken or config.secrets.secret_token.


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
# File 'lib/claude/extensions.rb', line 42

def encrypt(attr, options = {})
  attr_secret   = options.fetch(:secret, Claude.secret).inspect
  attr_internal = options.fetch(:attr, "encrypted_#{attr}")
  attr_iv       = options.fetch(:attr_iv, "encrypted_#{attr}_iv")
  attr_raw      = "#{attr_internal}_before_type_cast"

  module_eval "    def \#{attr}\n      return unless \#{attr_raw}\n\n      cipher = Cipher.for_decryption(\#{attr_secret}, \#{attr_iv})\n      cipher.decrypt(\#{attr_raw})\n    end\n\n    def \#{attr}=(value)\n      if value\n        iv     = RandomIV.generate\n        cipher = Cipher.for_encryption(\#{attr_secret}, iv)\n\n        self.\#{attr_iv}       = iv\n        self.\#{attr_internal} = cipher.encrypt(value)\n      else\n        self.\#{attr_iv}       = nil\n        self.\#{attr_internal} = nil\n      end\n    end\n  RUBY\nend\n", __FILE__, __LINE__ + 1