spec/fetcher_spec.rb in lastpass-1.0.1 vs spec/fetcher_spec.rb in lastpass-1.1.0

- old
+ new

@@ -5,16 +5,32 @@ describe LastPass::Fetcher do let(:username) { "username" } let(:password) { "password" } let(:key_iteration_count) { 5000 } + + let(:hash) { "7880a04588cfab954aa1a2da98fd9c0d2c6eba4c53e36a94510e6dbf30759256" } let(:session_id) { "53ru,Hb713QnEVM5zWZ16jMvxS0" } let(:session) { LastPass::Session.new session_id, key_iteration_count } + let(:blob_response) { "TFBBVgAAAAMxMjJQUkVNAAAACjE0MTQ5" } let(:blob_bytes) { blob_response.decode64 } let(:blob) { LastPass::Blob.new blob_bytes, key_iteration_count } + let(:login_post_data) { {method: "mobile", + web: 1, + xml: 1, + username: username, + hash: hash, + iterations: key_iteration_count} } + + let(:google_authenticator_code) { "123456" } + let(:yubikey_password) { "emdbwzemyisymdnevznyqhqnklaqheaxszzvtnxjrmkb" } + + let(:login_post_data_with_google_authenticator_code) { login_post_data.merge({otp: google_authenticator_code})} + let(:login_post_data_with_yubikey_password) { login_post_data.merge({otp: yubikey_password}) } + describe ".request_iteration_count" do it "makes a POST request" do expect(web_client = double("web_client")).to receive(:post) .with("https://lastpass.com/iterations.php", query: {email: username}) .and_return(http_ok(key_iteration_count.to_s)) @@ -38,74 +54,111 @@ it "raises an exception on invalid key iteration count" do expect { LastPass::Fetcher.request_iteration_count username, double("web_client", post: http_ok("not a number")) - }.to raise_error LastPass::InvalidResponse, "Key iteration count is invalid" + }.to raise_error LastPass::InvalidResponseError, "Key iteration count is invalid" end it "raises an exception on zero key iteration count" do expect { LastPass::Fetcher.request_iteration_count username, double("web_client", post: http_ok("0")) - }.to raise_error LastPass::InvalidResponse, "Key iteration count is not positive" + }.to raise_error LastPass::InvalidResponseError, "Key iteration count is not positive" end it "raises an exception on negative key iteration count" do expect { LastPass::Fetcher.request_iteration_count username, double("web_client", post: http_ok("-1")) - }.to raise_error LastPass::InvalidResponse, "Key iteration count is not positive" + }.to raise_error LastPass::InvalidResponseError, "Key iteration count is not positive" end end describe ".request_login" do - it "makes a POST request" do - expect(web_client = double("web_client")).to receive(:post) - .with("https://lastpass.com/login.php", format: :xml, body: anything) + def verify_post_request multifactor_password, post_data + web_client = double("web_client") + expect(web_client).to receive(:post) + .with("https://lastpass.com/login.php", format: :xml, body: post_data) .and_return(http_ok("ok" => {"sessionid" => session_id})) - LastPass::Fetcher.request_login username, password, key_iteration_count, web_client + LastPass::Fetcher.request_login username, + password, + key_iteration_count, + multifactor_password, + web_client end + it "makes a POST request" do + verify_post_request nil, login_post_data + end + + it "makes a POST request with Google Authenticator code" do + verify_post_request google_authenticator_code, login_post_data_with_google_authenticator_code + end + + it "makes a POST request with Yubikey password" do + verify_post_request yubikey_password, login_post_data_with_yubikey_password + end + it "returns a session" do expect(request_login_with_xml "<ok sessionid='#{session_id}' />").to eq session end it "raises an exception on HTTP error" do expect { request_login_with_error }.to raise_error LastPass::NetworkError end it "raises an exception when response is not a hash" do - expect { request_login_with_ok "not a hash" }.to raise_error LastPass::InvalidResponse + expect { request_login_with_ok "not a hash" }.to raise_error LastPass::InvalidResponseError end it "raises an exception on unknown response schema" do - expect { request_login_with_xml "<unknown />" }.to raise_error LastPass::UnknownResponseSchema + expect { request_login_with_xml "<unknown />" }.to raise_error LastPass::UnknownResponseSchemaError end it "raises an exception on unknown response schema" do - expect { request_login_with_xml "<response />" }.to raise_error LastPass::UnknownResponseSchema + expect { request_login_with_xml "<response />" }.to raise_error LastPass::UnknownResponseSchemaError end it "raises an exception on unknown response schema" do expect { request_login_with_xml "<response><error /></response>" } - .to raise_error LastPass::UnknownResponseSchema + .to raise_error LastPass::UnknownResponseSchemaError end it "raises an exception on unknown username" do message = "Unknown email address." expect { request_login_with_lastpass_error "unknownemail", message } - .to raise_error LastPass::LastPassUnknownUsername, message + .to raise_error LastPass::LastPassUnknownUsernameError, message end it "raises an exception on invalid password" do message = "Invalid password!" expect { request_login_with_lastpass_error "unknownpassword", message } - .to raise_error LastPass::LastPassInvalidPassword, message + .to raise_error LastPass::LastPassInvalidPasswordError, message end + it "raises an exception on missing Google Authenticator code" do + message = "Google Authenticator authentication required! " + + "Upgrade your browser extension so you can enter it." + expect { request_login_with_lastpass_error "googleauthrequired", message } + .to raise_error LastPass::LastPassIncorrectGoogleAuthenticatorCodeError, message + end + + it "raises an exception on incorrect Google Authenticator code" do + message = "Google Authenticator authentication failed!" + expect { request_login_with_lastpass_error "googleauthfailed", message } + .to raise_error LastPass::LastPassIncorrectGoogleAuthenticatorCodeError, message + end + + it "raises an exception on missing/incorrect Yubikey password" do + message = "Your account settings have restricted you from logging in " + + "from mobile devices that do not support YubiKey authentication." + expect { request_login_with_lastpass_error "yubikeyrestricted", message } + .to raise_error LastPass::LastPassIncorrectYubikeyPasswordError, message + end + it "raises an exception on unknown LastPass error with a message" do message = "Unknow error message" expect { request_login_with_lastpass_error "Unknown cause", message } .to raise_error LastPass::LastPassUnknownError, message end @@ -118,11 +171,11 @@ end describe ".fetch" do it "makes a GET request" do expect(web_client = double("web_client")).to receive(:get) - .with("https://lastpass.com/getaccts.php?mobile=1&b64=1&hash=0.0", + .with("https://lastpass.com/getaccts.php?mobile=1&b64=1&hash=0.0&hasplugin=3.0.23&requestsrc=android", format: :plain, cookies: {"PHPSESSID" => session_id}) .and_return(http_ok(blob_response)) LastPass::Fetcher.fetch session, web_client @@ -221,8 +274,9 @@ def request_login_with_response response LastPass::Fetcher.request_login username, password, key_iteration_count, + nil, double("web_client", post: response) end end