From 24913e3dda3d4ebd633e94e46ca221ebfcb9f89b Mon Sep 17 00:00:00 2001 From: Jenny Shen Date: Fri, 30 Jun 2023 23:45:27 -0400 Subject: [rubygems/rubygems] Move Webauthn listener thread to WebauthnListener class https://github.com/rubygems/rubygems/commit/6ec474975e --- .../gemcutter_utilities/webauthn_listener.rb | 14 ++++++------- test/rubygems/test_gem_commands_owner_command.rb | 6 +++--- test/rubygems/test_gem_commands_push_command.rb | 6 +++--- test/rubygems/test_gem_commands_yank_command.rb | 6 +++--- test/rubygems/test_gem_gemcutter_utilities.rb | 6 +++--- test/rubygems/test_webauthn_listener.rb | 23 +++++++++++++++++++--- test/rubygems/test_webauthn_listener_response.rb | 2 +- 7 files changed, 39 insertions(+), 24 deletions(-) diff --git a/lib/rubygems/gemcutter_utilities/webauthn_listener.rb b/lib/rubygems/gemcutter_utilities/webauthn_listener.rb index 5db6604f1a..ee3fc7bcab 100644 --- a/lib/rubygems/gemcutter_utilities/webauthn_listener.rb +++ b/lib/rubygems/gemcutter_utilities/webauthn_listener.rb @@ -18,8 +18,10 @@ require_relative "webauthn_listener/response" # # Example usage: # -# server = TCPServer.new(0) -# otp = Gem::WebauthnListener.wait_for_otp_code("https://rubygems.example", server) +# thread = Gem::WebauthnListener.listener_thread("https://rubygems.example", server) +# thread.join +# otp = thread[:otp] +# error = thread[:error] # module Gem::GemcutterUtilities @@ -32,7 +34,7 @@ module Gem::GemcutterUtilities def self.listener_thread(host, server) thread = Thread.new do - Thread.current[:otp] = wait_for_otp_code(host, server) + Thread.current[:otp] = new(host).wait_for_otp_code(server) rescue Gem::WebauthnVerificationError => e Thread.current[:error] = e ensure @@ -44,11 +46,7 @@ module Gem::GemcutterUtilities thread end - def self.wait_for_otp_code(host, server) - new(host).fetch_otp_from_connection(server) - end - - def fetch_otp_from_connection(server) + def wait_for_otp_code(server) loop do socket = server.accept request_line = socket.gets diff --git a/test/rubygems/test_gem_commands_owner_command.rb b/test/rubygems/test_gem_commands_owner_command.rb index bf50054816..fd9b1445a7 100644 --- a/test/rubygems/test_gem_commands_owner_command.rb +++ b/test/rubygems/test_gem_commands_owner_command.rb @@ -381,7 +381,7 @@ EOF ) TCPServer.stub(:new, server) do - Gem::GemcutterUtilities::WebauthnListener.stub(:wait_for_otp_code, "Uvh6T57tkWuUnWYo") do + Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:otp] = "Uvh6T57tkWuUnWYo" }) do use_ui @stub_ui do @cmd.add_owners("freewill", ["user-new1@example.com"]) end @@ -403,7 +403,7 @@ EOF response_success = "Owner added successfully." port = 5678 server = TCPServer.new(port) - raise_error = ->(*_args) { raise Gem::WebauthnVerificationError, "Something went wrong" } + error = Gem::WebauthnVerificationError.new("Something went wrong") @stub_fetcher.data["#{Gem.host}/api/v1/webauthn_verification"] = HTTPResponseFactory.create(body: webauthn_verification_url, code: 200, msg: "OK") @stub_fetcher.data["#{Gem.host}/api/v1/gems/freewill/owners"] = [ @@ -417,7 +417,7 @@ EOF ) TCPServer.stub(:new, server) do - Gem::GemcutterUtilities::WebauthnListener.stub(:wait_for_otp_code, raise_error) do + Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:error] = error }) do use_ui @stub_ui do @cmd.add_owners("freewill", ["user-new1@example.com"]) end diff --git a/test/rubygems/test_gem_commands_push_command.rb b/test/rubygems/test_gem_commands_push_command.rb index d1e8a392ee..b364c34865 100644 --- a/test/rubygems/test_gem_commands_push_command.rb +++ b/test/rubygems/test_gem_commands_push_command.rb @@ -445,7 +445,7 @@ class TestGemCommandsPushCommand < Gem::TestCase ) TCPServer.stub(:new, server) do - Gem::GemcutterUtilities::WebauthnListener.stub(:wait_for_otp_code, "Uvh6T57tkWuUnWYo") do + Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:otp] = "Uvh6T57tkWuUnWYo" }) do use_ui @ui do @cmd.send_gem(@path) end @@ -467,7 +467,7 @@ class TestGemCommandsPushCommand < Gem::TestCase response_success = "Successfully registered gem: freewill (1.0.0)" port = 5678 server = TCPServer.new(port) - raise_error = ->(*_args) { raise Gem::WebauthnVerificationError, "Something went wrong" } + error = Gem::WebauthnVerificationError.new("Something went wrong") @fetcher.data["#{Gem.host}/api/v1/gems"] = [ HTTPResponseFactory.create(body: response_fail, code: 401, msg: "Unauthorized"), @@ -482,7 +482,7 @@ class TestGemCommandsPushCommand < Gem::TestCase error = assert_raise Gem::MockGemUi::TermError do TCPServer.stub(:new, server) do - Gem::GemcutterUtilities::WebauthnListener.stub(:wait_for_otp_code, raise_error) do + Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:error] = error }) do use_ui @ui do @cmd.send_gem(@path) end diff --git a/test/rubygems/test_gem_commands_yank_command.rb b/test/rubygems/test_gem_commands_yank_command.rb index c45086e7a5..6a038c6ccb 100644 --- a/test/rubygems/test_gem_commands_yank_command.rb +++ b/test/rubygems/test_gem_commands_yank_command.rb @@ -141,7 +141,7 @@ class TestGemCommandsYankCommand < Gem::TestCase @cmd.options[:version] = req("= 1.0") TCPServer.stub(:new, server) do - Gem::GemcutterUtilities::WebauthnListener.stub(:wait_for_otp_code, "Uvh6T57tkWuUnWYo") do + Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:otp] = "Uvh6T57tkWuUnWYo" }) do use_ui @ui do @cmd.execute end @@ -166,7 +166,7 @@ class TestGemCommandsYankCommand < Gem::TestCase status_uri = "http://example/api/v1/webauthn_verification/odow34b93t6aPCdY/status.json" port = 5678 server = TCPServer.new(port) - raise_error = ->(*_args) { raise Gem::WebauthnVerificationError, "Something went wrong" } + error = Gem::WebauthnVerificationError.new("Something went wrong") @fetcher.data[webauthn_uri] = HTTPResponseFactory.create(body: webauthn_verification_url, code: 200, msg: "OK") @fetcher.data[yank_uri] = [ @@ -185,7 +185,7 @@ class TestGemCommandsYankCommand < Gem::TestCase error = assert_raise Gem::MockGemUi::TermError do TCPServer.stub(:new, server) do - Gem::GemcutterUtilities::WebauthnListener.stub(:wait_for_otp_code, raise_error) do + Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:error] = error }) do use_ui @ui do @cmd.execute end diff --git a/test/rubygems/test_gem_gemcutter_utilities.rb b/test/rubygems/test_gem_gemcutter_utilities.rb index fd10fcfa56..e9041c8d59 100644 --- a/test/rubygems/test_gem_gemcutter_utilities.rb +++ b/test/rubygems/test_gem_gemcutter_utilities.rb @@ -229,7 +229,7 @@ class TestGemGemcutterUtilities < Gem::TestCase @fetcher.respond_with_require_otp @fetcher.respond_with_webauthn_url(webauthn_verification_url) TCPServer.stub(:new, server) do - Gem::GemcutterUtilities::WebauthnListener.stub(:wait_for_otp_code, "Uvh6T57tkWuUnWYo") do + Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:otp] = "Uvh6T57tkWuUnWYo" }) do util_sign_in end ensure @@ -246,13 +246,13 @@ class TestGemGemcutterUtilities < Gem::TestCase webauthn_verification_url = "rubygems.org/api/v1/webauthn_verification/odow34b93t6aPCdY" port = 5678 server = TCPServer.new(port) - raise_error = ->(*_args) { raise Gem::WebauthnVerificationError, "Something went wrong" } + error = Gem::WebauthnVerificationError.new("Something went wrong") @fetcher.respond_with_require_otp @fetcher.respond_with_webauthn_url(webauthn_verification_url) error = assert_raise Gem::MockGemUi::TermError do TCPServer.stub(:new, server) do - Gem::GemcutterUtilities::WebauthnListener.stub(:wait_for_otp_code, raise_error) do + Gem::GemcutterUtilities::WebauthnListener.stub(:listener_thread, Thread.new { Thread.current[:error] = error }) do util_sign_in end ensure diff --git a/test/rubygems/test_webauthn_listener.rb b/test/rubygems/test_webauthn_listener.rb index c4e53ffe01..45745eb935 100644 --- a/test/rubygems/test_webauthn_listener.rb +++ b/test/rubygems/test_webauthn_listener.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true require_relative "helper" -require "rubygems/webauthn_listener" +require "rubygems/gemcutter_utilities/webauthn_listener" +require "rubygems/gemcutter_utilities" class WebauthnListenerTest < Gem::TestCase def setup @@ -16,6 +17,22 @@ class WebauthnListenerTest < Gem::TestCase super end + def test_listener_thread_retreives_otp_code + thread = Gem::GemcutterUtilities::WebauthnListener.listener_thread(Gem.host, @server) + Gem::MockBrowser.get URI("http://localhost:#{@port}?code=xyz") + + thread.join + assert_equal "xyz", thread[:otp] + end + + def test_listener_thread_sets_error + thread = Gem::GemcutterUtilities::WebauthnListener.listener_thread(Gem.host, @server) + Gem::MockBrowser.post URI("http://localhost:#{@port}?code=xyz") + + thread.join + assert_equal "Security device verification failed: Invalid HTTP method POST received.", thread[:error].message + end + def test_wait_for_otp_code_get_follows_options wait_for_otp_code assert Gem::MockBrowser.options(URI("http://localhost:#{@port}?code=xyz")).is_a? Net::HTTPNoContent @@ -106,7 +123,7 @@ class WebauthnListenerTest < Gem::TestCase def wait_for_otp_code @thread = Thread.new do - Thread.current[:otp] = Gem::GemcutterUtilities::WebauthnListener.wait_for_otp_code(Gem.host, @server) + Thread.current[:otp] = Gem::GemcutterUtilities::WebauthnListener.new(Gem.host).wait_for_otp_code(@server) end @thread.abort_on_exception = true @thread.report_on_exception = false @@ -115,7 +132,7 @@ class WebauthnListenerTest < Gem::TestCase def wait_for_otp_code_expect_error_with_message(message) @thread = Thread.new do error = assert_raise Gem::WebauthnVerificationError do - Thread.current[:otp] = Gem::GemcutterUtilities::WebauthnListener.wait_for_otp_code(Gem.host, @server) + Thread.current[:otp] = Gem::GemcutterUtilities::WebauthnListener.new(Gem.host).wait_for_otp_code(@server) end assert_equal message, error.message diff --git a/test/rubygems/test_webauthn_listener_response.rb b/test/rubygems/test_webauthn_listener_response.rb index c2622a6a0f..ce617ebada 100644 --- a/test/rubygems/test_webauthn_listener_response.rb +++ b/test/rubygems/test_webauthn_listener_response.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require_relative "helper" -require "rubygems/webauthn_listener/response" +require "rubygems/gemcutter_utilities/webauthn_listener/response" class WebauthnListenerResponseTest < Gem::TestCase def setup -- cgit v1.2.3