diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index a60999386..97ce9b953 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7154,6 +7154,17 @@ Value help/index.html + WebProfileURL + + Comment + URL for Web Profiles + Persist + 0 + Type + String + Value + https://my.secondlife.com/[AGENT_NAME] + HighResSnapshot Comment diff --git a/indra/newview/llfloateravatarinfo.cpp b/indra/newview/llfloateravatarinfo.cpp index d3fc5596d..f60e24623 100644 --- a/indra/newview/llfloateravatarinfo.cpp +++ b/indra/newview/llfloateravatarinfo.cpp @@ -42,6 +42,7 @@ #include "llcommandhandler.h" #include "llpanelavatar.h" #include "lluictrlfactory.h" +#include "llweb.h" // linden library includes #include "llinventory.h" @@ -293,3 +294,13 @@ LLPreview::EAssetStatus LLFloaterAvatarInfo::getAssetStatus() } return mAssetStatus; } + +std::string getProfileURL(const std::string& agent_name) +{ + std::string url = gSavedSettings.getString("WebProfileURL"); + LLSD subs; + subs["AGENT_NAME"] = agent_name; + url = LLWeb::expandURLSubstitutions(url,subs); + LLStringUtil::toLower(url); + return url; +} diff --git a/indra/newview/llfloateravatarinfo.h b/indra/newview/llfloateravatarinfo.h index 9d78e18ec..6e608e9e4 100644 --- a/indra/newview/llfloateravatarinfo.h +++ b/indra/newview/llfloateravatarinfo.h @@ -101,5 +101,6 @@ private: EOnlineStatus mSuggestedOnlineStatus; }; +std::string getProfileURL(const std::string& agent_name); #endif diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 08a260871..10e21ad92 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -4306,7 +4306,6 @@ bool process_login_success_response(std::string& password) #endif } - // Override grid info with anything sent in the login response std::string tmp = response["gridname"].asString(); if (!tmp.empty()) gHippoGridManager->getConnectedGrid()->setGridName(tmp); @@ -4351,6 +4350,14 @@ bool process_login_success_response(std::string& password) gHippoGridManager->saveFile(); gHippoLimits->setLimits(); + // Start the process of fetching the OpenID session cookie for this user login + std::string openid_url = response["openid_url"]; + if(!openid_url.empty()) + { + std::string openid_token = response["openid_token"]; + LLViewerMedia::openIDSetup(openid_url, openid_token); + } + gIMMgr->loadIgnoreGroup(); bool success = false; diff --git a/indra/newview/llurl.cpp b/indra/newview/llurl.cpp index ab65ead4c..83a5839a9 100644 --- a/indra/newview/llurl.cpp +++ b/indra/newview/llurl.cpp @@ -286,5 +286,11 @@ const char * LLURL::getFullPath() return(sReturnString); } +const char * LLURL::getAuthority() +{ + strncpy(LLURL::sReturnString,mAuthority, LL_MAX_PATH -1); /* Flawfinder: ignore */ + LLURL::sReturnString[LL_MAX_PATH -1] = '\0'; + return(sReturnString); +} char LLURL::sReturnString[LL_MAX_PATH] = ""; diff --git a/indra/newview/llurl.h b/indra/newview/llurl.h index 9a089dd83..e41b83d29 100644 --- a/indra/newview/llurl.h +++ b/indra/newview/llurl.h @@ -79,6 +79,7 @@ public: virtual const char *getFQURL() const; virtual const char *getFullPath(); + virtual const char *getAuthority(); virtual const char *updateRelativePath(const LLURL &url); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index c76b4b335..508dc1f5a 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -55,6 +55,7 @@ #include "llvieweraudio.h" #include "llweb.h" +#include "llfloateravatarinfo.h" // for getProfileURL() function //#include "viewerversion.h" // Merov: Temporary definitions while porting the new viewer media code to Snowglobe @@ -83,11 +84,6 @@ public: completeAny(status, mime_type); } - virtual void error( U32 status, const std::string& reason ) - { - // completeAny(status, "none/none"); - } - void completeAny(U32 status, const std::string& mime_type) { if(!mInitialized && ! mime_type.empty()) @@ -104,9 +100,81 @@ public: viewer_media_t mMediaImpl; bool mInitialized; }; + +class LLViewerMediaOpenIDResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLViewerMediaOpenIDResponder); +public: + LLViewerMediaOpenIDResponder( ) + { + } + + ~LLViewerMediaOpenIDResponder() + { + } + + /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + LL_DEBUGS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + LL_DEBUGS("MediaAuth") << content << LL_ENDL; + std::string cookie = content["set-cookie"].asString(); + + LLViewerMedia::openIDCookieResponse(cookie); + } + + /* virtual */ void completedRaw( + U32 status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + // This is just here to disable the default behavior (attempting to parse the response as llsd). + // We don't care about the content of the response, only the set-cookie header. + } + +}; + +class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLViewerMediaWebProfileResponder); +public: + LLViewerMediaWebProfileResponder(std::string host) + { + mHost = host; + } + + ~LLViewerMediaWebProfileResponder() + { + } + + /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL; + LL_WARNS("MediaAuth") << content << LL_ENDL; + + std::string cookie = content["set-cookie"].asString(); + + LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost); + } + + void completedRaw( + U32 status, + const std::string& reason, + const LLChannelDescriptors& channels, + const LLIOPipe::buffer_ptr_t& buffer) + { + // This is just here to disable the default behavior (attempting to parse the response as llsd). + // We don't care about the content of the response, only the set-cookie header. + } + + std::string mHost; +}; + +LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; +LLURL LLViewerMedia::sOpenIDURL; +std::string LLViewerMedia::sOpenIDCookie; typedef std::list impl_list; static impl_list sViewerMediaImplList; -LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL; static std::string sUpdatedCookies; static const char *PLUGIN_COOKIE_FILE_NAME = "plugin_cookies.txt"; @@ -370,6 +438,9 @@ void LLViewerMedia::clearAllCookies() LLFile::remove(target); } } + + // If we have an OpenID cookie, re-add it to the cookie store. + setOpenIDCookie(); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -453,6 +524,9 @@ void LLViewerMedia::loadCookieFile() plugin->clear_cookies(); } } + + // If we have an OpenID cookie, re-add it to the cookie store. + setOpenIDCookie(); } @@ -523,6 +597,112 @@ void LLViewerMedia::removeCookie(const std::string &name, const std::string &dom addCookie(name, "", domain, LLDate(LLDate::now().secondsSinceEpoch() - 1.0), path); } + + +LLSD LLViewerMedia::getHeaders() +{ + LLSD headers = LLSD::emptyMap(); + headers["Accept"] = "*/*"; + headers["Content-Type"] = "application/xml"; + headers["Cookie"] = sOpenIDCookie; + headers["User-Agent"] = getCurrentUserAgent(); + + return headers; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::setOpenIDCookie() +{ + if(!sOpenIDCookie.empty()) + { + // The LLURL can give me the 'authority', which is of the form: [username[:password]@]hostname[:port] + // We want just the hostname for the cookie code, but LLURL doesn't seem to have a way to extract that. + // We therefore do it here. + std::string authority = sOpenIDURL.mAuthority; + std::string::size_type host_start = authority.find('@'); + if(host_start == std::string::npos) + { + // no username/password + host_start = 0; + } + else + { + // Hostname starts after the @. + // (If the hostname part is empty, this may put host_start at the end of the string. In that case, it will end up passing through an empty hostname, which is correct.) + ++host_start; + } + std::string::size_type host_end = authority.rfind(':'); + if((host_end == std::string::npos) || (host_end < host_start)) + { + // no port + host_end = authority.size(); + } + + getCookieStore()->setCookiesFromHost(sOpenIDCookie, authority.substr(host_start, host_end - host_start)); + + // Do a web profile get so we can store the cookie + LLSD headers = LLSD::emptyMap(); + headers["Accept"] = "*/*"; + headers["Cookie"] = sOpenIDCookie; + headers["User-Agent"] = getCurrentUserAgent(); + + std::string profile_url = getProfileURL(""); + LLURL raw_profile_url( profile_url.c_str() ); + + LL_DEBUGS("MediaAuth") << "Requesting " << profile_url << llendl; + LL_DEBUGS("MediaAuth") << "sOpenIDCookie = [" << sOpenIDCookie << "]" << llendl; + LLHTTPClient::get(profile_url, + new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()), + headers); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::openIDSetup(const std::string &openid_url, const std::string &openid_token) +{ + LL_DEBUGS("MediaAuth") << "url = \"" << openid_url << "\", token = \"" << openid_token << "\"" << LL_ENDL; + + // post the token to the url + // the responder will need to extract the cookie(s). + + // Save the OpenID URL for later -- we may need the host when adding the cookie. + sOpenIDURL.init(openid_url.c_str()); + + // We shouldn't ever do this twice, but just in case this code gets repurposed later, clear existing cookies. + sOpenIDCookie.clear(); + + LLSD headers = LLSD::emptyMap(); + // Keep LLHTTPClient from adding an "Accept: application/llsd+xml" header + headers["Accept"] = "*/*"; + // and use the expected content-type for a post, instead of the LLHTTPClient::postRaw() default of "application/octet-stream" + headers["Content-Type"] = "application/x-www-form-urlencoded"; + + // postRaw() takes ownership of the buffer and releases it later, so we need to allocate a new buffer here. + size_t size = openid_token.size(); + U8 *data = new U8[size]; + memcpy(data, openid_token.data(), size); + + LLHTTPClient::postRaw( + openid_url, + data, + size, + new LLViewerMediaOpenIDResponder(), + headers); + +} + +///////////////////////////////////////////////////////////////////////////////////////// +// static +void LLViewerMedia::openIDCookieResponse(const std::string &cookie) +{ + LL_DEBUGS("MediaAuth") << "Cookie received: \"" << cookie << "\"" << LL_ENDL; + + sOpenIDCookie += cookie; + + setOpenIDCookie(); +} ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerMedia::cleanupClass() diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 5e4f49489..ada13304c 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -92,8 +92,17 @@ class LLViewerMedia static void addSessionCookie(const std::string &name, const std::string &value, const std::string &domain, const std::string &path = std::string("/"), bool secure = false ); static void removeCookie(const std::string &name, const std::string &domain, const std::string &path = std::string("/") ); + static void openIDSetup(const std::string &openid_url, const std::string &openid_token); + static void openIDCookieResponse(const std::string &cookie); + + static LLSD getHeaders(); + private: + static void setOpenIDCookie(); + static LLPluginCookieStore *sCookieStore; + static LLURL sOpenIDURL; + static std::string sOpenIDCookie; }; // Implementation functions not exported into header file @@ -104,7 +113,6 @@ class LLViewerMediaImpl public: friend class LLViewerMedia; - friend class LLMimeDiscoveryResponder; LLViewerMediaImpl(const std::string& media_url, const LLUUID& texture_id, @@ -123,9 +131,6 @@ public: LLPluginClassMedia* getMediaPlugin() const { return (LLPluginClassMedia*)mPluginBase; } void setSize(int width, int height); - // Inherited from LLViewerPluginManager. - /*virtual*/ void update(); - void play(); void stop(); void pause(); @@ -155,6 +160,7 @@ public: void scaleMouse(S32 *mouse_x, S32 *mouse_y); void updateMovieImage(const LLUUID& image_id, BOOL active); + void update(); void updateImagesMediaStreams(); LLUUID getMediaTextureID(); diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index 28bfe034a..4dbcfc578 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -35,11 +35,20 @@ #include "llweb.h" -#include "llviewerwindow.h" -#include "llwindow.h" +// Library includes +#include "llwindow.h" // spawnWebBrowser() -#include "llviewercontrol.h" +#include "llagent.h" +#include "llappviewer.h" #include "llfloatermediabrowser.h" +#include "llparcel.h" +#include "llviewercontrol.h" +#include "llviewernetwork.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" + +#include "sgversion.h" // static void LLWeb::initClass() @@ -125,6 +134,64 @@ std::string LLWeb::escapeURL(const std::string& url) return escaped_url; } +//static +std::string LLWeb::expandURLSubstitutions(const std::string &url, + const LLSD &default_subs) +{ + gCurrentVersion = llformat("%s %d.%d.%d.%d", + gVersionChannel, + gVersionMajor, + gVersionMinor, + gVersionPatch, + gVersionBuild ); + + LLSD substitution = default_subs; + substitution["VERSION"] = gCurrentVersion; + substitution["VERSION_MAJOR"] = gVersionMajor; + substitution["VERSION_MINOR"] = gVersionMinor; + substitution["VERSION_PATCH"] = gVersionPatch; + substitution["VERSION_BUILD"] = gVersionBuild; + substitution["CHANNEL"] = gVersionChannel; + substitution["GRID"] = LLViewerLogin::getInstance()->getGridLabel(); + substitution["OS"] = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); + substitution["SESSION_ID"] = gAgent.getSessionID(); + substitution["FIRST_LOGIN"] = gAgent.isFirstLogin(); + + // work out the current language + std::string lang = LLUI::getLanguage(); + if (lang == "en-us") + { + // *HACK: the correct fix is to change English.lproj/language.txt, + // but we're late in the release cycle and this is a less risky fix + lang = "en"; + } + substitution["LANGUAGE"] = lang; + + // find the region ID + LLUUID region_id; + LLViewerRegion *region = gAgent.getRegion(); + if (region) + { + region_id = region->getRegionID(); + } + substitution["REGION_ID"] = region_id; + + // find the parcel local ID + S32 parcel_id = 0; + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (parcel) + { + parcel_id = parcel->getLocalID(); + } + substitution["PARCEL_ID"] = llformat("%d", parcel_id); + + // expand all of the substitution strings and escape the url + std::string expanded_url = url; + LLStringUtil::format(expanded_url, substitution); + + return LLWeb::escapeURL(expanded_url); +} + // virtual void LLWeb::URLLoader::load(const std::string& url) { diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h index 8dd13ffcb..73f5c7ebe 100644 --- a/indra/newview/llweb.h +++ b/indra/newview/llweb.h @@ -57,6 +57,10 @@ public: // Returns escaped (eg, " " to "%20") url static std::string escapeURL(const std::string& url); + /// Expands various strings like [LANG], [VERSION], etc. in a URL + static std::string expandURLSubstitutions(const std::string &url, + const LLSD &default_subs); + class URLLoader : public LLAlertDialog::URLLoader { virtual void load(const std::string& url);