/** * @file exoflickrauth.cpp * @brief Handles all Flickr authentication issues * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (C) 2012 Katharine Berry * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "fscorehttputil.h" #include "llwindow.h" #include "llviewerwindow.h" #include "llbufferstream.h" #include "lluri.h" #include "llviewercontrol.h" #include "llnotificationsutil.h" #include "exoflickr.h" #include "llcorehttputil.h" #include "exoflickrauth.h" bool exoFlickrAuth::sAuthorisationInProgress = false; void exoFlickrAuthResponse( LLSD const &aData, exoFlickrAuth::authorized_callback_t aCallback ) { LLSD header = aData[ LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS ][ LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_HEADERS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD( aData[ LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS ] ); const LLSD::Binary &rawData = aData[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS_RAW].asBinary(); std::string result; result.assign( rawData.begin(), rawData.end() ); LLSD resultLLSD = LLURI::queryMap( result ); aCallback((status.getType() == HTTP_OK), resultLLSD); } exoFlickrAuth::exoFlickrAuth(authorized_callback_t callback) : mCallback(callback) { // Avoid doubled authentication attempts. if(sAuthorisationInProgress) { delete this; return; } mAuthenticating = true; sAuthorisationInProgress = true; if(gSavedPerAccountSettings.getString("ExodusFlickrToken").empty() || gSavedPerAccountSettings.getString("ExodusFlickrTokenSecret").empty()) { beginAuthorisation(); } else { checkAuthorisation(); } } exoFlickrAuth::~exoFlickrAuth() { if(mAuthenticating) { sAuthorisationInProgress = false; } } void exoFlickrAuth::checkAuthorisation() { exoFlickr::request("flickr.test.login", LLSD(), boost::bind(&exoFlickrAuth::checkResult, this, _1, _2)); } void exoFlickrAuth::checkResult(bool success, const LLSD &response) { if(!success) { LL_WARNS("Flickr") << "Login test failed (HTTP). Reauthenticating." << LL_ENDL; beginAuthorisation(); } else { if(response["stat"].asString() != "ok") { LL_WARNS("Flickr") << "Login test failed: " << response["message"] << "(" << response["code"] << "). Reauthenticating." << LL_ENDL; beginAuthorisation(); } else { LL_INFOS("Flickr") << "Stored Flickr tokens are valid." << LL_ENDL; mCallback(true, LLSD()); delete this; return; } } } void exoFlickrAuth::beginAuthorisation() { // Explain and confirm the process to the user. LLNotificationsUtil::add("ExodusFlickrVerificationExplanation", LLSD(), LLSD(), boost::bind(&exoFlickrAuth::explanationCallback, this, _1, _2)); } void exoFlickrAuth::explanationCallback(const LLSD& notification, const LLSD& response) { int option = LLNotificationsUtil::getSelectedOption(notification, response); if(option == 0) // OK { // Clear out any old authentication tokens gSavedPerAccountSettings.setString("ExodusFlickrToken", ""); gSavedPerAccountSettings.setString("ExodusFlickrTokenSecret",""); // Initiate authentication step one. LLSD params; params["oauth_callback"] = "oob"; LL_INFOS("Flickr") << "Initialising OAuth authorisation process." << LL_ENDL; exoFlickr::signRequest(params, "GET", "https://www.flickr.com/services/oauth/request_token"); std::string url = LLURI::buildHTTP( "https://www.flickr.com/services/oauth/request_token", LLSD::emptyArray(), params ).asString(); exoFlickrAuth::authorized_callback_t callback = boost::bind(&exoFlickrAuth::gotRequestToken, this, _1, _2); FSCoreHttpUtil::callbackHttpGetRaw( url, boost::bind( exoFlickrAuthResponse, _1, callback ) ); } else { mCallback(false, LLSD()); delete this; return; } } void exoFlickrAuth::gotRequestToken(bool success, const LLSD& params) { LL_INFOS("Flickr") << "Got request token, success = " << success << LL_ENDL; if(!success) { mCallback(false, LLSD()); delete this; return; } std::string token = params["oauth_token"].asString(); std::string secret = params["oauth_token_secret"].asString(); gSavedPerAccountSettings.setString("ExodusFlickrToken", token); gSavedPerAccountSettings.setString("ExodusFlickrTokenSecret", secret); LL_INFOS("Flickr") << "Token = '" << token << "', secret = '" << secret << "'" << LL_ENDL; // Proceed with stage two. // We spawn the browser using spawnWebBrowser instead of LLWeb to bypass the // browser prompt. This would a) be redundant to our earlier notice, and b) // is unclickable because we have also presented a modal dialog. gViewerWindow->getWindow()->spawnWebBrowser("https://www.flickr.com/services/oauth/authorize?perms=write&oauth_token=" + token, true); LLNotificationsUtil::add("ExodusFlickrVerificationPrompt", LLSD(), LLSD(), boost::bind(&exoFlickrAuth::gotVerifier, this, _1, _2)); } void exoFlickrAuth::gotVerifier(const LLSD& notification, const LLSD& response) { int option = LLNotificationsUtil::getSelectedOption(notification, response); if(option == 1) // Cancel { mCallback(false, LLSD()); delete this; return; } // Proceed with stage three. LLSD params; params["oauth_verifier"] = response["oauth_verifier"]; exoFlickr::signRequest(params, "GET", "https://www.flickr.com/services/oauth/access_token"); std::string url = LLURI::buildHTTP( "https://www.flickr.com/services/oauth/access_token", LLSD::emptyArray(), params ).asString(); exoFlickrAuth::authorized_callback_t callback = boost::bind(&exoFlickrAuth::gotAccessToken, this, _1, _2); FSCoreHttpUtil::callbackHttpGetRaw( url, boost::bind( exoFlickrAuthResponse, _1, callback ) ); } void exoFlickrAuth::gotAccessToken(bool success, const LLSD& params) { if(success) { // Save all the information we got back. gSavedPerAccountSettings.setString("ExodusFlickrToken", params["oauth_token"].asString()); gSavedPerAccountSettings.setString("ExodusFlickrTokenSecret", params["oauth_token_secret"].asString()); gSavedPerAccountSettings.setString("ExodusFlickrFullName", params["fullname"].asString()); gSavedPerAccountSettings.setString("ExodusFlickrNSID", params["user_nsid"].asString()); gSavedPerAccountSettings.setString("ExodusFlickrUsername", params["username"].asString()); mCallback(true, params); } else { LLNotificationsUtil::add("ExodusFlickrVerificationFailed"); mCallback(false, params); } delete this; }