diff options
author | andreykproductengine <andreykproductengine@lindenlab.com> | 2019-08-09 21:34:12 +0300 |
---|---|---|
committer | andreykproductengine <andreykproductengine@lindenlab.com> | 2019-08-09 21:34:12 +0300 |
commit | 99a4bd23dadbdaf8e82ceca26af531c93d5fd4a6 (patch) | |
tree | f88a535d9c3b28e2b32e4241ff27ee8624595d36 /indra/newview | |
parent | db6275b9f727d88f6e5501e36c165c2c43659bd7 (diff) |
SL-9699 Login selection
Diffstat (limited to 'indra/newview')
-rw-r--r-- | indra/newview/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/newview/app_settings/settings.xml | 11 | ||||
-rw-r--r-- | indra/newview/llfavoritesbar.cpp | 70 | ||||
-rw-r--r-- | indra/newview/llfavoritesbar.h | 9 | ||||
-rw-r--r-- | indra/newview/llfloaterforgetuser.cpp | 154 | ||||
-rw-r--r-- | indra/newview/llfloaterforgetuser.h | 46 | ||||
-rw-r--r-- | indra/newview/llfloaterpreference.cpp | 6 | ||||
-rw-r--r-- | indra/newview/llfloaterpreference.h | 1 | ||||
-rw-r--r-- | indra/newview/llloginhandler.cpp | 7 | ||||
-rw-r--r-- | indra/newview/llpanellogin.cpp | 426 | ||||
-rw-r--r-- | indra/newview/llpanellogin.h | 17 | ||||
-rw-r--r-- | indra/newview/llsecapi.h | 46 | ||||
-rw-r--r-- | indra/newview/llsechandler_basic.cpp | 176 | ||||
-rw-r--r-- | indra/newview/llsechandler_basic.h | 61 | ||||
-rw-r--r-- | indra/newview/llstartup.cpp | 41 | ||||
-rw-r--r-- | indra/newview/llviewerfloaterreg.cpp | 2 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_forget_user.xml | 40 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/panel_login.xml | 54 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/panel_preferences_advanced.xml | 23 | ||||
-rw-r--r-- | indra/newview/tests/llsecapi_test.cpp | 9 |
20 files changed, 1047 insertions, 154 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b8789da66b..0ca5a08dfc 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -246,6 +246,7 @@ set(viewer_SOURCE_FILES llfloaterexperiences.cpp llfloaterflickr.cpp llfloaterfonttest.cpp + llfloaterforgetuser.cpp llfloatergesture.cpp llfloatergodtools.cpp llfloatergotoline.cpp @@ -871,6 +872,7 @@ set(viewer_HEADER_FILES llfloaterexperiences.h llfloaterflickr.h llfloaterfonttest.h + llfloaterforgetuser.h llfloatergesture.h llfloatergodtools.h llfloatergotoline.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 2cd19da0c6..f54f683757 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -8434,6 +8434,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>RememberUser</key> + <map> + <key>Comment</key> + <string>Keep user name for next login</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> <key>RememberPassword</key> <map> <key>Comment</key> diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp index 5b4b7789b4..17952349dc 100644 --- a/indra/newview/llfavoritesbar.cpp +++ b/indra/newview/llfavoritesbar.cpp @@ -1493,19 +1493,25 @@ void LLFavoritesOrderStorage::getSLURL(const LLUUID& asset_id) } // static -std::string LLFavoritesOrderStorage::getStoredFavoritesFilename() +std::string LLFavoritesOrderStorage::getStoredFavoritesFilename(const std::string &grid) { - std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); + std::string user_dir = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""); return (user_dir.empty() ? "" : gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites_" - + LLGridManager::getInstance()->getGrid() + + grid + ".xml") ); } // static +std::string LLFavoritesOrderStorage::getStoredFavoritesFilename() +{ + return getStoredFavoritesFilename(LLGridManager::getInstance()->getGrid()); +} + +// static void LLFavoritesOrderStorage::destroyClass() { LLFavoritesOrderStorage::instance().cleanup(); @@ -1602,6 +1608,64 @@ void LLFavoritesOrderStorage::load() } } +// static +void LLFavoritesOrderStorage::removeFavoritesRecordOfUser(const std::string &user, const std::string &grid) +{ + std::string filename = getStoredFavoritesFilename(grid); + if (!filename.empty()) + { + LLSD fav_llsd; + llifstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::fromXML(fav_llsd, file); + file.close(); + + // Note : use the "John Doe" and not the "john.doe" version of the name. + // See saveFavoritesSLURLs() here above for the reason why. + if (fav_llsd.has(user)) + { + LLSD user_llsd = fav_llsd[user]; + + if ((user_llsd.beginArray() != user_llsd.endArray()) && user_llsd.beginArray()->has("id")) + { + for (LLSD::array_iterator iter = user_llsd.beginArray(); iter != user_llsd.endArray(); ++iter) + { + LLSD value; + value["id"] = iter->get("id").asUUID(); + iter->assign(value); + } + fav_llsd[user] = user_llsd; + llofstream file; + file.open(filename.c_str()); + if (file.is_open()) + { + LLSDSerialize::toPrettyXML(fav_llsd, file); + file.close(); + } + } + else + { + LL_INFOS("FavoritesBar") << "Removed favorites for " << user << LL_ENDL; + fav_llsd.erase(user); + } + } + + llofstream out_file; + out_file.open(filename.c_str()); + if (out_file.is_open()) + { + LLSDSerialize::toPrettyXML(fav_llsd, out_file); + LL_INFOS("FavoritesBar") << "saved favorites to '" << filename << "' " + << LL_ENDL; + out_file.close(); + } + } + } +} + +// static void LLFavoritesOrderStorage::removeFavoritesRecordOfUser() { std::string filename = getStoredFavoritesFilename(); diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h index cac32c7f2a..d93161fd7a 100644 --- a/indra/newview/llfavoritesbar.h +++ b/indra/newview/llfavoritesbar.h @@ -208,9 +208,15 @@ public: * @see cleanup() */ static void destroyClass(); + static std::string getStoredFavoritesFilename(const std::string &grid); static std::string getStoredFavoritesFilename(); static std::string getSavedOrderFileName(); + // Remove record of specified user's favorites from file on disk. + static void removeFavoritesRecordOfUser(const std::string &user, const std::string &grid); + // Remove record of current user's favorites from file on disk. + static void removeFavoritesRecordOfUser(); + BOOL saveFavoritesRecord(bool pref_changed = false); void showFavoritesOnLoginChanged(BOOL show); @@ -232,9 +238,6 @@ private: void load(); - // Remove record of current user's favorites from file on disk. - void removeFavoritesRecordOfUser(); - void onLandmarkLoaded(const LLUUID& asset_id, class LLLandmark* landmark); void storeFavoriteSLURL(const LLUUID& asset_id, std::string& slurl); diff --git a/indra/newview/llfloaterforgetuser.cpp b/indra/newview/llfloaterforgetuser.cpp new file mode 100644 index 0000000000..5659cb2f79 --- /dev/null +++ b/indra/newview/llfloaterforgetuser.cpp @@ -0,0 +1,154 @@ +/** + * @file llfloaterforgetuser.cpp + * @brief LLFloaterForgetUser class definition. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, Linden Research, Inc. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterforgetuser.h" + +#include "llcheckboxctrl.h" +#include "llfavoritesbar.h" +#include "llpanellogin.h" // for helper function getUserName() and to repopulate list if nessesary +#include "llscrolllistctrl.h" +#include "llsecapi.h" +#include "llviewernetwork.h" + + +LLFloaterForgetUser::LLFloaterForgetUser(const LLSD &key) + : LLFloater("floater_forget_user"), + mLoginPanelDirty(false) +{ + +} + +LLFloaterForgetUser::~LLFloaterForgetUser() +{ + if (mLoginPanelDirty) + { + LLPanelLogin::resetFields(); + } +} + +BOOL LLFloaterForgetUser::postBuild() +{ + // Note, storage works per grid, watever is selected currently in login screen or logged in. + // Since login screen can change grid, store the value. + mGrid = LLGridManager::getInstance()->getGrid(); + + LLScrollListCtrl *scroll_list = getChild<LLScrollListCtrl>("user_list"); + if (gSecAPIHandler->hasCredentialMap("login_list", mGrid)) + { + LLSecAPIHandler::credential_map_t credencials; + gSecAPIHandler->loadCredentialMap("login_list", mGrid, credencials); + + LLSecAPIHandler::credential_map_t::iterator cr_iter = credencials.begin(); + LLSecAPIHandler::credential_map_t::iterator cr_end = credencials.end(); + while (cr_iter != cr_end) + { + if (cr_iter->second.notNull()) // basic safety + { + LLScrollListItem::Params item_params; + item_params.value(cr_iter->first); + item_params.columns.add() + .value(LLPanelLogin::getUserName(cr_iter->second)) + .column("user") + .font(LLFontGL::getFontSansSerifSmall()); + scroll_list->addRow(item_params, ADD_BOTTOM); + } + cr_iter++; + } + scroll_list->selectFirstItem(); + } + else + { + LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(mGrid); + if (cred.notNull()) + { + LLScrollListItem::Params item_params; + item_params.value(cred->userID()); + item_params.columns.add() + .value(LLPanelLogin::getUserName(cred)) + .column("user") + .font(LLFontGL::getFontSansSerifSmall()); + scroll_list->addRow(item_params, ADD_BOTTOM); + scroll_list->selectFirstItem(); + } + } + + bool enable_button = scroll_list->getFirstSelectedIndex() != -1; + getChild<LLView>("delete_data")->setEnabled(enable_button); + LLButton *button = getChild<LLButton>("forget"); + button->setEnabled(enable_button); + button->setCommitCallback(boost::bind(&LLFloaterForgetUser::onForgetClicked, this)); + + return TRUE; +} + +void LLFloaterForgetUser::onForgetClicked() +{ + mLoginPanelDirty = true; + LLScrollListCtrl *scroll_list = getChild<LLScrollListCtrl>("user_list"); + std::string user_key = scroll_list->getSelectedValue(); + + // remove creds + gSecAPIHandler->removeFromCredentialMap("login_list", mGrid, user_key); + + LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(mGrid); + if (cred.notNull() && cred->userID() == user_key) + { + gSecAPIHandler->deleteCredential(cred); + } + + // Clean data + LLCheckBoxCtrl *chk_box = getChild<LLCheckBoxCtrl>("delete_data"); + BOOL delete_data = chk_box->getValue(); + if (delete_data) + { + // key is edentical to one we use for name of user's folder + std::string user_path = gDirUtilp->getOSUserAppDir() + gDirUtilp->getDirDelimiter() + user_key; + gDirUtilp->deleteDirAndContents(user_path); + + // Clean favorites, label is edentical to username + LLFavoritesOrderStorage::removeFavoritesRecordOfUser(scroll_list->getSelectedItemLabel(), mGrid); + + // Note: we do not clean user-related files from cache because there are id dependent (inventory) + // files and cache has separate cleaning mechanism either way. + // Also this only cleans user from current grid, not all of them. + } + + + // Update UI + scroll_list->deleteSelectedItems(); + scroll_list->selectFirstItem(); + if (scroll_list->getFirstSelectedIndex() == -1) + { + LLButton *button = getChild<LLButton>("forget"); + button->setEnabled(false); + chk_box->setEnabled(false); + } +} + + diff --git a/indra/newview/llfloaterforgetuser.h b/indra/newview/llfloaterforgetuser.h new file mode 100644 index 0000000000..119aece2d1 --- /dev/null +++ b/indra/newview/llfloaterforgetuser.h @@ -0,0 +1,46 @@ +/** + * @file llfloaterforgetuser.h + * @brief LLFloaterForgetUser class declaration. + * + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2019, Linden Research, Inc. + * + * 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERFORGETUSER_H +#define LL_LLFLOATERFORGETUSER_H + +#include "llfloater.h" + +class LLFloaterForgetUser : public LLFloater +{ +public: + LLFloaterForgetUser(const LLSD &key); + ~LLFloaterForgetUser(); + + BOOL postBuild(); + void onForgetClicked(); + +private: + bool mLoginPanelDirty; + std::string mGrid; +}; + +#endif diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 27a597a631..9d0e1972a3 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -419,6 +419,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.TranslationSettings", boost::bind(&LLFloaterPreference::onClickTranslationSettings, this)); mCommitCallbackRegistrar.add("Pref.AutoReplace", boost::bind(&LLFloaterPreference::onClickAutoReplace, this)); mCommitCallbackRegistrar.add("Pref.PermsDefault", boost::bind(&LLFloaterPreference::onClickPermsDefault, this)); + mCommitCallbackRegistrar.add("Pref.RememberedUsernames", boost::bind(&LLFloaterPreference::onClickRememberedUsernames, this)); mCommitCallbackRegistrar.add("Pref.SpellChecker", boost::bind(&LLFloaterPreference::onClickSpellChecker, this)); mCommitCallbackRegistrar.add("Pref.Advanced", boost::bind(&LLFloaterPreference::onClickAdvanced, this)); @@ -2256,6 +2257,11 @@ void LLFloaterPreference::onClickPermsDefault() LLFloaterReg::showInstance("perms_default"); } +void LLFloaterPreference::onClickRememberedUsernames() +{ + LLFloaterReg::showInstance("forget_username"); +} + void LLFloaterPreference::onDeleteTranscripts() { LLSD args; diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index d46f0deb7a..8345ad1bb6 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -181,6 +181,7 @@ public: void onClickProxySettings(); void onClickTranslationSettings(); void onClickPermsDefault(); + void onClickRememberedUsernames(); void onClickAutoReplace(); void onClickSpellChecker(); void onClickRenderExceptions(); diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp index eca34c0d4d..22cedf450e 100644 --- a/indra/newview/llloginhandler.cpp +++ b/indra/newview/llloginhandler.cpp @@ -139,8 +139,11 @@ LLPointer<LLCredential> LLLoginHandler::initializeLoginInfo() // so try to load it from the UserLoginInfo result = loadSavedUserLoginInfo(); if (result.isNull()) - { - result = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + { + // Since legacy viewer store login info one per grid, newer viewers have to + // reuse same information to remember last user and for compatibility, + // but otherwise login info is stored in separate map in gSecAPIHandler + result = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); } return result; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index e253557797..d7c189271e 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -77,6 +77,60 @@ LLPanelLogin *LLPanelLogin::sInstance = NULL; BOOL LLPanelLogin::sCapslockDidNotification = FALSE; BOOL LLPanelLogin::sCredentialSet = FALSE; +// Helper functions + +LLPointer<LLCredential> load_user_credentials(std::string &user_key) +{ + if (gSecAPIHandler->hasCredentialMap("login_list", LLGridManager::getInstance()->getGrid())) + { + // user_key should be of "name Resident" format + return gSecAPIHandler->loadFromCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), user_key); + } + else + { + // legacy (or legacy^2, since it also tries to load from settings) + return gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + } +} + +// keys are lower case to be case insensitive so they are not always +// identical to names which retain user input, like: +// "AwEsOmE Resident" -> "awesome_resident" +std::string get_user_key_from_name(const std::string &username) +{ + std::string key = username; + LLStringUtil::trim(key); + LLStringUtil::toLower(key); + if (!LLGridManager::getInstance()->isSystemGrid()) + { + size_t separator_index = username.find_first_of(" "); + if (separator_index == username.npos) + { + // CRED_IDENTIFIER_TYPE_ACCOUNT + return key; + } + } + // CRED_IDENTIFIER_TYPE_AGENT + size_t separator_index = username.find_first_of(" ._"); + std::string first = username.substr(0, separator_index); + std::string last; + if (separator_index != username.npos) + { + last = username.substr(separator_index + 1, username.npos); + LLStringUtil::trim(last); + } + else + { + // ...on Linden grids, single username users as considered to have + // last name "Resident" + // *TODO: Make login.cgi support "account_name" like above + last = "resident"; + } + + key = first + "_" + last; + return key; +} + class LLLoginLocationAutoHandler : public LLCommandHandler { public: @@ -168,6 +222,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, mCallback(callback), mCallbackData(cb_data), mListener(new LLPanelLoginListener(this)), + mFirstLoginThisInstall(gSavedSettings.getBOOL("FirstLoginThisInstall")), mUsernameLength(0), mPasswordLength(0), mLocationLength(0), @@ -186,7 +241,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, login_holder->addChild(this); } - if (gSavedSettings.getBOOL("FirstLoginThisInstall")) + if (mFirstLoginThisInstall) { buildFromFile( "panel_login_first.xml"); } @@ -206,35 +261,39 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, sendChildToBack(getChildView("forgot_password_text")); sendChildToBack(getChildView("sign_up_text")); - LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo"); - updateLocationSelectorsVisibility(); // separate so that it can be called from preferences - favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); - favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); - - LLComboBox* server_choice_combo = getChild<LLComboBox>("server_combo"); - server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this)); - - // Load all of the grids, sorted, and then add a bar and the current grid at the top - server_choice_combo->removeall(); - - std::string current_grid = LLGridManager::getInstance()->getGrid(); - std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); - for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin(); - grid_choice != known_grids.end(); - grid_choice++) - { - if (!grid_choice->first.empty() && current_grid != grid_choice->first) - { - LL_DEBUGS("AppInit")<<"adding "<<grid_choice->first<<LL_ENDL; - server_choice_combo->add(grid_choice->second, grid_choice->first); - } - } - server_choice_combo->sortByName(); - LL_DEBUGS("AppInit")<<"adding current "<<current_grid<<LL_ENDL; - server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), - current_grid, - ADD_TOP); - server_choice_combo->selectFirstItem(); + std::string current_grid = LLGridManager::getInstance()->getGrid(); + if (!mFirstLoginThisInstall) + { + LLComboBox* favorites_combo = getChild<LLComboBox>("start_location_combo"); + updateLocationSelectorsVisibility(); // separate so that it can be called from preferences + favorites_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); + favorites_combo->setFocusLostCallback(boost::bind(&LLPanelLogin::onLocationSLURL, this)); + + LLComboBox* server_choice_combo = getChild<LLComboBox>("server_combo"); + server_choice_combo->setCommitCallback(boost::bind(&LLPanelLogin::onSelectServer, this)); + + // Load all of the grids, sorted, and then add a bar and the current grid at the top + server_choice_combo->removeall(); + + std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(); + for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin(); + grid_choice != known_grids.end(); + grid_choice++) + { + if (!grid_choice->first.empty() && current_grid != grid_choice->first) + { + LL_DEBUGS("AppInit") << "adding " << grid_choice->first << LL_ENDL; + server_choice_combo->add(grid_choice->second, grid_choice->first); + } + } + server_choice_combo->sortByName(); + + LL_DEBUGS("AppInit") << "adding current " << current_grid << LL_ENDL; + server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(), + current_grid, + ADD_TOP); + server_choice_combo->selectFirstItem(); + } LLSLURL start_slurl(LLStartUp::getStartSLURL()); // The StartSLURL might have been set either by an explicit command-line @@ -297,14 +356,30 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, loadLoginPage(); LLComboBox* username_combo(getChild<LLComboBox>("username_combo")); - username_combo->setTextChangedCallback(boost::bind(&LLPanelLogin::addFavoritesToStartLocation, this)); + username_combo->setTextChangedCallback(boost::bind(&LLPanelLogin::onUserNameTextEnty, this)); // STEAM-14: When user presses Enter with this field in focus, initiate login - username_combo->setCommitCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); + username_combo->setCommitCallback(boost::bind(&LLPanelLogin::onUserListCommit, this)); + username_combo->setReturnCallback(boost::bind(&LLPanelLogin::onClickConnect, this)); username_combo->setKeystrokeOnEsc(TRUE); + + if (!mFirstLoginThisInstall) + { + LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name"); + remember_name->setCommitCallback(boost::bind(&LLPanelLogin::onRememberUserCheck, this)); + } } void LLPanelLogin::addFavoritesToStartLocation() { + if (mFirstLoginThisInstall) + { + // first login panel has no favorites, just update name length and buttons + std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple(); + mUsernameLength = user_defined_name.length(); + updateLoginButtons(); + return; + } + // Clear the combo. LLComboBox* combo = getChild<LLComboBox>("start_location_combo"); if (!combo) return; @@ -316,14 +391,14 @@ void LLPanelLogin::addFavoritesToStartLocation() // Load favorites into the combo. std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple(); + LLStringUtil::trim(user_defined_name); LLStringUtil::toLower(user_defined_name); - std::replace(user_defined_name.begin(), user_defined_name.end(), '.', ' '); std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites_" + LLGridManager::getInstance()->getGrid() + ".xml"); std::string old_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml"); mUsernameLength = user_defined_name.length(); updateLoginButtons(); - std::string::size_type index = user_defined_name.find(' '); + std::string::size_type index = user_defined_name.find_first_of(" ._"); if (index != std::string::npos) { std::string username = user_defined_name.substr(0, index); @@ -332,6 +407,10 @@ void LLPanelLogin::addFavoritesToStartLocation() { user_defined_name = username; } + else + { + user_defined_name = username + " " + lastname; + } } LLSD fav_llsd; @@ -443,24 +522,6 @@ void LLPanelLogin::giveFocus() } // static -void LLPanelLogin::showLoginWidgets() -{ - if (sInstance) - { - // *NOTE: Mani - This may or may not be obselete code. - // It seems to be part of the defunct? reg-in-client project. - sInstance->getChildView("login_widgets")->setVisible( true); - LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html"); - - // *TODO: Append all the usual login parameters, like first_login=Y etc. - std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage(); - web_browser->navigateTo( splash_screen_url, "text/html" ); - LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo"); - username_combo->setFocus(TRUE); - } -} - -// static void LLPanelLogin::show(const LLRect &rect, void (*callback)(S32 option, void* user_data), void* callback_data) @@ -480,9 +541,55 @@ void LLPanelLogin::show(const LLRect &rect, gFocusMgr.setDefaultKeyboardFocus(sInstance); } +//static +void LLPanelLogin::populateFields(LLPointer<LLCredential> credential, bool remember_user, bool remember_psswrd) +{ + if (!sInstance) + { + LL_WARNS() << "Attempted fillFields with no login view shown" << LL_ENDL; + return; + } + LLUICtrl* remember_check = sInstance->getChild<LLUICtrl>("remember_check"); + remember_check->setValue(remember_psswrd); + if (sInstance->mFirstLoginThisInstall) + { + // no list to populate + setFields(credential, remember_psswrd); + } + else + { + sInstance->getChild<LLUICtrl>("remember_name")->setValue(remember_user); + sInstance->populateUserList(credential, remember_psswrd); + remember_check->setEnabled(remember_user); + } +} + +//static +void LLPanelLogin::resetFields() +{ + if (!sInstance) + { + // class not existing at this point might happen since this + // function is used to reset list in case of changes by external sources + return; + } + if (sInstance->mFirstLoginThisInstall) + { + // no list to populate + LL_WARNS() << "Shouldn't happen, user should have no ability to modify list on first install" << LL_ENDL; + } + else + { + LLUICtrl* remember_check = sInstance->getChild<LLUICtrl>("remember_check"); + bool remember_psswrd = remember_check->getValue(); + LLPointer<LLCredential> cred = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + sInstance->populateUserList(cred, remember_psswrd); + } +} + // static void LLPanelLogin::setFields(LLPointer<LLCredential> credential, - BOOL remember) + bool remember_psswrd) { if (!sInstance) { @@ -492,13 +599,15 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential, sCredentialSet = TRUE; LL_INFOS("Credentials") << "Setting login fields to " << *credential << LL_ENDL; - LLSD identifier = credential->getIdentifier(); - if((std::string)identifier["type"] == "agent") + LLSD identifier = credential.notNull() ? credential->getIdentifier() : LLSD(); + + if(identifier.has("type") && (std::string)identifier["type"] == "agent") { + // not nessesary for panel_login.xml, needed for panel_login_first.xml std::string firstname = identifier["first_name"].asString(); std::string lastname = identifier["last_name"].asString(); std::string login_id = firstname; - if (!lastname.empty() && lastname != "Resident") + if (!lastname.empty() && lastname != "Resident" && lastname != "resident") { // support traditional First Last name SLURLs login_id += " "; @@ -506,22 +615,23 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential, } sInstance->getChild<LLComboBox>("username_combo")->setLabel(login_id); } - else if((std::string)identifier["type"] == "account") + else if(identifier.has("type") && (std::string)identifier["type"] == "account") { sInstance->getChild<LLComboBox>("username_combo")->setLabel((std::string)identifier["account_name"]); } else { - sInstance->getChild<LLComboBox>("username_combo")->setLabel(std::string()); + sInstance->getChild<LLComboBox>("username_combo")->setLabel(std::string()); } + sInstance->addFavoritesToStartLocation(); // if the password exists in the credential, set the password field with // a filler to get some stars - LLSD authenticator = credential->getAuthenticator(); + LLSD authenticator = credential.notNull() ? credential->getAuthenticator() : LLSD(); LL_INFOS("Credentials") << "Setting authenticator field " << authenticator["type"].asString() << LL_ENDL; if(authenticator.isMap() && authenticator.has("secret") && - (authenticator["secret"].asString().size() > 0) && remember) + (authenticator["secret"].asString().size() > 0) && remember_psswrd) { // This is a MD5 hex digest of a password. @@ -537,36 +647,25 @@ void LLPanelLogin::setFields(LLPointer<LLCredential> credential, { sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string()); } - sInstance->getChild<LLUICtrl>("remember_check")->setValue(remember); } - // static void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, - BOOL& remember) + bool& remember_user, + bool& remember_psswrd) { if (!sInstance) { LL_WARNS() << "Attempted getFields with no login view shown" << LL_ENDL; return; } - - // 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()); LLSD identifier = LLSD::emptyMap(); LLSD authenticator = LLSD::emptyMap(); - - if(credential.notNull()) - { - authenticator = credential->getAuthenticator(); - } - std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString(); - LLStringUtil::trim(username); + std::string username = sInstance->getChild<LLComboBox>("username_combo")->getValue().asString(); std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString(); + LLStringUtil::trim(username); LL_INFOS("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL; // determine if the username is a first/last form or not. @@ -586,6 +685,14 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR; authenticator["secret"] = password; } + else + { + credential = load_user_credentials(username); + if (credential.notNull()) + { + authenticator = credential->getAuthenticator(); + } + } } else { @@ -597,7 +704,7 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, if (separator_index != username.npos) { last = username.substr(separator_index+1, username.npos); - LLStringUtil::trim(last); + LLStringUtil::trim(last); } else { @@ -625,10 +732,28 @@ void LLPanelLogin::getFields(LLPointer<LLCredential>& credential, pass.hex_digest(md5pass); authenticator["secret"] = md5pass; } + else + { + std::string key = first + "_" + last; + LLStringUtil::toLower(key); + credential = load_user_credentials(key); + if (credential.notNull()) + { + authenticator = credential->getAuthenticator(); + } + } } } credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator); - remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); + remember_psswrd = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); + if (!sInstance->mFirstLoginThisInstall) + { + remember_user = sInstance->getChild<LLUICtrl>("remember_name")->getValue(); + } + else + { + remember_user = true; + } } @@ -898,8 +1023,8 @@ void LLPanelLogin::onClickConnect(void *) { sCredentialSet = FALSE; LLPointer<LLCredential> cred; - BOOL remember; - getFields(cred, remember); + bool remember_1, remember_2; + getFields(cred, remember_1, remember_2); std::string identifier_type; cred->identifierType(identifier_type); LLSD allowed_credential_types; @@ -953,6 +1078,57 @@ void LLPanelLogin::onClickSignUp(void*) } // static +void LLPanelLogin::onUserNameTextEnty(void*) +{ + sInstance->mPasswordModified = true; + sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string()); + sInstance->addFavoritesToStartLocation(); //will call updateLoginButtons() +} + +// static +void LLPanelLogin::onUserListCommit(void*) +{ + if (sInstance) + { + LLComboBox* username_combo(sInstance->getChild<LLComboBox>("username_combo")); + static S32 ind = -1; + if (ind != username_combo->getCurrentIndex()) + { + std::string user_key = username_combo->getSelectedValue(); + LLPointer<LLCredential> cred = gSecAPIHandler->loadFromCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), user_key); + bool remember_psswrd = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); + setFields(cred, remember_psswrd); + sInstance->mPasswordModified = false; + } + else + { + std::string pass = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString(); + if (pass.empty()) + { + sInstance->giveFocus(); + } + else + { + onClickConnect(NULL); + } + } + } +} + +// static +void LLPanelLogin::onRememberUserCheck(void*) +{ + if (sInstance) + { + LLCheckBoxCtrl* remember_name(sInstance->getChild<LLCheckBoxCtrl>("remember_name")); + LLCheckBoxCtrl* remember_psswrd(sInstance->getChild<LLCheckBoxCtrl>("remember_check")); + + bool remember = remember_name->getValue().asBoolean(); + remember_psswrd->setEnabled(remember); + } +} + +// static void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data) { LLPanelLogin *self = (LLPanelLogin *)user_data; @@ -979,9 +1155,11 @@ void LLPanelLogin::updateServer() // for that grid and set them to the UI. if(!sInstance->areCredentialFieldsDirty()) { - LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); - bool remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); - sInstance->setFields(credential, remember); + // populate dropbox and setFields + bool remember_psswrd = sInstance->getChild<LLUICtrl>("remember_check")->getValue(); + // Note: following call is related to initializeLoginInfo() + LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid()); + sInstance->populateUserList(credential, remember_psswrd); } // update the login panel links @@ -1011,14 +1189,63 @@ void LLPanelLogin::updateLoginButtons() LLButton* login_btn = getChild<LLButton>("connect_btn"); login_btn->setEnabled(mUsernameLength != 0 && mPasswordLength != 0); + + if (!mFirstLoginThisInstall) + { + LLComboBox* user_combo = getChild<LLComboBox>("username_combo"); + LLCheckBoxCtrl* remember_name = getChild<LLCheckBoxCtrl>("remember_name"); + remember_name->setEnabled(user_combo->getCurrentIndex() == -1); + } +} + +void LLPanelLogin::populateUserList(LLPointer<LLCredential> credential, bool remember_psswrd) +{ + LLComboBox* user_combo = getChild<LLComboBox>("username_combo"); + user_combo->removeall(); + user_combo->clear(); + + if (gSecAPIHandler->hasCredentialMap("login_list", LLGridManager::getInstance()->getGrid())) + { + LLSecAPIHandler::credential_map_t credencials; + gSecAPIHandler->loadCredentialMap("login_list", LLGridManager::getInstance()->getGrid(), credencials); + + LLSecAPIHandler::credential_map_t::iterator cr_iter = credencials.begin(); + LLSecAPIHandler::credential_map_t::iterator cr_end = credencials.end(); + while (cr_iter != cr_end) + { + if (cr_iter->second.notNull()) // basic safety in case of future changes + { + // cr_iter->first == user_id , to be able to be find it in case we select it + user_combo->add(LLPanelLogin::getUserName(cr_iter->second), cr_iter->first, ADD_BOTTOM, TRUE); + } + cr_iter++; + } + + if (credential.isNull() || !user_combo->setSelectedByValue(LLSD(credential->userID()), true)) + { + // selection failed, just deselect whatever might be selected + user_combo->setValue(std::string()); + } + else + { + setFields(credential, remember_psswrd); + } + } + else + { + if (credential.notNull()) + { + user_combo->add(LLPanelLogin::getUserName(credential), credential->userID(), ADD_BOTTOM, TRUE); + setFields(credential, remember_psswrd); + } + } } + void LLPanelLogin::onSelectServer() { // The user twiddled with the grid choice ui. // apply the selection to the grid setting. - LLPointer<LLCredential> credential; - LLComboBox* server_combo = getChild<LLComboBox>("server_combo"); LLSD server_combo_val = server_combo->getSelectedValue(); LL_INFOS("AppInit") << "grid "<<server_combo_val.asString()<< LL_ENDL; @@ -1077,3 +1304,34 @@ bool LLPanelLogin::getShowFavorites() { return gSavedPerAccountSettings.getBOOL("ShowFavoritesOnLogin"); } + +// static +std::string LLPanelLogin::getUserName(LLPointer<LLCredential> &cred) +{ + if (cred.isNull()) + { + return "unknown"; + } + const LLSD &ident = cred->getIdentifier(); + + if (!ident.isMap()) + { + return "unknown"; + } + else if ((std::string)ident["type"] == "agent") + { + std::string second_name = ident["last_name"]; + if (second_name == "resident" || second_name == "Resident") + { + return (std::string)ident["first_name"]; + } + return (std::string)ident["first_name"] + " " + (std::string)ident["last_name"]; + } + else if ((std::string)ident["type"] == "account") + { + return LLCacheName::cleanFullName((std::string)ident["account_name"]); + } + + return "unknown"; +} + diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index c633582d89..3eb7b68949 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -55,9 +55,9 @@ public: void (*callback)(S32 option, void* user_data), void* callback_data); - static void setFields(LLPointer<LLCredential> credential, BOOL remember); - - static void getFields(LLPointer<LLCredential>& credential, BOOL& remember); + static void populateFields(LLPointer<LLCredential> credential, bool remember_user, bool remember_psswrd); + static void resetFields(); + static void getFields(LLPointer<LLCredential>& credential, bool& remember_user, bool& remember_psswrd); static BOOL isCredentialSet() { return sCredentialSet; } @@ -72,8 +72,6 @@ public: void setSiteIsAlive( bool alive ); - void showLoginWidgets(); - static void loadLoginPage(); static void giveFocus(); static void setAlwaysRefresh(bool refresh); @@ -88,6 +86,9 @@ public: // called from prefs when initializing panel static bool getShowFavorites(); + // extract name from cred in a format apropriate for username field + static std::string getUserName(LLPointer<LLCredential> &cred); + private: friend class LLPanelLoginListener; void addFavoritesToStartLocation(); @@ -95,11 +96,16 @@ private: void onSelectServer(); void onLocationSLURL(); + static void setFields(LLPointer<LLCredential> credential, bool remember_psswrd); + static void onClickConnect(void*); static void onClickNewAccount(void*); static void onClickVersion(void*); static void onClickForgotPassword(void*); static void onClickSignUp(void*); + static void onUserNameTextEnty(void*); + static void onUserListCommit(void*); + static void onRememberUserCheck(void*); static void onPassKey(LLLineEditor* caller, void* user_data); static void updateServerCombo(); @@ -107,6 +113,7 @@ private: boost::scoped_ptr<LLPanelLoginListener> mListener; void updateLoginButtons(); + void populateUserList(LLPointer<LLCredential> credential, bool remember_psswrd); void (*mCallback)(S32 option, void *userdata); void* mCallbackData; diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index d207f3b5b7..c0f0a367c7 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -464,7 +464,19 @@ public: // delete a protected data item from the store virtual void deleteProtectedData(const std::string& data_type, const std::string& data_id)=0; - + + // persist data in a protected store's map + virtual void addToProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem, + const LLSD& data)=0; + + // remove data from protected store's map + virtual void removeFromProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem)=0; + +public: virtual LLPointer<LLCredential> createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator)=0; @@ -474,6 +486,38 @@ public: virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator)=0; virtual void deleteCredential(LLPointer<LLCredential> cred)=0; + + // has map of credentials declared as specific storage + virtual bool hasCredentialMap(const std::string& storage, + const std::string& grid)=0; + + // load map of credentials from specific storage + typedef std::map<std::string, LLPointer<LLCredential> > credential_map_t; + virtual void loadCredentialMap(const std::string& storage, + const std::string& grid, + credential_map_t& credential_map)=0; + + // load single username from map of credentials from specific storage + virtual LLPointer<LLCredential> loadFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid)=0; + + // add item to map of credentials from specific storage + virtual void addToCredentialMap(const std::string& storage, + LLPointer<LLCredential> cred, + bool save_authenticator)=0; + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + LLPointer<LLCredential> cred)=0; + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid)=0; + + virtual void removeCredentialMap(const std::string& storage, + const std::string& grid)=0; }; diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp index 9ab9e4a1a2..a8bb54a90e 100644 --- a/indra/newview/llsechandler_basic.cpp +++ b/indra/newview/llsechandler_basic.cpp @@ -52,6 +52,7 @@ #include "llmachineid.h" +static const std::string DEFAULT_CREDENTIAL_STORAGE = "credential"; // 128 bits of salt data... #define STORE_SALT_SIZE 16 @@ -1533,6 +1534,38 @@ void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type, mProtectedDataMap[data_type][data_id] = data; } +// persist data in a protected store's map +void LLSecAPIBasicHandler::addToProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem, + const LLSD& data) +{ + if (!mProtectedDataMap.has(data_type) || !mProtectedDataMap[data_type].isMap()) { + mProtectedDataMap[data_type] = LLSD::emptyMap(); + } + + if (!mProtectedDataMap[data_type].has(data_id) || !mProtectedDataMap[data_type][data_id].isMap()) { + mProtectedDataMap[data_type][data_id] = LLSD::emptyMap(); + } + + mProtectedDataMap[data_type][data_id][map_elem] = data; +} + +// remove data from protected store's map +void LLSecAPIBasicHandler::removeFromProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem) +{ + if (mProtectedDataMap.has(data_type) && + mProtectedDataMap[data_type].isMap() && + mProtectedDataMap[data_type].has(data_id) && + mProtectedDataMap[data_type][data_id].isMap() && + mProtectedDataMap[data_type][data_id].has(map_elem)) + { + mProtectedDataMap[data_type][data_id].erase(map_elem); + } +} + // // Create a credential object from an identifier and authenticator. credentials are // per grid. @@ -1545,10 +1578,10 @@ LLPointer<LLCredential> LLSecAPIBasicHandler::createCredential(const std::string return result; } -// Load a credential from the credential store, given the grid +// Load a credential from default credential store, given the grid LLPointer<LLCredential> LLSecAPIBasicHandler::loadCredential(const std::string& grid) { - LLSD credential = getProtectedData("credential", grid); + LLSD credential = getProtectedData(DEFAULT_CREDENTIAL_STORAGE, grid); LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid); if(credential.isMap() && credential.has("identifier")) @@ -1603,7 +1636,7 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> 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); + setProtectedData(DEFAULT_CREDENTIAL_STORAGE, cred->getGrid(), credential); //*TODO: If we're saving Agni credentials, should we write the // credentials to the legacy password.dat/etc? _writeProtectedData(); @@ -1613,11 +1646,137 @@ void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> cred, bool sav void LLSecAPIBasicHandler::deleteCredential(LLPointer<LLCredential> cred) { LLSD undefVal; - deleteProtectedData("credential", cred->getGrid()); + deleteProtectedData(DEFAULT_CREDENTIAL_STORAGE, cred->getGrid()); cred->setCredentialData(undefVal, undefVal); _writeProtectedData(); } +// has map of credentials declared as specific storage +bool LLSecAPIBasicHandler::hasCredentialMap(const std::string& storage, const std::string& grid) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD credential = getProtectedData(storage, grid); + + return credential.isMap(); +} + +// Load map of credentials from specified credential store, given the grid +void LLSecAPIBasicHandler::loadCredentialMap(const std::string& storage, const std::string& grid, credential_map_t& credential_map) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD credential = getProtectedData(storage, grid); + if (credential.isMap()) + { + LLSD::map_const_iterator crd_it = credential.beginMap(); + for (; crd_it != credential.endMap(); crd_it++) + { + LLSD::String name = crd_it->first; + const LLSD &link_map = crd_it->second; + LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid); + if (link_map.has("identifier")) + { + LLSD identifier = link_map["identifier"]; + LLSD authenticator; + if (link_map.has("authenticator")) + { + authenticator = link_map["authenticator"]; + } + result->setCredentialData(identifier, authenticator); + } + credential_map[name] = result; + } + } +} + +LLPointer<LLCredential> LLSecAPIBasicHandler::loadFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLPointer<LLSecAPIBasicCredential> result = new LLSecAPIBasicCredential(grid); + + LLSD credential = getProtectedData(storage, grid); + if (credential.isMap() && credential.has(userkey) && credential[userkey].has("identifier")) + { + LLSD identifier = credential[userkey]["identifier"]; + LLSD authenticator; + if (credential[userkey].has("authenticator")) + { + authenticator = credential[userkey]["authenticator"]; + } + result->setCredentialData(identifier, authenticator); + } + + return result; +} + +// add item to map of credentials from specific storage +void LLSecAPIBasicHandler::addToCredentialMap(const std::string& storage, LLPointer<LLCredential> cred, bool save_authenticator) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + std::string user_id = cred->userID(); + LLSD credential = LLSD::emptyMap(); + credential["identifier"] = cred->getIdentifier(); + if (save_authenticator) + { + credential["authenticator"] = cred->getAuthenticator(); + } + LL_DEBUGS("SECAPI") << "Saving Credential " << cred->getGrid() << ":" << cred->userID() << " " << save_authenticator << LL_ENDL; + addToProtectedMap(storage, cred->getGrid(), user_id, credential); + + _writeProtectedData(); +} + +// remove item from map of credentials from specific storage +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, LLPointer<LLCredential> cred) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD undefVal; + removeFromProtectedMap(storage, cred->getGrid(), cred->userID()); + cred->setCredentialData(undefVal, undefVal); + _writeProtectedData(); +} + +// remove item from map of credentials from specific storage +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) +{ + if (storage == DEFAULT_CREDENTIAL_STORAGE) + { + LL_ERRS() << "Storing maps in default, single-items storage is not allowed" << LL_ENDL; + } + + LLSD undefVal; + LLPointer<LLCredential> cred = loadFromCredentialMap(storage, grid, userkey); + removeFromProtectedMap(storage, grid, userkey); + cred->setCredentialData(undefVal, undefVal); + _writeProtectedData(); +} + +// remove item from map of credentials from specific storage +void LLSecAPIBasicHandler::removeCredentialMap(const std::string& storage, const std::string& grid) +{ + deleteProtectedData(storage, grid); + _writeProtectedData(); +} + // load the legacy hash for agni, and decrypt it given the // mac address std::string LLSecAPIBasicHandler::_legacyLoadPassword() @@ -1656,15 +1815,18 @@ std::string LLSecAPIBasicCredential::userID() const } else if ((std::string)mIdentifier["type"] == "agent") { - return (std::string)mIdentifier["first_name"] + "_" + (std::string)mIdentifier["last_name"]; + std::string id = (std::string)mIdentifier["first_name"] + "_" + (std::string)mIdentifier["last_name"]; + LLStringUtil::toLower(id); + return id; } else if ((std::string)mIdentifier["type"] == "account") { - return (std::string)mIdentifier["account_name"]; + std::string id = (std::string)mIdentifier["account_name"]; + LLStringUtil::toLower(id); + return id; } return "unknown"; - } // return a printable user identifier diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h index c35617f564..426b5d392a 100644 --- a/indra/newview/llsechandler_basic.h +++ b/indra/newview/llsechandler_basic.h @@ -211,8 +211,9 @@ class LLSecAPIBasicCredential : public LLCredential public: LLSecAPIBasicCredential(const std::string& grid) : LLCredential(grid) {} virtual ~LLSecAPIBasicCredential() {} - // return a value representing the user id, (could be guid, name, whatever) - virtual std::string userID() const; + // return a value representing the user id, used for server and voice + // (could be guid, name in format "name_resident", whatever) + virtual std::string userID() const; // printible string identifying the credential. virtual std::string asString() const; @@ -246,7 +247,10 @@ public: // exists, it'll be loaded. If not, one will be created (but not // persisted) virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id); - + + // protectedData functions technically should be pretected or private, + // they are not because of llsechandler_basic_test imlementation + // persist data in a protected store virtual void setProtectedData(const std::string& data_type, const std::string& data_id, @@ -259,19 +263,64 @@ public: // delete a protected data item from the store virtual void deleteProtectedData(const std::string& data_type, const std::string& data_id); - + + // persist data in a protected store's map + virtual void addToProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem, + const LLSD& data); + + // remove data from protected store's map + virtual void removeFromProtectedMap(const std::string& data_type, + const std::string& data_id, + const std::string& map_elem); + // credential management routines virtual LLPointer<LLCredential> createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator); - + + // load single credencial from default storage virtual LLPointer<LLCredential> loadCredential(const std::string& grid); + // save credencial to default storage virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator); virtual void deleteCredential(LLPointer<LLCredential> cred); - + + // has map of credentials declared as specific storage + virtual bool hasCredentialMap(const std::string& storage, + const std::string& grid); + + // load map of credentials from specific storage + virtual void loadCredentialMap(const std::string& storage, + const std::string& grid, + credential_map_t& credential_map); + + // load single username from map of credentials from specific storage + virtual LLPointer<LLCredential> loadFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid); + + // add item to map of credentials from specific storage + virtual void addToCredentialMap(const std::string& storage, + LLPointer<LLCredential> cred, + bool save_authenticator); + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + LLPointer<LLCredential> cred); + + // remove item from map of credentials from specific storage + virtual void removeFromCredentialMap(const std::string& storage, + const std::string& grid, + const std::string& userid); + + virtual void removeCredentialMap(const std::string& storage, + const std::string& grid); + + protected: void _readProtectedData(); void _writeProtectedData(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index bef27cfb99..77aa7b36b9 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -236,7 +236,8 @@ LLSLURL LLStartUp::sStartSLURL; static LLPointer<LLCredential> gUserCredential; static std::string gDisplayName; -static BOOL gRememberPassword = TRUE; +static bool gRememberPassword = true; +static bool gRememberUser = true; static U64 gFirstSimHandle = 0; static LLHost gFirstSim; @@ -701,19 +702,23 @@ bool idle_startup() else if (gSavedSettings.getBOOL("AutoLogin")) { // Log into last account - gRememberPassword = TRUE; - gSavedSettings.setBOOL("RememberPassword", TRUE); + gRememberPassword = true; + gRememberUser = true; + gSavedSettings.setBOOL("RememberPassword", TRUE); + gSavedSettings.setBOOL("RememberUser", TRUE); show_connect_box = false; } else if (gSavedSettings.getLLSD("UserLoginInfo").size() == 3) { // Console provided login&password gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); show_connect_box = false; } else { gRememberPassword = gSavedSettings.getBOOL("RememberPassword"); + gRememberUser = gSavedSettings.getBOOL("RememberUser"); show_connect_box = TRUE; } @@ -781,10 +786,7 @@ bool idle_startup() // Show the login dialog login_show(); // connect dialog is already shown, so fill in the names - if (gUserCredential.notNull() && !LLPanelLogin::isCredentialSet()) - { - LLPanelLogin::setFields( gUserCredential, gRememberPassword); - } + LLPanelLogin::populateFields( gUserCredential, gRememberUser, gRememberPassword); LLPanelLogin::giveFocus(); // MAINT-3231 Show first run dialog only for Desura viewer @@ -873,7 +875,7 @@ bool idle_startup() { // TODO if not use viewer auth // Load all the name information out of the login view - LLPanelLogin::getFields(gUserCredential, gRememberPassword); + LLPanelLogin::getFields(gUserCredential, gRememberUser, gRememberPassword); // end TODO // HACK: Try to make not jump on login @@ -885,14 +887,21 @@ bool idle_startup() // STATE_LOGIN_SHOW state if we've gone backwards mLoginStatePastUI = true; - // save the credentials - std::string userid = "unknown"; - if(gUserCredential.notNull()) - { - userid = gUserCredential->userID(); - gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); - } - gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + // save the credentials + std::string userid = "unknown"; + if (gUserCredential.notNull()) + { + userid = gUserCredential->userID(); + if (gRememberUser) + { + gSecAPIHandler->addToCredentialMap("login_list", gUserCredential, gRememberPassword); + // Legacy viewers use this method to store user credentials, newer viewers + // reuse it to be compatible and to remember last session + gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword); + } + } + gSavedSettings.setBOOL("RememberPassword", gRememberPassword); + gSavedSettings.setBOOL("RememberUser", gRememberUser); LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL; gDebugInfo["LoginName"] = userid; diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index f475ab7d66..846a8e62a1 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -69,6 +69,7 @@ #include "llfloaterevent.h" #include "llfloaterflickr.h" #include "llfloaterfonttest.h" +#include "llfloaterforgetuser.h" #include "llfloatergesture.h" #include "llfloatergodtools.h" #include "llfloatergridstatus.h" @@ -235,6 +236,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("experience_search", "floater_experience_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterExperiencePicker>); LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterFontTest>); + LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterForgetUser>); LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGesture>); LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGodTools>); diff --git a/indra/newview/skins/default/xui/en/floater_forget_user.xml b/indra/newview/skins/default/xui/en/floater_forget_user.xml new file mode 100644 index 0000000000..f2e894733f --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_forget_user.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + legacy_header_height="18" + height="258" + layout="topleft" + name="groups" + help_topic="forget_username" + title="REMEMBERED USERNAMES" + width="280"> + <scroll_list + height="173" + layout="topleft" + left="12" + name="user_list" + top="24" + width="256"> + <scroll_list.columns + name="user" + width="248" /> + </scroll_list> + <button + height="20" + label="Forget" + label_selected="Forget" + layout="topleft" + left_delta="90" + name="forget" + top_pad="8" + width="80" /> + <check_box + height="20" + label="Also delete local data for this username" + layout="topleft" + left="15" + name="delete_data" + top_pad="5" + width="260" + initial_value="1" + tooltip="Deletes local files: chat history, last session screenshot, browser cookies, teleport history, toolbar settings, e t c"/> +</floater> diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml index 7759d4fdb2..d601b36ce5 100644 --- a/indra/newview/skins/default/xui/en/panel_login.xml +++ b/indra/newview/skins/default/xui/en/panel_login.xml @@ -57,19 +57,15 @@ combo_editor.prevalidate_callback="ascii" tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine" name="username_combo" - width="232"> + width="206"> <combo_box.combo_editor text_pad_left="8" bg_image_always_focused="true"/> - <combo_box.combo_button - visible="false" /> - <combo_box.drop_down_button - visible="false" /> </combo_box> <line_editor follows="left|top" height="32" - left_pad="-11" + left_pad="15" max_length_chars="16" text_pad_left="8" name="password_edit" @@ -119,36 +115,49 @@ width="120" height="32" left_pad="15" - bottom_delta="0" /> + bottom_delta="0" /> + <text + follows="left|top" + font="SansSerifLarge" + font.style="BOLD" + text_color="EmphasisColor" + height="34" + name="sign_up_text" + left_pad="10" + width="200" + valign="center"> + Sign up + </text> <check_box - control_name="RememberPassword" follows="left|top" font="SansSerifMedium" left="185" - bottom_delta="21" + bottom_delta="21" height="24" label="Remember me" check_button.bottom="3" - name="remember_check" + name="remember_name" + tooltip="Already recorded user can be forgotten from preferences." width="145" /> - <text + <check_box + control_name="RememberPassword" follows="left|top" font="SansSerifMedium" text_color="EmphasisColor" height="16" - name="forgot_password_text" - left="408" + left="408" bottom_delta="0" - width="200"> - Forgotten password - </text> + label="Remember password" + check_button.bottom="3" + name="remember_check" + width="145" /> <combo_box allow_text_entry="false" font="SansSerifTiny" follows="left|top" height="26" left="588" - bottom_delta="10" + bottom_delta="8" max_chars="128" label="Select grid" layout="topleft" @@ -159,12 +168,13 @@ font="SansSerifMedium" text_color="EmphasisColor" height="16" - name="sign_up_text" + name="forgot_password_text" left="778" - bottom_delta="-10" - width="200"> - Sign up - </text> + bottom_delta="-8" + width="120" + halign="center"> + Password help + </text> </layout_panel> <layout_panel height="172" diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml index 8296438d4c..d0518aa245 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml @@ -248,14 +248,27 @@ top_pad="5" width="237"/> <button + follows="top|left" + layout="topleft" + label="Remembered Usernames" + name="remembered_usernames" height="20" - label="Default Creation Permissions" + left="30" + top_pad="16" + width="200"> + <button.commit_callback + function="Pref.RememberedUsernames" /> + </button> + <button + follows="top|left" layout="topleft" + label="Default Creation Permissions" name="default_creation_permissions" + height="20" left="30" - top_pad = "20" - width="250"> - <button.commit_callback - function="Pref.PermsDefault" /> + top_pad="16" + width="200"> + <button.commit_callback + function="Pref.PermsDefault" /> </button> </panel> diff --git a/indra/newview/tests/llsecapi_test.cpp b/indra/newview/tests/llsecapi_test.cpp index d7e87ed52e..a1005c654c 100644 --- a/indra/newview/tests/llsecapi_test.cpp +++ b/indra/newview/tests/llsecapi_test.cpp @@ -60,12 +60,21 @@ LLPointer<LLCertificate> LLSecAPIBasicHandler::getCertificate(X509* openssl_cert LLPointer<LLCertificateChain> LLSecAPIBasicHandler::getCertificateChain(const X509_STORE_CTX* chain) { return NULL; } LLPointer<LLCertificateStore> LLSecAPIBasicHandler::getCertificateStore(const std::string& store_id) { return NULL; } void LLSecAPIBasicHandler::setProtectedData(const std::string& data_type, const std::string& data_id, const LLSD& data) {} +void LLSecAPIBasicHandler::addToProtectedMap(const std::string& data_type, const std::string& data_id, const std::string& map_elem, const LLSD& data) {} +void LLSecAPIBasicHandler::removeFromProtectedMap(const std::string& data_type, const std::string& data_id, const std::string& map_elem) {} LLSD LLSecAPIBasicHandler::getProtectedData(const std::string& data_type, const std::string& data_id) { return LLSD(); } void LLSecAPIBasicHandler::deleteProtectedData(const std::string& data_type, const std::string& data_id) {} LLPointer<LLCredential> LLSecAPIBasicHandler::createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator) { return NULL; } LLPointer<LLCredential> LLSecAPIBasicHandler::loadCredential(const std::string& grid) { return NULL; } void LLSecAPIBasicHandler::saveCredential(LLPointer<LLCredential> cred, bool save_authenticator) {} void LLSecAPIBasicHandler::deleteCredential(LLPointer<LLCredential> cred) {} +bool LLSecAPIBasicHandler::hasCredentialMap(const std::string& storage, const std::string& grid) { return false; } +void LLSecAPIBasicHandler::loadCredentialMap(const std::string& storage, const std::string& grid, credential_map_t& credential_map) {} +LLPointer<LLCredential> LLSecAPIBasicHandler::loadFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) { return NULL; } +void LLSecAPIBasicHandler::addToCredentialMap(const std::string& storage, LLPointer<LLCredential> cred, bool save_authenticator) {} +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, LLPointer<LLCredential> cred) {} +void LLSecAPIBasicHandler::removeFromCredentialMap(const std::string& storage, const std::string& grid, const std::string& userkey) {} +void LLSecAPIBasicHandler::removeCredentialMap(const std::string& storage, const std::string& grid) {} // ------------------------------------------------------------------------------------------- // TUT |