fnando/encrypt_attr

View on GitHub
lib/encrypt_attr/base.rb

Summary

Maintainability
A
45 mins
Test Coverage
module EncryptAttr
  module Base
    def self.included(target)
      target.extend(ClassMethods)
    end

    class << self
      # Define the object that will encrypt/decrypt values.
      # By default, it's EncryptAttr::Encryptor
      attr_accessor :encryptor
    end

    def self.secret_token
      @secret_token
    end

    def self.secret_token=(secret_token)
      encryptor.validate_secret_token(secret_token.to_s) if encryptor.respond_to?(:validate_secret_token)
      @secret_token = secret_token.to_s
    end

    # Set initial token value to empty string.
    # Cannot assign through writer method because of size warning.
    @secret_token = ""

    # Set initial encryptor engine.
    self.encryptor = Encryptor

    module ClassMethods
      def encrypt_attr(*args, secret_token: EncryptAttr.secret_token, encryptor: EncryptAttr.encryptor)
        encryptor.validate_secret_token(secret_token) if encryptor.respond_to?(:validate_secret_token)

        args.each do |attribute|
          define_encrypted_attribute(attribute, secret_token, encryptor)
        end
      end
      alias_method :attr_encrypt, :encrypt_attr
      alias_method :attr_encrypted, :encrypt_attr
      alias_method :attr_vault, :encrypt_attr
      alias_method :encrypt_attr, :encrypt_attr
      alias_method :encrypt_attribute, :encrypt_attr
      alias_method :encrypted_attr, :encrypt_attr
      alias_method :encrypted_attribute, :encrypt_attr

      private

      def define_encrypted_attribute(attribute, secret_token, encryptor)
        define_method attribute do
          value = instance_variable_get("@#{attribute}")
          encrypted_value = send("encrypted_#{attribute}") unless value
          value = encryptor.decrypt(secret_token, encrypted_value) if encrypted_value
          instance_variable_set("@#{attribute}", value)
        end

        define_method "#{attribute}=" do |value|
          instance_variable_set("@#{attribute}", value)
          send("encrypted_#{attribute}=", nil)
          send("encrypted_#{attribute}=", encryptor.encrypt(secret_token, value)) if value && value != ""
        end
      end
    end
  end
end