123456789_123456789_123456789_123456789_123456789_

Class: Gem::GemcutterUtilities::WebauthnPoller

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
Inherits: Object
Defined in: lib/rubygems/gemcutter_utilities/webauthn_poller.rb

Constant Summary

::Gem::GemcutterUtilities - Included

API_SCOPES, ERROR_CODE, EXCLUSIVELY_API_SCOPES

Class Method Summary

Instance Attribute Summary

::Gem::GemcutterUtilities - Included

#host

The host to connect to either from the RUBYGEMS_HOST environment variable or from the user’s configuration.

#host=, #scope=, #webauthn_enabled?, #default_host?

Instance Method Summary

::Gem::GemcutterUtilities - Included

#add_key_option

Add the –key option.

#add_otp_option

Add the –otp option.

#api_key

The API key from the command options or from the user’s configuration.

#mfa_unauthorized?,
#otp

The OTP code from the command options or from the user’s configuration.

#rubygems_api_request

Creates an RubyGems API to #host and Gem.path with the given HTTP method.

#set_api_key

Returns true when the user has enabled multifactor authentication from response text and no otp provided by options.

#sign_in

Signs in with the RubyGems API at sign_in_host and sets the rubygems API key.

#update_scope,
#verify_api_key

Retrieves the pre-configured API key key or terminates interaction with an error.

#with_response

If response is an HTTP Success (2XX) response, yields the response if a block was given or shows the response body to the user.

#api_key_forbidden?, #fetch_otp, #get_key_name, #get_mfa_params, #get_scope_params, #get_user_profile, #pretty_host, #request_with_otp, #wait_for_otp_thread, #webauthn_verification_url

::Gem::Text - Included

#clean_text

Remove any non-printable characters and make the text suitable for printing.

#format_text

Wraps text to wrap characters and optionally indents by indent characters.

#levenshtein_distance

Returns a value representing the “cost” of transforming str1 into str2 Vendored version of DidYouMean::Levenshtein.distance from the ruby/did_you_mean gem @ 1.4.0 github.com/ruby/did_you_mean/blob/2ddf39b874808685965dbc47d344cf6c7651807c/lib/did_you_mean/levenshtein.rb#L7-L37.

#truncate_text, #min3

Constructor Details

.new(options, host) ⇒ WebauthnPoller

[ GitHub ]

  
# File 'lib/rubygems/gemcutter_utilities/webauthn_poller.rb', line 29

def initialize(options, host)
  @options = options
  @host = host
end

Class Method Details

.poll_thread(options, host, webauthn_url, credentials)

[ GitHub ]

  
# File 'lib/rubygems/gemcutter_utilities/webauthn_poller.rb', line 34

def self.poll_thread(options, host, webauthn_url, credentials)
  Thread.new do
    thread = Thread.current
    thread.abort_on_exception = true
    thread.report_on_exception = false
    thread[:otp] = new(options, host).poll_for_otp(webauthn_url, credentials)
  rescue Gem::WebauthnVerificationError, Gem::Timeout::Error => e
    thread[:error] = e
  end
end

Instance Attribute Details

#host (readonly)

[ GitHub ]

  
# File 'lib/rubygems/gemcutter_utilities/webauthn_poller.rb', line 27

attr_reader :options, :host

#options (readonly)

[ GitHub ]

  
# File 'lib/rubygems/gemcutter_utilities/webauthn_poller.rb', line 27

attr_reader :options, :host

Instance Method Details

#poll_for_otp(webauthn_url, credentials)

[ GitHub ]

  
# File 'lib/rubygems/gemcutter_utilities/webauthn_poller.rb', line 45

def poll_for_otp(webauthn_url, credentials)
  Gem::Timeout.timeout(TIMEOUT_IN_SECONDS) do
    loop do
      response = webauthn_verification_poll_response(webauthn_url, credentials)
      raise Gem::WebauthnVerificationError, response.message unless response.is_a?(Gem::Net::HTTPSuccess)

      require "json"
      parsed_response = JSON.parse(response.body)
      case parsed_response["status"]
      when "pending"
        sleep 5
      when "success"
        return parsed_response["code"]
      else
        raise Gem::WebauthnVerificationError, parsed_response.fetch("message", "Invalid response from server")
      end
    end
  end
end

#webauthn_verification_poll_response(webauthn_url, credentials) (private)

[ GitHub ]

  
# File 'lib/rubygems/gemcutter_utilities/webauthn_poller.rb', line 67

def webauthn_verification_poll_response(webauthn_url, credentials)
  webauthn_token = %r{(?<=\/)[^\/]+(?=$)}.match(webauthn_url)[0]
  rubygems_api_request(:get, "api/v1/webauthn_verification/#{webauthn_token}/status.json") do |request|
    if credentials.empty?
      request.add_field "Authorization", api_key
    elsif credentials[:identifier] && credentials[:password]
      request.basic_auth credentials[:identifier], credentials[:password]
    else
      raise Gem::WebauthnVerificationError, "Provided missing credentials"
    end
  end
end