From 625b19692670172b2989cb35a4b4b44872ca9c79 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Wed, 7 Nov 2012 15:37:20 -0300 Subject: [PATCH] Handle login failures and disconnections --- em-msn.gemspec | 1 + lib/em-msn.rb | 1 + lib/msn/authentication_error.rb | 2 ++ lib/msn/messenger.rb | 32 ++++++++++++++++++++++++-------- lib/msn/nexus.rb | 9 +++++++++ lib/msn/notification_server.rb | 25 ++++++++++++++++--------- 6 files changed, 53 insertions(+), 17 deletions(-) create mode 100644 lib/msn/authentication_error.rb diff --git a/em-msn.gemspec b/em-msn.gemspec index b3b1c6e..8ff8d63 100644 --- a/em-msn.gemspec +++ b/em-msn.gemspec @@ -14,6 +14,7 @@ Gem::Specification.new do |s| s.files = [ "lib/em-msn.rb", + "lib/msn/authentication_error.rb", "lib/msn/message.rb", "lib/msn/contact.rb", "lib/msn/nexus.rb", diff --git a/lib/em-msn.rb b/lib/em-msn.rb index 0e31f88..d8cc4dc 100644 --- a/lib/em-msn.rb +++ b/lib/em-msn.rb @@ -14,6 +14,7 @@ module Msn require "nokogiri" require 'rexml/text' +require_relative 'msn/authentication_error' require_relative 'msn/protocol' require_relative 'msn/message' require_relative 'msn/contact' diff --git a/lib/msn/authentication_error.rb b/lib/msn/authentication_error.rb new file mode 100644 index 0000000..8adc488 --- /dev/null +++ b/lib/msn/authentication_error.rb @@ -0,0 +1,2 @@ +class Msn::AuthenticationError < StandardError +end \ No newline at end of file diff --git a/lib/msn/messenger.rb b/lib/msn/messenger.rb index 98a09d6..016f28e 100644 --- a/lib/msn/messenger.rb +++ b/lib/msn/messenger.rb @@ -61,6 +61,14 @@ def on_ready(&handler) @on_ready_handler = handler end + def on_login_failed(&handler) + @on_login_failed = handler + end + + def on_disconnect(&handler) + @on_disconnect = handler + end + def on_message(&handler) @on_message_handler = handler end @@ -74,20 +82,28 @@ def send_message(email, text) end def accept_message(message) - if @on_message_handler - Fiber.new { @on_message_handler.call(message) }.resume - end + call_handler @on_message_handler, message end def contact_request(email, display_name) - if @on_contact_request - Fiber.new { @on_contact_request.call(email, display_name) }.resume - end + call_handler @on_contact_request, email, display_name end def ready - if @on_ready_handler - Fiber.new { @on_ready_handler.call }.resume + call_handler @on_ready_handler + end + + def login_failed(message) + call_handler @on_login_failed, message + end + + def disconnected + call_handler @on_disconnect + end + + def call_handler(handler, *args) + if handler + Fiber.new { handler.call(*args) }.resume end end diff --git a/lib/msn/nexus.rb b/lib/msn/nexus.rb index 653dcc5..fb053f6 100644 --- a/lib/msn/nexus.rb +++ b/lib/msn/nexus.rb @@ -8,6 +8,7 @@ class Msn::Nexus "wst" => "http://schemas.xmlsoap.org/ws/2004/04/trust", "wsp" => "http://schemas.xmlsoap.org/ws/2002/12/policy", "wsa" => "http://schemas.xmlsoap.org/ws/2004/03/addressing", + "S" => "http://schemas.xmlsoap.org/soap/envelope/", } def initialize(messenger, policy, nonce) @@ -36,6 +37,7 @@ def fetch_data @fetched_data = true @sso_token, secret, @ticket_token = get_binary_secret messenger.username, messenger.password + @secret = compute_return_value secret end @@ -45,8 +47,15 @@ def get_binary_secret(username, password) soap = msn_sso_template.result(binding) response = RestClient.post "https://login.live.com/RST.srf", soap + xml = Nokogiri::XML(response) + # Check invalid login + fault = xml.xpath("//S:Fault/faultstring") + if fault + raise Msn::AuthenticationError.new(fault.text) + end + rstr = xml.xpath "//wst:RequestSecurityTokenResponse[wsp:AppliesTo/wsa:EndpointReference/wsa:Address='messengerclear.live.com']", Namespaces token = rstr.xpath("wst:RequestedSecurityToken/wsse:BinarySecurityToken[@Id='Compact1']", Namespaces).first.text secret = rstr.xpath("wst:RequestedProofToken/wst:BinarySecret", Namespaces).first.text diff --git a/lib/msn/notification_server.rb b/lib/msn/notification_server.rb index 5b16ff4..94f75ef 100644 --- a/lib/msn/notification_server.rb +++ b/lib/msn/notification_server.rb @@ -94,15 +94,20 @@ def post_init def login Fiber.new do - ver "MSNP18", "CVR0" - cvr "0x0409", "winnt", "5.1", "i386", "MSNMSGR", "8.5.1302", "BC01", username - response = usr "SSO", "I", username - if response[0] == "XFR" && response[2] == "NS" - host, port = response[3].split ':' - @reconnect_host, @reconnect_port = response[3].split ':' + begin + ver "MSNP18", "CVR0" + cvr "0x0409", "winnt", "5.1", "i386", "MSNMSGR", "8.5.1302", "BC01", username + response = usr "SSO", "I", username + if response[0] == "XFR" && response[2] == "NS" + host, port = response[3].split ':' + @reconnect_host, @reconnect_port = response[3].split ':' + close_connection + else + login_to_nexus(response[4], response[5]) + end + rescue Msn::AuthenticationError => ex + messenger.login_failed(ex.message) close_connection - else - login_to_nexus(response[4], response[5]) end end.resume end @@ -125,7 +130,7 @@ def login_to_nexus(policy, nonce) response = usr "SSO", "S", @nexus.sso_token, @nexus.secret, guid if response[2] != "OK" - raise "Login failed (3)" + raise Msn::AuthenticationError.new("Didn't receive OK from SSO") end end @@ -148,6 +153,8 @@ def unbind reconnect @reconnect_host, @reconnect_port.to_i @reconnect_host = @reconnect_port = nil login + else + messenger.disconnected end end end