lib/lastpass/fetcher.rb in lastpass-1.0.1 vs lib/lastpass/fetcher.rb in lastpass-1.1.0

- old
+ new

@@ -1,17 +1,17 @@ # Copyright (C) 2013 Dmitry Yakimenko (detunized@gmail.com). # Licensed under the terms of the MIT license. See LICENCE for details. module LastPass class Fetcher - def self.login username, password + def self.login username, password, multifactor_password = nil key_iteration_count = request_iteration_count username - request_login username, password, key_iteration_count + request_login username, password, key_iteration_count, multifactor_password end def self.fetch session, web_client = HTTParty - response = web_client.get "https://lastpass.com/getaccts.php?mobile=1&b64=1&hash=0.0", + response = web_client.get "https://lastpass.com/getaccts.php?mobile=1&b64=1&hash=0.0&hasplugin=3.0.23&requestsrc=android", format: :plain, cookies: {"PHPSESSID" => URI.encode(session.id)} raise NetworkError unless response.response.is_a? Net::HTTPOK @@ -25,34 +25,43 @@ raise NetworkError unless response.response.is_a? Net::HTTPOK begin count = Integer response.parsed_response rescue ArgumentError - raise InvalidResponse, "Key iteration count is invalid" + raise InvalidResponseError, "Key iteration count is invalid" end - raise InvalidResponse, "Key iteration count is not positive" unless count > 0 + raise InvalidResponseError, "Key iteration count is not positive" unless count > 0 count end - def self.request_login username, password, key_iteration_count, web_client = HTTParty + def self.request_login username, + password, + key_iteration_count, + multifactor_password = nil, + web_client = HTTParty + + body = { + method: "mobile", + web: 1, + xml: 1, + username: username, + hash: make_hash(username, password, key_iteration_count), + iterations: key_iteration_count + } + + body[:otp] = multifactor_password if multifactor_password + response = web_client.post "https://lastpass.com/login.php", format: :xml, - body: { - method: "mobile", - web: 1, - xml: 1, - username: username, - hash: make_hash(username, password, key_iteration_count), - iterations: key_iteration_count - } + body: body raise NetworkError unless response.response.is_a? Net::HTTPOK parsed_response = response.parsed_response - raise InvalidResponse unless parsed_response.is_a? Hash + raise InvalidResponseError unless parsed_response.is_a? Hash create_session parsed_response, key_iteration_count or raise login_error parsed_response end @@ -68,23 +77,26 @@ nil end def self.login_error parsed_response error = (parsed_response["response"] || {})["error"] - return UnknownResponseSchema unless error.is_a? Hash + return UnknownResponseSchemaError unless error.is_a? Hash exceptions = { - "unknownemail" => LastPassUnknownUsername, - "unknownpassword" => LastPassInvalidPassword, + "unknownemail" => LastPassUnknownUsernameError, + "unknownpassword" => LastPassInvalidPasswordError, + "googleauthrequired" => LastPassIncorrectGoogleAuthenticatorCodeError, + "googleauthfailed" => LastPassIncorrectGoogleAuthenticatorCodeError, + "yubikeyrestricted" => LastPassIncorrectYubikeyPasswordError, } cause = error["cause"] message = error["message"] if cause (exceptions[cause] || LastPassUnknownError).new message || cause else - InvalidResponse.new message + InvalidResponseError.new message end end def self.decode_blob blob # TODO: Check for invalid base64