<commit_before># frozen_string_literal: true

module TokenAuthenticatableStrategies
  class Encrypted < Base
    def find_token_authenticatable(token, unscoped = false)
      return unless token

      encrypted_value = Gitlab::CryptoHelper.aes256_gcm_encrypt(token)
      token_authenticatable = relation(unscoped)
        .find_by(encrypted_field => encrypted_value)

      if fallback?
        token_authenticatable ||= fallback_strategy
          .find_token_authenticatable(token)
      end

      token_authenticatable
    rescue ActiveRecord::StatementInvalid
      nil
    end

    def ensure_token(instance)
      # TODO, tech debt, because some specs are testing migrations, but are still
      # using factory bot to create resources, it might happen that a database
      # schema does not have "#{token_name}_encrypted" field yet, however a bunch
      # of models call `ensure_#{token_name}` in `before_save`.
      #
      super if instance.has_attribute?(encrypted_field)
    end

    def get_token(instance)
      raw_token = instance.read_attribute(encrypted_field)
      token = Gitlab::CryptoHelper.aes256_gcm_decrypt(raw_token)

      token || (fallback_strategy.get_token(instance) if fallback?)
    end

    def set_token(instance, token)
      raise ArgumentError unless token.present?

      instance[encrypted_field] = Gitlab::CryptoHelper.aes256_gcm_encrypt(token)
      token
    end

    protected

    def fallback_strategy
      @fallback_strategy ||= TokenAuthenticatableStrategies::Insecure
        .new(klass, token_field, options)
    end

    def token_set?(instance)
      raw_token = instance.read_attribute(encrypted_field)
      raw_token ||= (instance.read_attribute(token_field) if fallback?)

      raw_token.present?<commit_msg>Use falback to set token if encrypted field is missing<commit_after># frozen_string_literal: true

module TokenAuthenticatableStrategies
  class Encrypted < Base
    def find_token_authenticatable(token, unscoped = false)
      return unless token

      encrypted_value = Gitlab::CryptoHelper.aes256_gcm_encrypt(token)
      token_authenticatable = relation(unscoped)
        .find_by(encrypted_field => encrypted_value)

      if fallback?
        token_authenticatable ||= fallback_strategy
          .find_token_authenticatable(token)
      end

      token_authenticatable
    rescue ActiveRecord::StatementInvalid
      nil
    end

    def ensure_token(instance)
      # TODO, tech debt, because some specs are testing migrations, but are still
      # using factory bot to create resources, it might happen that a database
      # schema does not have "#{token_name}_encrypted" field yet, however a bunch
      # of models call `ensure_#{token_name}` in `before_save`.

      return super if instance.has_attribute?(encrypted_field)

      if fallback?
        fallback_strategy.ensure_token(instance)
      else
        raise ArgumentError, 'Encrypted field does not exist without fallback'
      end
    end

    def get_token(instance)
      raw_token = instance.read_attribute(encrypted_field)
      token = Gitlab::CryptoHelper.aes256_gcm_decrypt(raw_token)

      token || (fallback_strategy.get_token(instance) if fallback?)
    end

    def set_token(instance, token)
      raise ArgumentError unless token.present?

      instance[encrypted_field] = Gitlab::CryptoHelper.aes256_gcm_encrypt(token)
      token
    end

    protected

    def fallback_strategy
      @fallback_strategy ||= TokenAuthenticatableStrategies::Insecure
        .new(klass, token_field, options)
    end

    def token_set?(instance)
      raw_token = instance.read_attribute(encrypted_field)
      raw_token ||= (instance.read_attribute(token_field) if fallback?)

      raw_token.present?
{'fraction_non_alphanumeric': 0.06766116142781034, 'fraction_numerical': 0.004794885455514118, 'mean_word_length': 3.5186522262334536, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '6125618', 'n_tokens_mistral': 1115, 'n_tokens_neox': 1069, 'n_words': 259}