diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7d495ceae5..31f1985309 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -13083,7 +13083,7 @@ Change of this parameter will affect the layout of buttons in notification toast
Persist
1
Type
- LLSD
+ String
Value
diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp
index 9b4f146332..8975e30cc6 100644
--- a/indra/newview/llloginhandler.cpp
+++ b/indra/newview/llloginhandler.cpp
@@ -148,56 +148,4 @@ bool LLLoginHandler::handle(const LLSD& tokens,
LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
}
return true;
-}
-
-
-
-// Initialize the credentials
-// If the passed in URL contains login info, parse
-// that into a credential and web login key. Otherwise
-// check the command line. If the command line
-// does not contain any login creds, load the last saved
-// ones from the protected credential store.
-// This always returns with a credential structure set in the
-// login handler
-LLPointer LLLoginHandler::initializeLoginInfo()
-{
- LLPointer result = NULL;
- // so try to load it from the UserLoginInfo
- result = loadSavedUserLoginInfo();
- if (result.isNull())
- {
- result = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
- }
-
- return result;
-}
-
-
-LLPointer LLLoginHandler::loadSavedUserLoginInfo()
-{
- // load the saved user login info into a LLCredential.
- // perhaps this should be moved.
- LLSD cmd_line_login = gSavedSettings.getLLSD("UserLoginInfo");
- if (cmd_line_login.size() == 3)
- {
-
- LLMD5 pass((unsigned char*)cmd_line_login[2].asString().c_str());
- char md5pass[33]; /* Flawfinder: ignore */
- pass.hex_digest(md5pass);
- LLSD identifier = LLSD::emptyMap();
- identifier["type"] = "agent";
- identifier["first_name"] = cmd_line_login[0];
- identifier["last_name"] = cmd_line_login[1];
-
- LLSD authenticator = LLSD::emptyMap();
- authenticator["type"] = "hash";
- authenticator["algorithm"] = "md5";
- authenticator["secret"] = md5pass;
- // yuck, we'll fix this with mani's changes.
- gSavedSettings.setBOOL("AutoLogin", TRUE);
- return gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(),
- identifier, authenticator);
- }
- return NULL;
-}
+}
\ No newline at end of file
diff --git a/indra/newview/llloginhandler.h b/indra/newview/llloginhandler.h
index 1f2eacd094..0e1f17c16a 100644
--- a/indra/newview/llloginhandler.h
+++ b/indra/newview/llloginhandler.h
@@ -44,9 +44,6 @@ class LLLoginHandler : public LLCommandHandler
// Web-based login unsupported
//LLUUID getWebLoginKey() const { return mWebLoginKey; }
- LLPointer loadSavedUserLoginInfo();
- LLPointer initializeLoginInfo();
-
private:
void parse(const LLSD& queryMap);
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 0fdd6c426c..fe2ba7324e 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -167,9 +167,14 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect,
LLComboBox* server_choice_combo = sInstance->getChild("server_combo");
server_choice_combo->setCommitCallback(onSelectServer, NULL);
+ LLComboBox* saved_login_choice_combo = sInstance->getChild("saved_logins_combo");
+ saved_login_choice_combo->setCommitCallback(onSelectSavedLogin, NULL);
// server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1));
updateServerCombo();
+ updateSavedLoginsCombo();
+ saved_login_choice_combo->setLabel(gSavedSettings.getString("UserLoginInfo"));
+ childSetAction("delete_saved_login_btn", onClickDelete, this);
childSetAction("connect_btn", onClickConnect, this);
getChild("login")->setDefaultBtn("connect_btn");
@@ -512,7 +517,7 @@ void LLPanelLogin::getFields(LLPointer& credential,
// load the credential so we can pass back the stored password or hash if the user did
// not modify the password field.
- credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
+ credential = gSecAPIHandler->loadCredential(credential_name());
LLSD identifier = LLSD::emptyMap();
LLSD authenticator = LLSD::emptyMap();
@@ -585,7 +590,7 @@ void LLPanelLogin::getFields(LLPointer& credential,
}
}
}
- credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator);
+ credential = gSecAPIHandler->createCredential(credential_name(), identifier, authenticator);
remember = sInstance->getChild("remember_check")->getValue();
}
@@ -880,6 +885,7 @@ void LLPanelLogin::onClickConnect(void *)
}
updateStartSLURL();
std::string username = sInstance->getChild("username_combo")->getValue().asString();
+ gSavedSettings.setString("UserLoginInfo", credential_name());
LLSD blocked = FSData::allowed_login();
if (!blocked.isMap()) //hack for testing for an empty LLSD
@@ -974,6 +980,23 @@ void LLPanelLogin::onClickHelp(void*)
}
}
+//static
+void LLPanelLogin::onClickDelete(void*)
+{
+ if (sInstance)
+ {
+ LLComboBox* saved_logins_combo = sInstance->getChild("saved_logins_combo");
+ std::string credName = saved_logins_combo->getValue().asString();
+ if ( credName == gSavedSettings.getString("UserLoginInfo") )
+ gSavedSettings.getControl("UserLoginInfo")->resetToDefault();
+ LLPointer credential = gSecAPIHandler->loadCredential(credName);
+ gSecAPIHandler->deleteCredential(credential);
+ updateSavedLoginsCombo();
+ saved_logins_combo->selectFirstItem();
+ saved_logins_combo->updateLabel();
+ }
+}
+
// static
void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
{
@@ -997,7 +1020,7 @@ void LLPanelLogin::updateServer()
// for that grid and set them to the UI.
if(sInstance && !sInstance->areCredentialFieldsDirty())
{
- LLPointer credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
+ LLPointer credential = gSecAPIHandler->loadCredential(credential_name());
bool remember = sInstance->getChild("remember_check")->getValue();
sInstance->setFields(credential, remember);
}
@@ -1048,6 +1071,34 @@ void LLPanelLogin::updateServerCombo()
update_grid_help();
}
+void LLPanelLogin::updateSavedLoginsCombo()
+{
+ if (!sInstance)
+ {
+ return;
+ }
+ // We add all of the possible values, sorted, and then add a bar and the current value at the top
+ LLComboBox* saved_logins_combo = sInstance->getChild("saved_logins_combo");
+ saved_logins_combo->removeall();
+
+ std::vector logins = gSecAPIHandler->listCredentials();
+
+ for (std::vector::iterator login_choice = logins.begin();
+ login_choice != logins.end();
+ login_choice++)
+ {
+ saved_logins_combo->add(*login_choice);
+ }
+
+ saved_logins_combo->sortByName();
+
+/* saved_logins_combo->addSeparator(ADD_TOP);
+
+ saved_logins_combo->add(gSavedSettings.getString("UserLoginInfo"));
+
+ saved_logins_combo->selectFirstItem(); */
+}
+
// static
void LLPanelLogin::onSelectServer(LLUICtrl*, void*)
{
@@ -1057,7 +1108,7 @@ void LLPanelLogin::onSelectServer(LLUICtrl*, void*)
LL_INFOS("AppInit") << "onSelectServer" << LL_ENDL;
// The user twiddled with the grid choice ui.
// apply the selection to the grid setting.
- LLPointer credential;
+// LLPointer credential; <- SA: is this ever used?
LLComboBox* combo = sInstance->getChild("server_combo");
LLSD combo_val = combo->getSelectedValue();
@@ -1093,7 +1144,7 @@ void LLPanelLogin::onSelectServer(LLUICtrl*, void*)
//
combo = sInstance->getChild("start_location_combo");
- combo->setCurrentByIndex(1);
+// combo->setCurrentByIndex(1); <- SA: Why???
LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation")));
@@ -1104,6 +1155,61 @@ void LLPanelLogin::onSelectServer(LLUICtrl*, void*)
updateLocationCombo(false);
updateLoginPanelLinks();
}
+
+// static
+void LLPanelLogin::onSelectSavedLogin(LLUICtrl*, void*)
+{
+ // *NOTE: The paramters for this method are ignored.
+ LL_INFOS("AppInit") << "onSelectSavedLogin" << LL_ENDL;
+
+
+ LLComboBox* combo = sInstance->getChild("saved_logins_combo");
+ LLSD combo_val = combo->getSelectedValue();
+ if (combo_val.isUndefined())
+ {
+ combo_val = combo->getValue();
+ }
+ LLPointer credential = gSecAPIHandler->loadCredential(combo_val);
+
+ combo = sInstance->getChild("start_location_combo");
+ LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation")));
+
+ std::string credName = combo_val.asString();
+
+ // if they've selected another grid, we should load the credentials
+ // for that grid and set them to the UI.
+ if(sInstance && !sInstance->areCredentialFieldsDirty())
+ {
+ LLPointer credential = gSecAPIHandler->loadCredential(credName);
+ bool remember = sInstance->getChild("remember_check")->getValue();
+ sInstance->setFields(credential, remember);
+ }
+ U32 arobase = credName.find("@");
+ if (arobase != -1 && arobase +1 < credName.length())
+ credName = credName.substr(arobase+1, credName.length() - arobase - 1);
+//
+ if(LLGridManager::getInstance()->getGrid() == credName)
+ {
+ return;
+ }
+
+ try
+ {
+ LLGridManager::getInstance()->setGridChoice(credName);
+ }
+ catch (LLInvalidGridName ex)
+ {
+ // do nothing
+ }
+//
+ updateServerCombo();
+ // grid changed so show new splash screen (possibly)
+ loadLoginPage();
+ updateLocationCombo(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION);
+ updateLocationCombo(false);
+ updateLoginPanelLinks();
+}
+
/*
void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe)
{
@@ -1191,4 +1297,9 @@ std::string canonicalize_username(const std::string& name)
return first + ' ' + last;
}
-
+std::string LLPanelLogin::credential_name()
+{
+ std::string username = sInstance->getChild("username_combo")->getValue().asString();
+ LLStringUtil::trim(username);
+ return username + "@" + LLGridManager::getInstance()->getGrid();
+}
\ No newline at end of file
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index d08dcb4826..87b2581fa1 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -94,16 +94,23 @@ private:
static void onClickVersion(void*);
static void onClickForgotPassword(void*);
static void onClickHelp(void*);
+ static void onClickDelete(void*);
static void onPassKey(LLLineEditor* caller, void* user_data);
static void onSelectServer(LLUICtrl*, void*);
+ static void onSelectSavedLogin(LLUICtrl*, void*);
// static void onServerComboLostFocus(LLFocusableElement*);
static void updateServerCombo();
+ static void updateSavedLoginsCombo();
static void updateStartSLURL();
void onModeChange(const LLSD& original_value, const LLSD& new_value);
void onModeChangeConfirm(const LLSD& original_value, const LLSD& new_value, const LLSD& notification, const LLSD& response);
static void updateLoginPanelLinks();
+ // Helper for making a standardized saved login name, depending on user name and grid name
+ static std::string credential_name();
+
+
private:
LLPointer mLogoImage;
boost::scoped_ptr mListener;
diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
index 812a539324..293012936c 100644
--- a/indra/newview/llsecapi.h
+++ b/indra/newview/llsecapi.h
@@ -286,7 +286,7 @@ bool operator!=(const LLCertificateVector::iterator& _lhs, const LLCertificateVe
#define CRED_AUTHENTICATOR_TYPE_HASH "hash"
//
// LLCredential - interface for credentials providing the following functionality:
-// * Persistence of credential information based on grid (for saving username/password)
+// * Persistence of credential information based on some identifier/grid name (for saving username/password)
// * Serialization to an OGP identifier/authenticator pair
//
class LLCredential : public LLRefCount
@@ -295,9 +295,9 @@ public:
LLCredential() {}
- LLCredential(const std::string& grid)
+ LLCredential(const std::string& CredentialName)
{
- mGrid = grid;
+ mCredentialName = CredentialName;
mIdentifier = LLSD::emptyMap();
mAuthenticator = LLSD::emptyMap();
}
@@ -314,7 +314,7 @@ public:
virtual LLSD getAuthenticator() { return mAuthenticator; }
virtual void authenticatorType(std::string& authType);
virtual LLSD getLoginParams();
- virtual std::string getGrid() { return mGrid; }
+ virtual std::string getCredentialName() { return mCredentialName; }
virtual void clearAuthenticator() { mAuthenticator = LLSD(); }
@@ -324,7 +324,7 @@ public:
protected:
LLSD mIdentifier;
LLSD mAuthenticator;
- std::string mGrid;
+ std::string mCredentialName;
};
std::ostream& operator <<(std::ostream& s, const LLCredential& cred);
@@ -464,11 +464,13 @@ public:
virtual void deleteProtectedData(const std::string& data_type,
const std::string& data_id)=0;
- virtual LLPointer createCredential(const std::string& grid,
+ virtual LLPointer createCredential(const std::string& name,
const LLSD& identifier,
const LLSD& authenticator)=0;
- virtual LLPointer loadCredential(const std::string& grid)=0;
+ virtual LLPointer loadCredential(const std::string& name)=0;
+
+ virtual std::vector listCredentials()=0;
virtual void saveCredential(LLPointer cred, bool save_authenticator)=0;
diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp
index 90e8ff0aae..7a301b6575 100644
--- a/indra/newview/llsechandler_basic.cpp
+++ b/indra/newview/llsechandler_basic.cpp
@@ -1445,21 +1445,21 @@ void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type,
//
// Create a credential object from an identifier and authenticator. credentials are
-// per grid.
-LLPointer LLSecAPIBasicHandler::createCredential(const std::string& grid,
+// per credential name (was: grid).
+LLPointer LLSecAPIBasicHandler::createCredential(const std::string& credName,
const LLSD& identifier,
const LLSD& authenticator)
{
- LLPointer result = new LLSecAPIBasicCredential(grid);
+ LLPointer result = new LLSecAPIBasicCredential(credName);
result->setCredentialData(identifier, authenticator);
return result;
}
-// Load a credential from the credential store, given the grid
-LLPointer LLSecAPIBasicHandler::loadCredential(const std::string& grid)
+// Load a credential from the credential store, given the credential name
+LLPointer LLSecAPIBasicHandler::loadCredential(const std::string& credName)
{
- LLSD credential = getProtectedData("credential", grid);
- LLPointer result = new LLSecAPIBasicCredential(grid);
+ LLSD credential = getProtectedData("credential", credName);
+ LLPointer result = new LLSecAPIBasicCredential(credName);
if(credential.isMap() &&
credential.has("identifier"))
{
@@ -1512,8 +1512,8 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer cred, bool sav
{
credential["authenticator"] = cred->getAuthenticator();
}
- LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL;
- setProtectedData("credential", cred->getGrid(), credential);
+ LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getCredentialName() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL;
+ setProtectedData("credential", cred->getCredentialName(), credential);
//*TODO: If we're saving Agni credentials, should we write the
// credentials to the legacy password.dat/etc?
_writeProtectedData();
@@ -1523,11 +1523,27 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer cred, bool sav
void LLSecAPIBasicHandler::deleteCredential(LLPointer cred)
{
LLSD undefVal;
- deleteProtectedData("credential", cred->getGrid());
+ deleteProtectedData("credential", cred->getCredentialName());
cred->setCredentialData(undefVal, undefVal);
_writeProtectedData();
}
+// List saved logins
+std::vector LLSecAPIBasicHandler::listCredentials()
+{
+ if (mProtectedDataMap.has("credential") && mProtectedDataMap["credential"].isMap())
+ {
+ std::vector logins(mProtectedDataMap["credential"].size());
+ int i = 0;
+ for (LLSD::map_const_iterator it = mProtectedDataMap["credential"].beginMap(); it != mProtectedDataMap["credential"].endMap(); ++it)
+ {
+ logins[i++] = it->first;
+ }
+ return logins;
+ }
+ else return std::vector();
+}
+
// load the legacy hash for agni, and decrypt it given the
// mac address
std::string LLSecAPIBasicHandler::_legacyLoadPassword()
@@ -1562,7 +1578,7 @@ std::string LLSecAPIBasicCredential::userID() const
{
if (!mIdentifier.isMap())
{
- return mGrid + "(null)";
+ return mCredentialName + "(null)";
}
else if ((std::string)mIdentifier["type"] == "agent")
{
@@ -1582,18 +1598,18 @@ std::string LLSecAPIBasicCredential::asString() const
{
if (!mIdentifier.isMap())
{
- return mGrid + ":(null)";
+ return mCredentialName + ":(null)";
}
else if ((std::string)mIdentifier["type"] == "agent")
{
- return mGrid + ":" + (std::string)mIdentifier["first_name"] + " " + (std::string)mIdentifier["last_name"];
+ return mCredentialName + ":" + (std::string)mIdentifier["first_name"] + " " + (std::string)mIdentifier["last_name"];
}
else if ((std::string)mIdentifier["type"] == "account")
{
- return mGrid + ":" + (std::string)mIdentifier["account_name"];
+ return mCredentialName + ":" + (std::string)mIdentifier["account_name"];
}
- return mGrid + ":(unknown type)";
+ return mCredentialName + ":(unknown type)";
}
diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h
index 1ce5a87c75..5e62b8315b 100644
--- a/indra/newview/llsechandler_basic.h
+++ b/indra/newview/llsechandler_basic.h
@@ -208,7 +208,7 @@ public:
class LLSecAPIBasicCredential : public LLCredential
{
public:
- LLSecAPIBasicCredential(const std::string& grid) : LLCredential(grid) {}
+ LLSecAPIBasicCredential(const std::string& credName) : LLCredential(credName) {}
virtual ~LLSecAPIBasicCredential() {}
// return a value representing the user id, (could be guid, name, whatever)
virtual std::string userID() const;
@@ -261,15 +261,17 @@ public:
// credential management routines
- virtual LLPointer createCredential(const std::string& grid,
+ virtual LLPointer createCredential(const std::string& credName,
const LLSD& identifier,
const LLSD& authenticator);
- virtual LLPointer loadCredential(const std::string& grid);
+ virtual LLPointer loadCredential(const std::string& credName);
virtual void saveCredential(LLPointer cred, bool save_authenticator);
virtual void deleteCredential(LLPointer cred);
+
+ virtual std::vector listCredentials();
protected:
void _readProtectedData();
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 096d3db34f..31d770a661 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -790,7 +790,7 @@ bool idle_startup()
//
if (gUserCredential.isNull())
{
- gUserCredential = gLoginHandler.initializeLoginInfo();
+ gUserCredential = gSecAPIHandler->loadCredential(gSavedSettings.getString("UserLoginInfo"));
}
// Previous initializeLoginInfo may have generated user credentials. Re-check them.
if (gUserCredential.isNull())
@@ -851,7 +851,7 @@ bool idle_startup()
// show the login view until login_show() is called below.
if (gUserCredential.isNull())
{
- gUserCredential = gLoginHandler.initializeLoginInfo();
+ gUserCredential = gSecAPIHandler->loadCredential(gSavedSettings.getString("UserLoginInfo"));
}
if (gHeadlessClient)
{
@@ -982,7 +982,6 @@ bool idle_startup()
if(gUserCredential.notNull())
{
userid = gUserCredential->userID();
- gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword);
}
gSavedSettings.setBOOL("RememberPassword", gRememberPassword);
LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL;
@@ -1297,6 +1296,7 @@ bool idle_startup()
// create the default proximal channel
LLVoiceChannel::initClass();
LLGridManager::getInstance()->setFavorite();
+ gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword);
LLStartUp::setStartupState( STATE_WORLD_INIT);
}
else
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index 279fa0b465..2857db102d 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -44,13 +44,13 @@ name="login_widgets"
layout="topleft"
orientation="horizontal"
top="519"
-width="996"
+width="1246"
height="80">
@@ -202,6 +202,37 @@ top_pad="0"
name="server_combo"
width="120"
visible="false" />
+
+ Saved logins:
+
+
+