[rubygems/rubygems] Move Webauthn listener thread to WebauthnListener class

https://github.com/rubygems/rubygems/commit/6ec474975e
This commit is contained in:
Jenny Shen 2023-06-30 23:45:27 -04:00 committed by git
parent fce04f9a6c
commit 24913e3dda
7 changed files with 39 additions and 24 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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