<commit_before>require 'addressable/uri'

module OAuth2
  module Server
    class Request

      RESPONSE_TYPES = [ :code, :token ]
      GRANT_TYPES = [ :authorization_code, :password, :client_credentials :refresh_token ]

      attr_reader :response_type, :grant_type, :client_id, :client_secret, :state, :scope, 
                  :errors

      def self.from_http_request
        # create request from http headers
      end

      def initialize(opts={})
        @client_id     = opts[:client_id]
        @client_secret = opts[:client_secret]
        @redirect_uri  = opts[:redirect_uri]
        @response_type = opts[:response_type]
        @grant_type    = opts[:grant_type]
        @state         = opts[:state]
        @scope         = opts[:scope]
        @code          = opts[:code]
        @username      = opts[:username]
        @password      = opts[:password]
        @errors        = {}
        @validated     = nil
      end

      def client_application
        @client_application || validate_client_id
      end

      def client_valid?
        !!client_application
      end

      def grant_type_valid?
        !!validate_grant_type
      rescue OAuth2Error::InvalidRequest => e
        false
      end

      def response_type_valid?
        !!validate_response_type
      rescue OAuth2Error::InvalidRequest => e
        false
      end

      def redirect_uri_valid?
        validate_redirect_uri
      rescue OAuth2Error::InvalidRequest => e
        false
      end

      def redirect_uri
        @redirect_uri.nil? client_application.redirect_uri : validate_redirect_uri
      end

      def authorization_code
        # 
        validate()
        unless @response_type.to_sym == :code
          raise OAuth2Error::UnsupportedResponseType, "The response type, #{@response_type}, is not valid for this request"
        end
        generate_authorization_code
      end

      def authorization_response
        # {
        #   :code => "2YotnFZFEjr1zCsicMWpAA", 
        #   :state => "auth",
        # }
        response = { 
          :code => authorization_code
        }
        response[:state] = state unless state.nil?
        response 
      end

      def authorization_redirect_uri(allow=false) 
        # https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
        build_response_uri authorization_response
      end

      def access_token
        # {
        #   :access_token => "<KEY>zCsicMWpAA", 
        #   :token_type => "bearer",
        #   :expires_in => 3600,
        #   :refresh_token => "<KEY>",
        # }
        validate()
        unless (@grant_type || @response_type.to_sym == :token)
          raise OAuth2Error::InvalidRequest, "The grant type or response type provided is not valid"
        end
        generate_access_token.to_hash
      end

      def access_token_redirect_uri
        # http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600
        build_response_uri :fragment_params => access_token
      end
      
    private

      def build_response_uri(query_params={}, fragment_params=nil)
        uri = Addressable::URI.parse redirect_uri
        uri.query_values = Addressable::URI.form_encode query_params unless query_params.nil?
        uri.fragment = Addressable::URI.form_encode fragment_params unless fragment_params.nil?
        return uri
      end

      def validate
        # check if we already ran validation
        return unless @validated.nil?

        # REQUIRED: Check that client_id is valid
        validate_client_id

        # REQUIRED: Either response_type or grant_type  
        if response_type.nil? && grant_type.nil?
          raise OAuth2Error::InvalidRequest, "Missing parameters: response_type or grant_type"
        end

        # validate response_type if given
        validate_response_type unless @response_type.nil?

        # validate grant_type if given
        validate_grant_type unless @grant_type.nil?

        # validate redirect uri if given grant_type is authorization_code or response_type is token
        if @response_type.to_sym == :token || @grant_type.to_sym == :authorization_code
          validate_redirect_uri
        end

        # validate code if grant_type is authorization_code
        if @grant_type.to_sym == :client_credentials
          validate_client_credentials
        end

        # validate code if grant_type is authorization_code
        if @grant_type.to_sym == :authorization_code
          validate_authorization_code
        end

        # validate user credentials if grant_type is password
        if @grant_type.to_sym == :password
          validate_user_credentials
        end

        # cache validation result
        @validated = true
      end

      def validate_authorization_code
        if @code.nil?
          raise OAuth2Error::InvalidRequest, "Missing parameters: code"
        end
        unless verify_authorization_code
          raise OAuth2Error::UnauthorizedClient, "Authorization code provided did not match client"
        end
        @code
      end

      def validate_client_id
        if @client_id.nil?
          raise OAuth2Error::InvalidRequest, "Missing parameters: client_id"
        end
        @client_application = verify_client_id
        return @client_application unless @client_application.nil?
        raise OAuth2Error::InvalidClient
      end

      def validate_client_credentials
        if @client_id.nil? && @client_secret.nil?
          @errors[:client] = []
          @errors[:client] << "client_id" if @client_id.nil?
          @errors[:client] << "client_secret" if @client_secret.nil?
          raise OAuth2Error::InvalidRequest, "Missing parameters: #{@errors[:client].join(", ")}"
        end
        authenticate_client @client_id, @client_secret
      # rescue Exception => e
      #   @errors[:client] = "Unauthorized Client"
      #   raise OAuth2Error::UnauthorizedClient, @errors[:client] 
      end

      def validate_user_credentials
        if @username.nil? || @password.nil?
          @errors[:user_credentials] = []
          @errors[:user_credentials] << "username" if @username.nil?
          @errors[:user_credentials] << "password" if @password.nil?
          raise OAuth2Error::InvalidRequest, "Missing parameters: #{@errors[:user_credentials].join(", ")}"
        end
        user = authenticate_user @username, @password
        return user unless user.nil?
        @errors[:credentials] = "Invalid username and/or password"
        raise OAuth2Error::AccessDenied
      end

      def validate_response_type
        return RESPONSE_TYPES.include? @response_type.to_sym
        @errors[:response_type] = "Invalid response type"
        raise OAuth2Error::UnsupportedResponseType
      end

      def validate_grant_type
        return GRANT_TYPES.include? @grant_type.to_sym
        @errors[:grant_type] = "Unsupported grant type"
        raise OAuth2Error::UnsupportedGrantType
      end

      def validate_scope
        # FIX ME!!
        @errors[:scope] = "InvalidScope"
        raise OAuth2Error::InvalidScope, "FIX ME!!!!!!"<commit_msg>added refresh token validation to validation flow<commit_after>require 'addressable/uri'

module OAuth2
  module Server
    class Request

      RESPONSE_TYPES = [ :code, :token ]
      GRANT_TYPES = [ :authorization_code, :password, :client_credentials :refresh_token ]

      attr_reader :response_type, :grant_type, :client_id, :client_secret, :state, :scope, 
                  :errors

      def self.from_http_request
        # create request from http headers
      end

      def initialize(opts={})
        @client_id     = opts[:client_id]
        @client_secret = opts[:client_secret]
        @redirect_uri  = opts[:redirect_uri]
        @response_type = opts[:response_type]
        @grant_type    = opts[:grant_type]
        @state         = opts[:state]
        @scope         = opts[:scope]
        @code          = opts[:code]
        @username      = opts[:username]
        @password      = opts[:password]
        @errors        = {}
        @validated     = nil
      end

      def client_application
        @client_application || validate_client_id
      end

      def client_valid?
        !!client_application
      end

      def grant_type_valid?
        !!validate_grant_type
      rescue OAuth2Error::InvalidRequest => e
        false
      end

      def response_type_valid?
        !!validate_response_type
      rescue OAuth2Error::InvalidRequest => e
        false
      end

      def redirect_uri_valid?
        validate_redirect_uri
      rescue OAuth2Error::InvalidRequest => e
        false
      end

      def redirect_uri
        @redirect_uri.nil? client_application.redirect_uri : validate_redirect_uri
      end

      def authorization_code
        # 
        validate()
        unless @response_type.to_sym == :code
          raise OAuth2Error::UnsupportedResponseType, "The response type, #{@response_type}, is not valid for this request"
        end
        generate_authorization_code
      end

      def authorization_response
        # {
        #   :code => "2YotnFZFEjr1zCsicMWpAA", 
        #   :state => "auth",
        # }
        response = { 
          :code => authorization_code
        }
        response[:state] = state unless state.nil?
        response 
      end

      def authorization_redirect_uri(allow=false) 
        # https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
        build_response_uri authorization_response
      end

      def access_token
        # {
        #   :access_token => "<KEY>", 
        #   :token_type => "bearer",
        #   :expires_in => 3600,
        #   :refresh_token => "<KEY>",
        # }
        validate()
        unless (@grant_type.nil? && @response_type.to_sym == :token)
          raise OAuth2Error::UnsupportedResponseType, "The response type provided is not valid for this request"
        end
        generate_access_token.to_hash
      end

      def access_token_redirect_uri
        # http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600
        build_response_uri :fragment_params => access_token
      end
      
    private

      def build_response_uri(query_params={}, fragment_params=nil)
        uri = Addressable::URI.parse redirect_uri
        uri.query_values = Addressable::URI.form_encode query_params unless query_params.nil?
        uri.fragment = Addressable::URI.form_encode fragment_params unless fragment_params.nil?
        return uri
      end

      def validate
        # check if we already ran validation
        return unless @validated.nil?

        # REQUIRED: Check that client_id is valid
        validate_client_id

        # REQUIRED: Either response_type or grant_type  
        if response_type.nil? && grant_type.nil?
          raise OAuth2Error::InvalidRequest, "Missing parameters: response_type or grant_type"
        end

        # validate response_type if given
        validate_response_type unless @response_type.nil?

        # validate grant_type if given
        validate_grant_type unless @grant_type.nil?

        # validate redirect uri if given grant_type is authorization_code or response_type is token
        if @response_type.to_sym == :token || @grant_type.to_sym == :authorization_code
          validate_redirect_uri
        end

        # validate code if grant_type is client_credentials
        if @grant_type.to_sym == :client_credentials
          validate_client_credentials
        end

        # validate code if grant_type is authorization_code
        if @grant_type.to_sym == :authorization_code
          validate_authorization_code
        end

        # validate user credentials if grant_type is password
        if @grant_type.to_sym == :password
          validate_user_credentials
        end

        # validate user credentials if grant_type is password
        if @grant_type.to_sym == :refresh_token
          validate_refresh_token
        end

        # cache validation result
        @validated = true
      end

      def validate_authorization_code
        if @code.nil?
          raise OAuth2Error::InvalidRequest, "Missing parameters: code"
        end
        unless verify_authorization_code
          raise OAuth2Error::UnauthorizedClient, "Authorization code provided did not match client"
        end
        @code
      end

      def validate_client_id
        if @client_id.nil?
          raise OAuth2Error::InvalidRequest, "Missing parameters: client_id"
        end
        @client_application = verify_client_id
        return @client_application unless @client_application.nil?
        raise OAuth2Error::InvalidClient
      end

      def validate_client_credentials
        if @client_id.nil? && @client_secret.nil?
          @errors[:client] = []
          @errors[:client] << "client_id" if @client_id.nil?
          @errors[:client] << "client_secret" if @client_secret.nil?
          raise OAuth2Error::InvalidRequest, "Missing parameters: #{@errors[:client].join(", ")}"
        end
        authenticate_client @client_id, @client_secret
      # rescue Exception => e
      #   @errors[:client] = "Unauthorized Client"
      #   raise OAuth2Error::UnauthorizedClient, @errors[:client] 
      end

      def validate_user_credentials
        if @username.nil? || @password.nil?
          @errors[:user_credentials] = []
          @errors[:user_credentials] << "username" if @username.nil?
          @errors[:user_credentials] << "password" if @password.nil?
          raise OAuth2Error::InvalidRequest, "Missing parameters: #{@errors[:user_credentials].join(", ")}"
        end
        user = authenticate_user @username, @password
        return user unless user.nil?
        @errors[:credentials] = "Invalid username and/or password"
        raise OAuth2Error::AccessDenied
      end

      def validate_response_type
        return RESPONSE_TYPES.include? @response_type.to_sym
        @errors[:response_type] = "Invalid response type"
        raise OAuth2Error::UnsupportedResponseType
      end

      def validate_grant_type
        return GRANT_TYPES.include? @grant_type.to_sym
        @errors[:grant_type] = "Unsupported grant type"
        raise OAuth2Error::UnsupportedGrantType
      end

      def validate_refresh_token
        if @refresh_token.nil?
          raise OAuth2Error::InvalidRequest, "Missing parameters: refresh_token"
        end
        token = verify_refresh_token
        return true unless token.nil?
        raise OAuth2Error::InvalidRequest, "Invalid refresh token" 
      end

      def validate_scope
        # FIX ME!!
        @errors[:scope] = "InvalidScope"
        raise OAuth2Error::InvalidScope, "FIX ME!!!!!!"
{'fraction_non_alphanumeric': 0.07948856717629549, 'fraction_numerical': 0.0043295900419429035, 'mean_word_length': 2.3976097448862332, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 31, 'https://': 2, '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': '5700733', 'n_tokens_mistral': 4206, 'n_tokens_neox': 4055, 'n_words': 937}