<commit_before>require 'base64'
require_relative 'setting/cipher'
module MournfulSettings
  class Setting < ActiveRecord::Base
    
    self.table_name = 'mournful_settings_settings'
       
    VALUE_TYPES = ['text', 'number', 'decimal']
    
    before_save :encrypt_text

    validates :value_type, :presence => true, :inclusion => {:in => VALUE_TYPES}
    validates :value, :presence => true
    validates :name, :uniqueness => true, :presence => true

    def self.value_types
      VALUE_TYPES
    end
    
    def self.for(name)
      setting = find_by_name(name)
      setting.value if setting
    end

    def value
      if value_type.present? 
        parent_value = encrypted? ? decrypt(super) : super
        
        case value_type.to_s
          when 'number'
            parent_value.to_f
          when 'decimal'
            BigDecimal.new(parent_value.to_s)
          else
            parent_value
        end
      end
    end
    
    private
    def encrypt(text)
      add_separators Base64.encode64 Cipher.encrypt text.to_s
    end
    
    def decrypt(text)
      if is_encrypted?(text)
        Cipher.decrypt Base64.decode64 remove_separators text
      else
        text
      end
    end
    
    def is_encrypted?(text)
      inside_separators_and_is_base64_encoded?(text)
    end

    def inside_separators_and_is_base64_encoded?(text)
      return false unless text.kind_of? String
      elements = {
        :starts_with_separator => "^#{separator}",
        :non_white_space_with_equal_sign_packing => '\S+=*',
        :base64_end => "\n",
        :ends_with_separator => "#{separator}$"
      }
      pattern = elements.values.join
      /#{pattern}/ =~ text      
    end
    
    def is_separator_delimited(text)
      
    end
    
    def encrypt_text  
      if encrypted?
        self.value = encrypt(self.value)
      else
        self.value = decrypt(self.value)
      end
    end
    
    def add_separators(text)
      [separator, text, separator].join
    end
    
    def remove_separators(text)
      text.gsub(separator, "")
    end
    
    def separator
      31.chr # ASCII unit separator
    end
    
  end
end<commit_msg>Removes dependency on matching value encoding to determine if it is encrypted<commit_after>require 'base64'
require_relative 'setting/cipher'
module MournfulSettings
  class Setting < ActiveRecord::Base
    
    self.table_name = 'mournful_settings_settings'
       
    VALUE_TYPES = ['text', 'number', 'decimal']
    
    before_save :encrypt_text

    validates :value_type, :presence => true, :inclusion => {:in => VALUE_TYPES}
    validates :value, :presence => true
    validates :name, :uniqueness => true, :presence => true

    def self.value_types
      VALUE_TYPES
    end
    
    def self.for(name)
      setting = find_by_name(name)
      setting.value if setting
    end

    def value
      if value_type.present? 
        parent_value = encrypted? ? decrypt(super) : super
        
        case value_type.to_s
          when 'number'
            parent_value.to_f
          when 'decimal'
            BigDecimal.new(parent_value.to_s)
          else
            parent_value
        end
      end
    end
    
    private
    def encrypt(text)
      add_separators Base64.encode64 Cipher.encrypt text.to_s
    end
    
    def decrypt(text)
      if is_encrypted?(text)
        Cipher.decrypt Base64.decode64 remove_separators text
      else
        text
      end
    end
    
    def is_encrypted?(text)
      inside_separators_and_is_base64_encoded?(text)
    end

    def inside_separators_and_is_base64_encoded?(text)
      return unless text.kind_of? String
      bytes = text.bytes.to_a
      return unless bytes[0] == ascii_unit_separator_byte
      return unless bytes[-1] == ascii_unit_separator_byte
      return unless bytes[-2] == last_byte_of_base_64_encoded_text
      non_white_space_with_equal_sign_packing =~ text[1..-3]
    end
    
    def non_white_space_with_equal_sign_packing 
      /\S+=*/
    end

    
    def encrypt_text  
      if encrypted?
        self.value = encrypt(self.value)
      else
        self.value = decrypt(self.value)
      end
    end
    
    def add_separators(text)
      [separator, text, separator].join
    end
    
    def remove_separators(text)
      text.gsub(separator, "")
    end
   
    # Used to delimit encrypted values to make identification more reliable
    def separator
      ascii_unit_separator_byte.chr 
    end
    
    def ascii_unit_separator_byte
      31
    end
    
    def last_byte_of_base_64_encoded_text
      line_feed_byte
    end
    
    def line_feed_byte
      10
    end
    
  end
end
{'fraction_non_alphanumeric': 0.07390745501285347, 'fraction_numerical': 0.009640102827763496, 'mean_word_length': 2.171875, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 19, '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': '7198952', 'n_tokens_mistral': 1536, 'n_tokens_neox': 1469, 'n_words': 322}