Class: Familia::EncryptedFieldType

Inherits:
FieldType
  • Object
show all
Defined in:
lib/familia/features/encrypted_fields/encrypted_field_type.rb

Instance Attribute Summary collapse

Attributes inherited from FieldType

#fast_method_name, #method_name, #name, #on_conflict, #options

Instance Method Summary collapse

Methods inherited from FieldType

#deserialize, #generated_methods, #inspect, #install, #serialize, #transient?

Constructor Details

#initialize(name, aad_fields: [], **options) ⇒ EncryptedFieldType

Returns a new instance of EncryptedFieldType.



9
10
11
12
# File 'lib/familia/features/encrypted_fields/encrypted_field_type.rb', line 9

def initialize(name, aad_fields: [], **options)
  super(name, **options.merge(on_conflict: :raise))
  @aad_fields = Array(aad_fields).freeze
end

Instance Attribute Details

#aad_fieldsObject (readonly)

Returns the value of attribute aad_fields.



7
8
9
# File 'lib/familia/features/encrypted_fields/encrypted_field_type.rb', line 7

def aad_fields
  @aad_fields
end

Instance Method Details

#categoryObject



82
83
84
# File 'lib/familia/features/encrypted_fields/encrypted_field_type.rb', line 82

def category
  :encrypted
end

#decrypt_value(record, encrypted) ⇒ Object

Decrypt a value for the given record



71
72
73
74
75
76
# File 'lib/familia/features/encrypted_fields/encrypted_field_type.rb', line 71

def decrypt_value(record, encrypted)
  context = build_context(record)
  additional_data = build_aad(record)

  Familia::Encryption.decrypt(encrypted, context: context, additional_data: additional_data)
end

#define_fast_writer(klass) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/familia/features/encrypted_fields/encrypted_field_type.rb', line 40

def define_fast_writer(klass)
  # Encrypted fields override base fast writer for security
  return unless @fast_method_name&.to_s&.end_with?('!')

  field_name = @name
  method_name = @method_name
  fast_method_name = @fast_method_name
  field_type = self

  handle_method_conflict(klass, fast_method_name) do
    klass.define_method fast_method_name do |val|
      raise ArgumentError, "#{fast_method_name} requires a value" if val.nil?

      encrypted = field_type.encrypt_value(self, val)
      send(:"#{method_name}=", val) if method_name

      ret = hset(field_name, encrypted)
      ret.zero? || ret.positive?
    end
  end
end

#define_getter(klass) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/familia/features/encrypted_fields/encrypted_field_type.rb', line 27

def define_getter(klass)
  field_name = @name
  method_name = @method_name
  field_type = self

  handle_method_conflict(klass, method_name) do
    klass.define_method method_name do
      encrypted = instance_variable_get(:"@#{field_name}")
      encrypted.nil? ? nil : field_type.decrypt_value(self, encrypted)
    end
  end
end

#define_setter(klass) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/familia/features/encrypted_fields/encrypted_field_type.rb', line 14

def define_setter(klass)
  field_name = @name
  method_name = @method_name
  field_type = self

  handle_method_conflict(klass, :"#{method_name}=") do
    klass.define_method :"#{method_name}=" do |value|
      encrypted = value.nil? ? nil : field_type.encrypt_value(self, value)
      instance_variable_set(:"@#{field_name}", encrypted)
    end
  end
end

#encrypt_value(record, value) ⇒ Object

Encrypt a value for the given record



63
64
65
66
67
68
# File 'lib/familia/features/encrypted_fields/encrypted_field_type.rb', line 63

def encrypt_value(record, value)
  context = build_context(record)
  additional_data = build_aad(record)

  Familia::Encryption.encrypt(value, context: context, additional_data: additional_data)
end

#persistent?Boolean

Returns:

  • (Boolean)


78
79
80
# File 'lib/familia/features/encrypted_fields/encrypted_field_type.rb', line 78

def persistent?
  true
end