Class: Gem::GemcutterUtilities::WebauthnListener

Inherits:
Object
  • Object
show all
Defined in:
lib/rubygems/gemcutter_utilities/webauthn_listener.rb,
lib/rubygems/gemcutter_utilities/webauthn_listener/response.rb

Defined Under Namespace

Classes: BadRequestResponse, MethodNotAllowedResponse, NoContentResponse, NotFoundResponse, OkResponse, Response, SocketResponder

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host) ⇒ WebauthnListener

Returns a new instance of WebauthnListener.



31
32
33
# File 'lib/rubygems/gemcutter_utilities/webauthn_listener.rb', line 31

def initialize(host)
  @host = host
end

Instance Attribute Details

#hostObject (readonly)

Returns the value of attribute host.



29
30
31
# File 'lib/rubygems/gemcutter_utilities/webauthn_listener.rb', line 29

def host
  @host
end

Class Method Details

.listener_thread(host, server) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/rubygems/gemcutter_utilities/webauthn_listener.rb', line 35

def self.listener_thread(host, server)
  Thread.new do
    thread = Thread.current
    thread.abort_on_exception = true
    thread.report_on_exception = false
    thread[:otp] = new(host).wait_for_otp_code(server)
  rescue Gem::WebauthnVerificationError => e
    thread[:error] = e
  ensure
    server.close
  end
end

Instance Method Details

#wait_for_otp_code(server) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/rubygems/gemcutter_utilities/webauthn_listener.rb', line 48

def wait_for_otp_code(server)
  loop do
    socket = server.accept
    request_line = socket.gets

    method, req_uri, _protocol = request_line.split(" ")
    req_uri = URI.parse(req_uri)

    responder = SocketResponder.new(socket)

    unless root_path?(req_uri)
      responder.send(NotFoundResponse.for(host))
      raise Gem::WebauthnVerificationError, "Page at #{req_uri.path} not found."
    end

    case method.upcase
    when "OPTIONS"
      responder.send(NoContentResponse.for(host))
      next # will be GET
    when "GET"
      if otp = parse_otp_from_uri(req_uri)
        responder.send(OkResponse.for(host))
        return otp
      end
      responder.send(BadRequestResponse.for(host))
      raise Gem::WebauthnVerificationError, "Did not receive OTP from #{host}."
    else
      responder.send(MethodNotAllowedResponse.for(host))
      raise Gem::WebauthnVerificationError, "Invalid HTTP method #{method.upcase} received."
    end
  end
end