diff options
-rw-r--r-- | lib/rubygems/gemcutter_utilities.rb | 8 | ||||
-rw-r--r-- | test/rubygems/test_gem_gemcutter_utilities.rb | 59 |
2 files changed, 56 insertions, 11 deletions
diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb index 3ee8579933..c4f31dc0d6 100644 --- a/lib/rubygems/gemcutter_utilities.rb +++ b/lib/rubygems/gemcutter_utilities.rb @@ -2,6 +2,7 @@ require_relative "remote_fetcher" require_relative "text" +require_relative "webauthn_listener" ## # Utility methods for using the RubyGems API. @@ -260,13 +261,16 @@ module Gem::GemcutterUtilities end def wait_for_otp(webauthn_url) + server = TCPServer.new 0 + port = server.addr[1].to_s + thread = Thread.new do - Thread.current[:otp] = "Uvh6T57tkWuUnWYo" + Thread.current[:otp] = Gem::WebauthnListener.wait_for_otp_code(host, server) end thread.abort_on_exception = true thread.report_on_exception = false - url_with_port = "#{webauthn_url}?port=5678" + url_with_port = "#{webauthn_url}?port=#{port}" say "You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device." thread.join diff --git a/test/rubygems/test_gem_gemcutter_utilities.rb b/test/rubygems/test_gem_gemcutter_utilities.rb index aa876e6ca8..93aec0c67c 100644 --- a/test/rubygems/test_gem_gemcutter_utilities.rb +++ b/test/rubygems/test_gem_gemcutter_utilities.rb @@ -235,22 +235,63 @@ class TestGemGemcutterUtilities < Gem::TestCase webauthn_verification_url = "rubygems.org/api/v1/webauthn_verification/odow34b93t6aPCdY" response_fail = "You have enabled multifactor authentication" api_key = "a5fdbb6ba150cbb83aad2bb2fede64cf040453903" - - util_sign_in(proc do - @call_count ||= 0 - if (@call_count += 1).odd? - HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized") - else - HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK") + port = 5678 + server = TCPServer.new(port) + + TCPServer.stub(:new, server) do + Gem::WebauthnListener.stub(:wait_for_otp_code, "Uvh6T57tkWuUnWYo") do + util_sign_in(proc do + @call_count ||= 0 + if (@call_count += 1).odd? + HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized") + else + HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK") + end + end, nil, [], "", webauthn_verification_url) end - end, nil, [], "", webauthn_verification_url) + ensure + server.close + end - url_with_port = "#{webauthn_verification_url}?port=5678" + url_with_port = "#{webauthn_verification_url}?port=#{port}" assert_match "You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device.", @sign_in_ui.output assert_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"] end + def test_sign_in_with_webauthn_enabled_with_error + webauthn_verification_url = "rubygems.org/api/v1/webauthn_verification/odow34b93t6aPCdY" + response_fail = "You have enabled multifactor authentication" + api_key = "a5fdbb6ba150cbb83aad2bb2fede64cf040453903" + port = 5678 + server = TCPServer.new(port) + raise_error = ->(*_args) { raise Gem::WebauthnVerificationError, "Something went wrong" } + + error = assert_raise Gem::WebauthnVerificationError do + TCPServer.stub(:new, server) do + Gem::WebauthnListener.stub(:wait_for_otp_code, raise_error) do + util_sign_in(proc do + @call_count ||= 0 + if (@call_count += 1).odd? + HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized") + else + HTTPResponseFactory.create(body: api_key, code: 200, msg: "OK") + end + end, nil, [], "", webauthn_verification_url) + end + ensure + server.close + end + end + + assert_equal "Security device verification failed: Something went wrong", error.message + + url_with_port = "#{webauthn_verification_url}?port=#{port}" + assert_match "You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device.", @sign_in_ui.output + refute_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output + refute_match "Signed in with API key:", @sign_in_ui.output + end + def util_sign_in(response, host = nil, args = [], extra_input = "", webauthn_url = nil) email = "you@example.com" password = "secret" |