<commit_before>require 'devise/strategies/authenticatable'
require 'tiddle/model_name'
require 'tiddle/token_issuer'

module Devise
  module Strategies
    class TokenAuthenticatable < Authenticatable
      def authenticate!
        env["devise.skip_trackable"] = true

        resource = mapping.to.find_for_authentication(authentication_keys_from_headers)
        return fail(:invalid_token) unless resource

        token = Tiddle::TokenIssuer.build.find_token(resource, token_from_headers)
        if token && unexpired?(token)
          touch_token(token)
          return success!(resource)
        end

        fail(:invalid_token)
      end

      def valid?
        authentication_keys_from_headers.present? && token_from_headers.present?
      end

      def store?
        false
      end

      private

      def authentication_keys_from_headers
        authentication_keys.map do |key|
          { key => env["HTTP_X_#{model_name}_#{key.upcase}"] }
        end.reduce(:merge)
      end

      def token_from_headers
        env["HTTP_X_#{model_name}_TOKEN"]
      end

      def model_name
        Tiddle::ModelName.new.with_underscores(mapping.to)
      end

      def authentication_keys
        mapping.to.authentication_keys
      end

      def touch_token(token)
        token.update_attribute(:last_used_at, Time.current) if token.last_used_at < 1.hour.ago
      end

      def unexpired?(token)
        return true if token.expires_in == 0
        DateTime.current <= token.last_used_at + token.expires_in
      end
    end
  end
end

Warden::Strategies.add(:token_authenticatable, Devise::Strategies::TokenAuthenticatable)<commit_msg>few minor changes<commit_after>require 'devise/strategies/authenticatable'
require 'tiddle/model_name'
require 'tiddle/token_issuer'

module Devise
  module Strategies
    class TokenAuthenticatable < Authenticatable
      def authenticate!
        env["devise.skip_trackable"] = true

        resource = mapping.to.find_for_authentication(authentication_keys_from_headers)
        return fail(:invalid_token) unless resource

        token = Tiddle::TokenIssuer.build.find_token(resource, token_from_headers)
        if token && unexpired?(token)
          touch_token(token)
          return success!(resource)
        end

        fail(:invalid_token)
      end

      def valid?
        authentication_keys_from_headers.present? && token_from_headers.present?
      end

      def store?
        false
      end

      private

      def authentication_keys_from_headers
        authentication_keys.map do |key|
          { key => env["HTTP_X_#{model_name}_#{key.upcase}"] }
        end.reduce(:merge)
      end

      def token_from_headers
        env["HTTP_X_#{model_name}_TOKEN"]
      end

      def model_name
        Tiddle::ModelName.new.with_underscores(mapping.to)
      end

      def authentication_keys
        mapping.to.authentication_keys
      end

      def touch_token(token)
        token.update_attribute(:last_used_at, Time.current) if token.last_used_at < 1.hour.ago
      end

      def unexpired?(token)
        return true if token.expires_in.zero?
        Time.current <= token.last_used_at + token.expires_in
      end
    end
  end
end

Warden::Strategies.add(:token_authenticatable, Devise::Strategies::TokenAuthenticatable)
{'fraction_non_alphanumeric': 0.07903469079939668, 'fraction_numerical': 0.0009049773755656109, 'mean_word_length': 2.7853881278538815, 'pattern_counts': {'":': 0, '<': 9, '<?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': '199822', 'n_tokens_mistral': 1000, 'n_tokens_neox': 976, 'n_words': 180}