<commit_before>require 'openssl'
require 'iconv'
require 'active_record'
require 'base64'

module HotLikeSauce

  def self.secret_key
    @secret_key ||= "please_init_this_somewhere_before_using"
  end

  def self.secret_key=(val)
    @secret_key = val
  end

  def self.crypto_method
    @crypto_method ||= "aes-256-cbc"
  end

  def self.crypto_method=(val)
    @crypto_method = val
  end

  module ARMethods

    def inherited(child_class)
      child_class.send :extend,  HotLikeSauce::ClassMethods
      child_class.send :include, HotLikeSauce::InstanceMethods
    end

  end

  module ClassMethods

    def obscured_fields
      @obscured_fields ||= []
    end

    def obscured_fields=(val)
      @obscured_fields = val
    end

    def unobscured_read_fields
      @unobscured_read_fields ||= []
    end

    def unobscured_read_fields=(val)
      @unobscured_read_fields = val
    end

    def attr_obscurable(*args)
      fields = args.map {|arg| arg if arg.is_a?(Symbol)}.compact
      options = args.map {|arg| arg if arg.is_a?(Hash)}.compact.first
      options ||= {}

      fields.each do |field|

        type = self.columns_hash[field.to_s].type
        raise "#{field} must be a string or text field" unless type == :string || type == :text
        self.obscured_fields = (self.obscured_fields << field).uniq
        self.unobscured_read_fields = (self.unobscured_read_fields << field).uniq unless options[:obscure_on_read] == true

        define_method field do
          super()
          value = Base64::decode64(read_attribute(field))
          self.class.unobscured_read_fields.include?(field) ? _unobscure(value) : value
        end

        define_method "#{field}=" do |value|
          super(value)
          write_attribute(field, Base64::encode64(_obscure(value)))
        end

      end

    end

    def obscure_read_on_fields!(*fields_array)
      if fields_array.empty?
        self.unobscured_read_fields = []
      else
        self.unobscured_read_fields -= fields_array
      end
    end

    def unobscure_read_on_fields!(*fields_array)
      if fields_array.empty?
        self.unobscured_read_fields = self.obscured_fields
      else
        self.unobscured_read_fields += self.obscured_fields & fields_array
      end
    end

  end

  module InstanceMethods

  private

    def _obscure(value)
      _crypt :encrypt, HotLikeSauce::secret_key, value
    end

    def _unobscure(value)
      _crypt :decrypt, HotLikeSauce::secret_key, value
    end

    def _crypt(method, key, value)
      cipher = OpenSSL::Cipher::Cipher.new(HotLikeSauce::crypto_method)
      cipher.send(method)
      cipher.pkcs5_keyivgen(key)
      cipher.update(value) + cipher.final
    end

  end

end


ActiveRecord::Base.send :extend,  HotLikeSauce::ARMethods<commit_msg>move base64'ing to the _obscure and _unobscure methods<commit_after>require 'openssl'
require 'iconv'
require 'active_record'
require 'base64'

module HotLikeSauce

  def self.secret_key
    @secret_key ||= "please_init_this_somewhere_before_using"
  end

  def self.secret_key=(val)
    @secret_key = val
  end

  def self.crypto_method
    @crypto_method ||= "aes-256-cbc"
  end

  def self.crypto_method=(val)
    @crypto_method = val
  end

  module ARMethods

    def inherited(child_class)
      child_class.send :extend,  HotLikeSauce::ClassMethods
      child_class.send :include, HotLikeSauce::InstanceMethods
    end

  end

  module ClassMethods

    def obscured_fields
      @obscured_fields ||= []
    end

    def obscured_fields=(val)
      @obscured_fields = val
    end

    def unobscured_read_fields
      @unobscured_read_fields ||= []
    end

    def unobscured_read_fields=(val)
      @unobscured_read_fields = val
    end

    def attr_obscurable(*args)
      fields = args.map {|arg| arg if arg.is_a?(Symbol)}.compact
      options = args.map {|arg| arg if arg.is_a?(Hash)}.compact.first
      options ||= {}

      fields.each do |field|

        type = self.columns_hash[field.to_s].type
        raise "#{field} must be a string or text field" unless type == :string || type == :text
        self.obscured_fields = (self.obscured_fields << field).uniq
        self.unobscured_read_fields = (self.unobscured_read_fields << field).uniq unless options[:obscure_on_read] == true

        define_method field do
          super()
          value = read_attribute(field)
          self.class.unobscured_read_fields.include?(field) ? _unobscure(value) : value
        end

        define_method "#{field}=" do |value|
          super(value)
          write_attribute(field, _obscure(value))
        end

      end

    end

    def obscure_read_on_fields!(*fields_array)
      if fields_array.empty?
        self.unobscured_read_fields = []
      else
        self.unobscured_read_fields -= fields_array
      end
    end

    def unobscure_read_on_fields!(*fields_array)
      if fields_array.empty?
        self.unobscured_read_fields = self.obscured_fields
      else
        self.unobscured_read_fields += self.obscured_fields & fields_array
      end
    end

  end

  module InstanceMethods

  private

    def _obscure(value)
      Base64::encode64(_crypt(:encrypt, HotLikeSauce::secret_key, value))
    end

    def _unobscure(value)
      _crypt(:decrypt, HotLikeSauce::secret_key, Base64::decode64(value))
    end

    def _crypt(method, key, value)
      cipher = OpenSSL::Cipher::Cipher.new(HotLikeSauce::crypto_method)
      cipher.send(method)
      cipher.pkcs5_keyivgen(key)
      cipher.update(value) + cipher.final
    end

  end

end


ActiveRecord::Base.send :extend,  HotLikeSauce::ARMethods
{'fraction_non_alphanumeric': 0.09265516628134447, 'fraction_numerical': 0.005335230304108127, 'mean_word_length': 2.949438202247191, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3671148', 'n_tokens_mistral': 1957, 'n_tokens_neox': 1859, 'n_words': 366}