From a1fb89ebb6e6cc89ed301b10305c145da3be295f Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Tue, 23 Nov 2021 17:44:06 -0800
Subject: SL-16365 Viewer adds empty mfa token to login params

---
 indra/newview/lllogininstance.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index e81d2cc082..25182593ce 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -225,6 +225,7 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
 	request_params["id0"] = mSerialNumber;
 	request_params["host_id"] = gSavedSettings.getString("HostID");
 	request_params["extended_errors"] = true; // request message_id and message_args
+	request_params["token"] = "";
 
     // log request_params _before_ adding the credentials   
     LL_DEBUGS("LLLogin") << "Login parameters: " << LLSDOStreamer<LLSDNotationFormatter>(request_params) << LL_ENDL;
-- 
cgit v1.2.3


From d307843dd431de86e6d4c4f3e6fe8eaf946354d4 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Tue, 23 Nov 2021 17:39:37 -0800
Subject: SL-16388 Viewer MFA Implementation

We now present MFA errors to the user during login and prompt them for
an authentication token.
---
 indra/newview/CMakeLists.txt                       |   2 +
 indra/newview/llfloatermfa.cpp                     | 104 +++++++++++++++++++++
 indra/newview/llfloatermfa.h                       |  50 ++++++++++
 indra/newview/lllogininstance.cpp                  |  40 ++++++++
 indra/newview/lllogininstance.h                    |   1 +
 indra/newview/llstartup.cpp                        |   6 +-
 indra/newview/llviewerfloaterreg.cpp               |   2 +
 indra/newview/skins/default/xui/en/floater_mfa.xml |  50 ++++++++++
 8 files changed, 252 insertions(+), 3 deletions(-)
 create mode 100644 indra/newview/llfloatermfa.cpp
 create mode 100644 indra/newview/llfloatermfa.h
 create mode 100644 indra/newview/skins/default/xui/en/floater_mfa.xml

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 1969c498f0..9e6cd48f21 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -271,6 +271,7 @@ set(viewer_SOURCE_FILES
     llfloatermap.cpp
     llfloatermediasettings.cpp
     llfloatermemleak.cpp
+    llfloatermfa.cpp
     llfloatermodelpreview.cpp
     llfloatermodeluploadbase.cpp
     llfloatermyscripts.cpp
@@ -913,6 +914,7 @@ set(viewer_HEADER_FILES
     llfloatermarketplacelistings.h
     llfloatermediasettings.h
     llfloatermemleak.h
+    llfloatermfa.h
     llfloatermodelpreview.h
     llfloatermodeluploadbase.h
     llfloatermyscripts.h
diff --git a/indra/newview/llfloatermfa.cpp b/indra/newview/llfloatermfa.cpp
new file mode 100644
index 0000000000..9fb6788923
--- /dev/null
+++ b/indra/newview/llfloatermfa.cpp
@@ -0,0 +1,104 @@
+/**
+ * @file llfloatermfa.cpp
+ * @brief Multi-Factor Auth token submission dialog
+ *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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 "llfloatermfa.h"
+
+// viewer includes
+#include "llevents.h"
+
+
+LLFloaterMFA::LLFloaterMFA(const LLSD& data)
+:   LLModalDialog("mfa_challenge"),
+    mMessage(data["message"].asStringRef()),
+    mReplyPumpName(data["reply_pump"].asStringRef())
+{
+
+}
+
+LLFloaterMFA::~LLFloaterMFA()
+{
+}
+
+BOOL LLFloaterMFA::postBuild()
+{
+    childSetAction("Continue", onContinue, this);
+    childSetAction("Cancel", onCancel, this);
+
+    if (hasChild("token_prompt"))
+    {
+        // this displays the prompt message
+        LLUICtrl *token_prompt = getChild<LLUICtrl>("token_prompt");
+        token_prompt->setEnabled( FALSE );
+        token_prompt->setFocus(TRUE);
+        token_prompt->setValue(LLSD(mMessage));
+
+        return TRUE;
+    }
+
+    return TRUE;
+}
+
+// static
+void LLFloaterMFA::onContinue( void* userdata )
+{
+    LLFloaterMFA* self = (LLFloaterMFA*) userdata;
+    LL_INFOS("MFA") << "User submits MFA token for challenge." << LL_ENDL;
+
+    std::string token{"8675309"};
+
+    if (self->hasChild("token"))
+    {
+        // this displays the prompt message
+        LLUICtrl *token_ctrl = self->getChild<LLUICtrl>("token");
+
+        token = token_ctrl->getValue().asStringRef();
+    }
+
+    if(self->mReplyPumpName != "")
+    {
+        LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD(token));
+    }
+
+    self->closeFloater(); // destroys this object
+}
+
+// static
+void LLFloaterMFA::onCancel( void* userdata )
+{
+    LLFloaterMFA* self = (LLFloaterMFA*) userdata;
+    LL_INFOS("MFA") << "User cancels MFA challenge attempt." << LL_ENDL;
+
+    if(self->mReplyPumpName != "")
+    {
+        LL_DEBUGS("MFA") << self->mReplyPumpName << LL_ENDL;
+        LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD());
+    }
+
+    // destroys this object
+    self->closeFloater();
+}
diff --git a/indra/newview/llfloatermfa.h b/indra/newview/llfloatermfa.h
new file mode 100644
index 0000000000..c6c79439b8
--- /dev/null
+++ b/indra/newview/llfloatermfa.h
@@ -0,0 +1,50 @@
+/**
+ * @file llfloatermfa.h
+ * @brief Multi-Factor Auth token submission dialog
+ *
+ * $LicenseInfo:firstyear=2003&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, 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_LLFLOATERMFA_H
+#define LL_LLFLOATERMFA_H
+
+#include "llmodaldialog.h"
+
+
+class LLFloaterMFA :
+    public LLModalDialog
+{
+public:
+    LLFloaterMFA(const LLSD& data);
+    virtual ~LLFloaterMFA();
+
+    BOOL postBuild();
+
+    static void onContinue(void* userdata);
+    static void onCancel(void* userdata);
+
+private:
+    std::string mMessage;
+    std::string mReplyPumpName;
+};
+
+#endif // LL_FLOATERMFA_H
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 25182593ce..e380e5a3f4 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -75,6 +75,8 @@ public:
 
 static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback";
 static const char * const TOS_LISTENER_NAME = "lllogininstance_tos";
+static const char * const MFA_REPLY_PUMP = "lllogininstance_mfa_callback";
+static const char * const MFA_LISTENER_NAME = "lllogininstance_mfa";
 
 std::string construct_start_string();
 
@@ -408,6 +410,23 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
                 boost::bind(&LLLoginInstance::syncWithUpdater, this, resp, _1, _2));
         }
     }
+    else if(reason_response == "mfa_challenge")
+    {
+        LL_DEBUGS("LLLogin") << " MFA challenge" << LL_ENDL;
+
+        LLSD data(LLSD::emptyMap());
+        data["message"] = message_response;
+        data["reply_pump"] = MFA_REPLY_PUMP;
+        if (gViewerWindow)
+        {
+            gViewerWindow->setShowProgress(FALSE);
+        }
+        LLFloaterReg::showInstance("message_mfa", data);
+        LLEventPumps::instance().obtain(MFA_REPLY_PUMP)
+            .listen(MFA_LISTENER_NAME, [=](const LLSD& token) {
+                return this->handleMFAResponse(token, "token");
+            });
+    }
     else if(   reason_response == "key"
             || reason_response == "presence"
             || reason_response == "connect"
@@ -502,6 +521,27 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
 	return true;
 }
 
+bool LLLoginInstance::handleMFAResponse(const std::string& token, const std::string& key)
+{
+    if(!token.empty())
+    {
+        LL_INFOS("LLLogin") << "LLLoginInstance::handleMFAResponse: token submitted" << LL_ENDL;
+
+        // Set the request data to true and retry login.
+        mRequestData["params"][key] = token;
+        reconnect();
+    }
+    else
+    {
+        LL_INFOS("LLLogin") << "LLLoginInstance::handleMFAResponse: no token, attemptComplete" << LL_ENDL;
+
+        attemptComplete();
+    }
+
+    LLEventPumps::instance().obtain(MFA_REPLY_PUMP).stopListening(MFA_LISTENER_NAME);
+    return true;
+}
+
 std::string construct_start_string()
 {
 	std::string start;
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
index b759b43474..ce64e9e3be 100644
--- a/indra/newview/lllogininstance.h
+++ b/indra/newview/lllogininstance.h
@@ -84,6 +84,7 @@ private:
 	void syncWithUpdater(ResponsePtr resp, const LLSD& notification, const LLSD& response);
 
 	bool handleTOSResponse(bool v, const std::string& key);
+	bool handleMFAResponse(const std::string& v, const std::string& key);
 
 	void attemptComplete() { mAttemptComplete = true; } // In the future an event?
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index f22be6481a..228d64c17b 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1117,10 +1117,10 @@ bool idle_startup()
 			}
 			else 
 			{
-				if (reason_response != "tos") 
+				if (reason_response != "tos"  && reason_response != "mfa_challenge")
 				{
-					// Don't pop up a notification in the TOS case because
-					// LLFloaterTOS::onCancel() already scolded the user.
+					// Don't pop up a notification in the TOS or MFA cases because
+					// the specialized floater has already scolded the user.
 					std::string error_code;
 					if(response.has("errorcode"))
 					{
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 5a05f89758..603cc00062 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -91,6 +91,7 @@
 #include "llfloatermarketplacelistings.h"
 #include "llfloatermediasettings.h"
 #include "llfloatermemleak.h"
+#include "llfloatermfa.h"
 #include "llfloatermodelpreview.h"
 #include "llfloatermyscripts.h"
 #include "llfloatermyenvironment.h"
@@ -286,6 +287,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("marketplace_validation", "floater_marketplace_validation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceValidation>);
 	LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>);
 	LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>);
+	LLFloaterReg::add("message_mfa", "floater_mfa.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMFA>);
 	LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMove>);
 	LLFloaterReg::add("mute_object_by_name", "floater_mute_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGetBlockedObjectName>);
 	LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMap>);
diff --git a/indra/newview/skins/default/xui/en/floater_mfa.xml b/indra/newview/skins/default/xui/en/floater_mfa.xml
new file mode 100644
index 0000000000..acdfbc82c0
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_mfa.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_minimize="false"
+ height="87"
+ layout="topleft"
+ name="mfa_challenge"
+ help_topic="mfa_challenge"
+ width="480">
+    <text
+     type="string"
+     length="1"
+     bottom="20"
+     follows="top|left"
+     height="15"
+     layout="topleft"
+     left="10"
+     name="token_prompt"
+     top="20">
+        token prompt
+    </text>
+    <text_box
+     allow_text_entry="true"
+     follows="left|top|right"
+     height="19"
+     layout="topleft"
+     left_delta="70"
+     max_chars="16"
+     name="token_entry"
+     top_delta="-4"
+     width="16" />
+    <button
+     follows="top|left"
+     height="20"
+     label="Continue"
+     layout="topleft"
+     left="10"
+     name="Continue"
+     top="50"
+     width="64" />
+    <button
+     follows="top|left"
+     height="20"
+     label="Cancel"
+     layout="topleft"
+     left_pad="5"
+     name="Cancel"
+     top_delta="0"
+     width="64" />
+</floater>
-- 
cgit v1.2.3


From 30cd108c7e4a524c9f17060d5b2f7b4ff193b4b8 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Mon, 6 Dec 2021 16:17:55 -0800
Subject: SL-16388 Viewer MFA Implementation Improvements

token input is now handled and message formatting is improved.
Added beginnings of support for saving slmfa_hash value client side.
---
 indra/newview/llfloatermfa.cpp                     | 27 +++++++++++-----------
 indra/newview/lllogininstance.cpp                  |  1 +
 indra/newview/skins/default/xui/en/floater_mfa.xml | 25 ++++++++++----------
 3 files changed, 28 insertions(+), 25 deletions(-)

diff --git a/indra/newview/llfloatermfa.cpp b/indra/newview/llfloatermfa.cpp
index 9fb6788923..9356605b8c 100644
--- a/indra/newview/llfloatermfa.cpp
+++ b/indra/newview/llfloatermfa.cpp
@@ -46,35 +46,36 @@ LLFloaterMFA::~LLFloaterMFA()
 
 BOOL LLFloaterMFA::postBuild()
 {
-    childSetAction("Continue", onContinue, this);
-    childSetAction("Cancel", onCancel, this);
+    centerOnScreen();
 
-    if (hasChild("token_prompt"))
+    childSetAction("continue_btn", onContinue, this);
+    childSetAction("cancel_btn", onCancel, this);
+    childSetCommitCallback("token_edit", [](LLUICtrl*, void* userdata) { onContinue(userdata);}, this);
+
+    if (hasChild("token_prompt_text"))
     {
         // this displays the prompt message
-        LLUICtrl *token_prompt = getChild<LLUICtrl>("token_prompt");
+        LLUICtrl *token_prompt = getChild<LLUICtrl>("token_prompt_text");
         token_prompt->setEnabled( FALSE );
         token_prompt->setFocus(TRUE);
         token_prompt->setValue(LLSD(mMessage));
-
-        return TRUE;
     }
 
     return TRUE;
 }
 
 // static
-void LLFloaterMFA::onContinue( void* userdata )
+void LLFloaterMFA::onContinue(void* userdata )
 {
-    LLFloaterMFA* self = (LLFloaterMFA*) userdata;
+    LLFloaterMFA* self = static_cast<LLFloaterMFA*>(userdata);
     LL_INFOS("MFA") << "User submits MFA token for challenge." << LL_ENDL;
 
-    std::string token{"8675309"};
+    std::string token;
 
-    if (self->hasChild("token"))
+    if (self->hasChild("token_edit"))
     {
         // this displays the prompt message
-        LLUICtrl *token_ctrl = self->getChild<LLUICtrl>("token");
+        LLUICtrl *token_ctrl = self->getChild<LLUICtrl>("token_edit");
 
         token = token_ctrl->getValue().asStringRef();
     }
@@ -88,9 +89,9 @@ void LLFloaterMFA::onContinue( void* userdata )
 }
 
 // static
-void LLFloaterMFA::onCancel( void* userdata )
+void LLFloaterMFA::onCancel(void* userdata)
 {
-    LLFloaterMFA* self = (LLFloaterMFA*) userdata;
+    LLFloaterMFA* self = static_cast<LLFloaterMFA*>(userdata);
     LL_INFOS("MFA") << "User cancels MFA challenge attempt." << LL_ENDL;
 
     if(self->mReplyPumpName != "")
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index e380e5a3f4..553a8c91ff 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -228,6 +228,7 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
 	request_params["host_id"] = gSavedSettings.getString("HostID");
 	request_params["extended_errors"] = true; // request message_id and message_args
 	request_params["token"] = "";
+	request_params["slmfa_hash"] = "";
 
     // log request_params _before_ adding the credentials   
     LL_DEBUGS("LLLogin") << "Login parameters: " << LLSDOStreamer<LLSDNotationFormatter>(request_params) << LL_ENDL;
diff --git a/indra/newview/skins/default/xui/en/floater_mfa.xml b/indra/newview/skins/default/xui/en/floater_mfa.xml
index acdfbc82c0..361641d313 100644
--- a/indra/newview/skins/default/xui/en/floater_mfa.xml
+++ b/indra/newview/skins/default/xui/en/floater_mfa.xml
@@ -1,42 +1,43 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <floater
+ title="MFA Token Requred"
  legacy_header_height="18"
  can_minimize="false"
- height="87"
+ can_close="false"
+ height="110"
  layout="topleft"
  name="mfa_challenge"
  help_topic="mfa_challenge"
  width="480">
     <text
      type="string"
+     word_wrap="true"
      length="1"
-     bottom="20"
      follows="top|left"
      height="15"
      layout="topleft"
      left="10"
-     name="token_prompt"
+     name="token_prompt_text"
      top="20">
         token prompt
     </text>
-    <text_box
+    <line_editor
      allow_text_entry="true"
      follows="left|top|right"
      height="19"
      layout="topleft"
-     left_delta="70"
+     bottom_delta="40"
      max_chars="16"
-     name="token_entry"
-     top_delta="-4"
-     width="16" />
+     name="token_edit"
+     width="100" />
     <button
      follows="top|left"
      height="20"
      label="Continue"
      layout="topleft"
      left="10"
-     name="Continue"
-     top="50"
+     name="continue_btn"
+     bottom_delta="30"
      width="64" />
     <button
      follows="top|left"
@@ -44,7 +45,7 @@
      label="Cancel"
      layout="topleft"
      left_pad="5"
-     name="Cancel"
-     top_delta="0"
+     name="cancel_btn"
+     bottom_delta="0"
      width="64" />
 </floater>
-- 
cgit v1.2.3


From 6d177898a9a5883ad7939be162e51d9a61d0e0b1 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Mon, 13 Dec 2021 14:58:38 -0800
Subject: SL-16501 SLMFAHash is now saved client side

---
 indra/newview/app_settings/settings_per_account.xml | 11 +++++++++++
 indra/newview/lllogininstance.cpp                   |  2 +-
 indra/newview/llstartup.cpp                         |  5 +++++
 indra/newview/tests/lllogininstance_test.cpp        |  1 +
 4 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index 537744b44c..d7d008689c 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -436,5 +436,16 @@
         <key>Value</key>
         <integer>2</integer>
       </map>
+      <key>SLMFAHash</key>
+      <map>
+        <key>Comment</key>
+        <string>MFA state hash for authentication</string>
+        <key>Persist</key>
+        <integer>1</integer>
+        <key>Type</key>
+        <string>String</string>
+        <key>Value</key>
+        <string></string>
+      </map>
     </map>
 </llsd>
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 553a8c91ff..f19569d429 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -228,7 +228,7 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
 	request_params["host_id"] = gSavedSettings.getString("HostID");
 	request_params["extended_errors"] = true; // request message_id and message_args
 	request_params["token"] = "";
-	request_params["slmfa_hash"] = "";
+	request_params["slmfa_hash"] = gSavedPerAccountSettings.getString("SLMFAHash");
 
     // log request_params _before_ adding the credentials   
     LL_DEBUGS("LLLogin") << "Login parameters: " << LLSDOStreamer<LLSDNotationFormatter>(request_params) << LL_ENDL;
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 228d64c17b..05d17b47bc 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -3605,6 +3605,11 @@ bool process_login_success_response()
 		LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token);
 	}
 
+	if(response.has("slmfa_hash"))
+	{
+		gSavedPerAccountSettings.setString("SLMFAHash", response["slmfa_hash"]);
+	}
+
 	bool success = false;
 	// JC: gesture loading done below, when we have an asset system
 	// in place.  Don't delete/clear gUserCredentials until then.
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
index 8d1956957c..43f0e89222 100644
--- a/indra/newview/tests/lllogininstance_test.cpp
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -190,6 +190,7 @@ std::string LLGridManager::getAppSLURLBase(const std::string& grid_name)
 //-----------------------------------------------------------------------------
 #include "../llviewercontrol.h"
 LLControlGroup gSavedSettings("Global");
+LLControlGroup gSavedPerAccountSettings("PerAccount");
 
 LLControlGroup::LLControlGroup(const std::string& name) :
 	LLInstanceTracker<LLControlGroup, std::string>(name){}
-- 
cgit v1.2.3


From b74dc0e27a09fef55d12e5ea0e22a13ec9ca24e8 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Tue, 14 Dec 2021 09:07:09 -0800
Subject: SL-16388 Viewer MFA fix Duplicate Listener crash when first token
 challenge failed

also cleaned up some xui warnings
---
 indra/newview/lllogininstance.cpp                  | 3 ++-
 indra/newview/skins/default/xui/en/floater_mfa.xml | 2 --
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index f19569d429..902510c294 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -524,6 +524,8 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
 
 bool LLLoginInstance::handleMFAResponse(const std::string& token, const std::string& key)
 {
+    LLEventPumps::instance().obtain(MFA_REPLY_PUMP).stopListening(MFA_LISTENER_NAME);
+
     if(!token.empty())
     {
         LL_INFOS("LLLogin") << "LLLoginInstance::handleMFAResponse: token submitted" << LL_ENDL;
@@ -539,7 +541,6 @@ bool LLLoginInstance::handleMFAResponse(const std::string& token, const std::str
         attemptComplete();
     }
 
-    LLEventPumps::instance().obtain(MFA_REPLY_PUMP).stopListening(MFA_LISTENER_NAME);
     return true;
 }
 
diff --git a/indra/newview/skins/default/xui/en/floater_mfa.xml b/indra/newview/skins/default/xui/en/floater_mfa.xml
index 361641d313..7fd31cd9e2 100644
--- a/indra/newview/skins/default/xui/en/floater_mfa.xml
+++ b/indra/newview/skins/default/xui/en/floater_mfa.xml
@@ -22,12 +22,10 @@
         token prompt
     </text>
     <line_editor
-     allow_text_entry="true"
      follows="left|top|right"
      height="19"
      layout="topleft"
      bottom_delta="40"
-     max_chars="16"
      name="token_edit"
      width="100" />
     <button
-- 
cgit v1.2.3


From 6aa438aa60b08077b4af667ac24e4e3ffbe7c9a9 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Tue, 14 Dec 2021 12:00:03 -0800
Subject: SL-16388 fixed copyright header dates for new MFA floater source
 files

---
 indra/newview/llfloatermfa.cpp | 4 ++--
 indra/newview/llfloatermfa.h   | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/indra/newview/llfloatermfa.cpp b/indra/newview/llfloatermfa.cpp
index 9356605b8c..9eff702a46 100644
--- a/indra/newview/llfloatermfa.cpp
+++ b/indra/newview/llfloatermfa.cpp
@@ -2,9 +2,9 @@
  * @file llfloatermfa.cpp
  * @brief Multi-Factor Auth token submission dialog
  *
- * $LicenseInfo:firstyear=2003&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
  * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2021, 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
diff --git a/indra/newview/llfloatermfa.h b/indra/newview/llfloatermfa.h
index c6c79439b8..9332b35877 100644
--- a/indra/newview/llfloatermfa.h
+++ b/indra/newview/llfloatermfa.h
@@ -2,9 +2,9 @@
  * @file llfloatermfa.h
  * @brief Multi-Factor Auth token submission dialog
  *
- * $LicenseInfo:firstyear=2003&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2021&license=viewerlgpl$
  * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
+ * Copyright (C) 2021, 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
-- 
cgit v1.2.3


From ea2ae3769f7edf42d8c3816d9b4bd039f80e4b03 Mon Sep 17 00:00:00 2001
From: "Brad Kittenbrink (Brad Linden)" <brad@lindenlab.com>
Date: Tue, 14 Dec 2021 12:50:33 -0800
Subject: SL-16388 floater_mfa line wrapping fix when the server message is
 very long

---
 indra/newview/skins/default/xui/en/floater_mfa.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/skins/default/xui/en/floater_mfa.xml b/indra/newview/skins/default/xui/en/floater_mfa.xml
index 7fd31cd9e2..a649cc6d47 100644
--- a/indra/newview/skins/default/xui/en/floater_mfa.xml
+++ b/indra/newview/skins/default/xui/en/floater_mfa.xml
@@ -8,7 +8,7 @@
  layout="topleft"
  name="mfa_challenge"
  help_topic="mfa_challenge"
- width="480">
+ width="550">
     <text
      type="string"
      word_wrap="true"
-- 
cgit v1.2.3


From 95e2f6286c140b6d3a7562a7e73f70d0ab60685b Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Wed, 15 Dec 2021 17:01:48 -0800
Subject: SL-16388 Improvements to llfloatermfa.cpp from code review

---
 indra/newview/llfloatermfa.cpp | 38 +++++++++++++++++---------------------
 1 file changed, 17 insertions(+), 21 deletions(-)

diff --git a/indra/newview/llfloatermfa.cpp b/indra/newview/llfloatermfa.cpp
index 9eff702a46..7710817c23 100644
--- a/indra/newview/llfloatermfa.cpp
+++ b/indra/newview/llfloatermfa.cpp
@@ -52,14 +52,13 @@ BOOL LLFloaterMFA::postBuild()
     childSetAction("cancel_btn", onCancel, this);
     childSetCommitCallback("token_edit", [](LLUICtrl*, void* userdata) { onContinue(userdata);}, this);
 
-    if (hasChild("token_prompt_text"))
-    {
-        // this displays the prompt message
-        LLUICtrl *token_prompt = getChild<LLUICtrl>("token_prompt_text");
-        token_prompt->setEnabled( FALSE );
-        token_prompt->setFocus(TRUE);
-        token_prompt->setValue(LLSD(mMessage));
-    }
+    // this displays the prompt message
+    LLUICtrl *token_prompt = getChild<LLUICtrl>("token_prompt_text");
+    token_prompt->setEnabled( FALSE );
+    token_prompt->setValue(LLSD(mMessage));
+
+    LLUICtrl *token_edit = getChild<LLUICtrl>("token_edit");
+    token_edit->setFocus(TRUE);
 
     return TRUE;
 }
@@ -68,24 +67,21 @@ BOOL LLFloaterMFA::postBuild()
 void LLFloaterMFA::onContinue(void* userdata )
 {
     LLFloaterMFA* self = static_cast<LLFloaterMFA*>(userdata);
-    LL_INFOS("MFA") << "User submits MFA token for challenge." << LL_ENDL;
 
-    std::string token;
+    LLUICtrl *token_ctrl = self->getChild<LLUICtrl>("token_edit");
 
-    if (self->hasChild("token_edit"))
-    {
-        // this displays the prompt message
-        LLUICtrl *token_ctrl = self->getChild<LLUICtrl>("token_edit");
+    std::string token(token_ctrl->getValue().asStringRef());
 
-        token = token_ctrl->getValue().asStringRef();
-    }
-
-    if(self->mReplyPumpName != "")
+    if (!token.empty())
     {
-        LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD(token));
-    }
+        LL_INFOS("MFA") << "User submits MFA token for challenge." << LL_ENDL;
+        if(self->mReplyPumpName != "")
+        {
+            LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD(token));
+        }
 
-    self->closeFloater(); // destroys this object
+        self->closeFloater(); // destroys this object
+    }
 }
 
 // static
-- 
cgit v1.2.3


From b37699acaa8a530a7e06088448aaa7139855721b Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Tue, 4 Jan 2022 10:20:14 -0800
Subject: DRTVWR-550 setting viewer channel name for project build

---
 BuildParams | 1 +
 1 file changed, 1 insertion(+)

diff --git a/BuildParams b/BuildParams
index 27ae40767a..12346d0378 100644
--- a/BuildParams
+++ b/BuildParams
@@ -35,6 +35,7 @@ buildscripts_shared_more_NAMEs="build_secrets build_variables git_hooks"
 # should use a viewer_channel that begins with "Second Life"
 ################################################################
 viewer_channel = "Second Life Test"
+DRTVWR-550-mfa.viewer_channel = "Second Life Project MFA"
 
 ################################################################
 # Special packaging parameters.
-- 
cgit v1.2.3


From 262b5cdd1881eadb13d7572659597acb3b6e375c Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Wed, 5 Jan 2022 13:39:37 -0800
Subject: DRTVWR-550 correct formatting of branch variable name for
 viewer_channel

---
 BuildParams | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/BuildParams b/BuildParams
index 12346d0378..149f0e21a1 100644
--- a/BuildParams
+++ b/BuildParams
@@ -35,7 +35,7 @@ buildscripts_shared_more_NAMEs="build_secrets build_variables git_hooks"
 # should use a viewer_channel that begins with "Second Life"
 ################################################################
 viewer_channel = "Second Life Test"
-DRTVWR-550-mfa.viewer_channel = "Second Life Project MFA"
+DRTVWR_550_mfa.viewer_channel = "Second Life Project MFA"
 
 ################################################################
 # Special packaging parameters.
-- 
cgit v1.2.3


From 90dbc4eaf7d30346dc658a32e80f4e9ad5841c2b Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Wed, 5 Jan 2022 15:05:39 -0800
Subject: DRTVWR-550 oops, more correct formatting for branch viewer_channel
 variable naming.

---
 BuildParams | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/BuildParams b/BuildParams
index 149f0e21a1..323ba9245e 100644
--- a/BuildParams
+++ b/BuildParams
@@ -35,7 +35,7 @@ buildscripts_shared_more_NAMEs="build_secrets build_variables git_hooks"
 # should use a viewer_channel that begins with "Second Life"
 ################################################################
 viewer_channel = "Second Life Test"
-DRTVWR_550_mfa.viewer_channel = "Second Life Project MFA"
+DRTVWR_550_mfa_viewer_channel = "Second Life Project MFA"
 
 ################################################################
 # Special packaging parameters.
-- 
cgit v1.2.3


From 96a6d21086353639d48befa20d86c97d2fd2dddb Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Fri, 14 Jan 2022 22:24:52 -0800
Subject: SL-16514 store mfa hash in protected data using LLSecAPIBasicHandler

---
 indra/newview/app_settings/settings_per_account.xml |  2 +-
 indra/newview/lllogininstance.cpp                   | 15 ++++++++++++---
 indra/newview/llstartup.cpp                         |  5 ++++-
 indra/newview/tests/lllogininstance_test.cpp        |  9 +++++++++
 4 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index d7d008689c..7d4af7db7f 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -441,7 +441,7 @@
         <key>Comment</key>
         <string>MFA state hash for authentication</string>
         <key>Persist</key>
-        <integer>1</integer>
+        <integer>0</integer>
         <key>Type</key>
         <string>String</string>
         <key>Value</key>
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 902510c294..a4c001ad8b 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -228,11 +228,20 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
 	request_params["host_id"] = gSavedSettings.getString("HostID");
 	request_params["extended_errors"] = true; // request message_id and message_args
 	request_params["token"] = "";
-	request_params["slmfa_hash"] = gSavedPerAccountSettings.getString("SLMFAHash");
 
-    // log request_params _before_ adding the credentials   
+    // log request_params _before_ adding the credentials or sensitive MFA hash data
     LL_DEBUGS("LLLogin") << "Login parameters: " << LLSDOStreamer<LLSDNotationFormatter>(request_params) << LL_ENDL;
 
+    std::string slmfa_hash = gSavedPerAccountSettings.getString("SLMFAHash"); //non-persistent to enable testing
+    if(slmfa_hash.empty())
+    {
+        LLPointer<LLSecAPIHandler> basic_secure_store = getSecHandler(BASIC_SECHANDLER);
+        std::string grid(LLGridManager::getInstance()->getGridId());
+        slmfa_hash = basic_secure_store->getProtectedData("slmfa_hash", grid).asString();
+    }
+
+    request_params["slmfa_hash"] = slmfa_hash;
+
     // Copy the credentials into the request after logging the rest
     LLSD credentials(user_credential->getLoginParams());
     for (LLSD::map_const_iterator it = credentials.beginMap();
@@ -417,7 +426,7 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
 
         LLSD data(LLSD::emptyMap());
         data["message"] = message_response;
-        data["reply_pump"] = MFA_REPLY_PUMP;
+        data["reply_pump"] = MFA_REPLY_PUMP
         if (gViewerWindow)
         {
             gViewerWindow->setShowProgress(FALSE);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 8e81843153..956ed2d212 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -133,6 +133,7 @@
 #include "llproxy.h"
 #include "llproductinforequest.h"
 #include "llqueryflags.h"
+#include "llsecapi.h"
 #include "llselectmgr.h"
 #include "llsky.h"
 #include "llstatview.h"
@@ -3599,7 +3600,9 @@ bool process_login_success_response()
 
 	if(response.has("slmfa_hash"))
 	{
-		gSavedPerAccountSettings.setString("SLMFAHash", response["slmfa_hash"]);
+		LLPointer<LLSecAPIHandler> basic_secure_store = getSecHandler(BASIC_SECHANDLER);
+		std::string grid(LLGridManager::getInstance()->getGridId());
+		basic_secure_store->setProtectedData("slmfa_hash", grid, response["slmfa_hash"]);
 	}
 
 	bool success = false;
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
index 43f0e89222..9253516411 100644
--- a/indra/newview/tests/lllogininstance_test.cpp
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -186,6 +186,15 @@ std::string LLGridManager::getAppSLURLBase(const std::string& grid_name)
 {
 	return "myappslurl";
 }
+std::string LLGridManager::getGridId(const std::string& grid)
+{
+    return std::string();
+}
+
+LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type)
+{
+    return nullptr;
+}
 
 //-----------------------------------------------------------------------------
 #include "../llviewercontrol.h"
-- 
cgit v1.2.3


From 990bee7ee227c947cc5e133ff0818c347b404e9d Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Fri, 14 Jan 2022 22:38:45 -0800
Subject: SL-16654 simplify MFA token prompt UI to use notifications instead of
 new custom floater.

---
 indra/newview/CMakeLists.txt                       |   2 -
 indra/newview/llfloatermfa.cpp                     | 101 ---------------------
 indra/newview/llfloatermfa.h                       |  50 ----------
 indra/newview/lllogininstance.cpp                  |  52 ++++-------
 indra/newview/lllogininstance.h                    |   1 -
 indra/newview/llviewerfloaterreg.cpp               |   2 -
 .../newview/skins/default/xui/en/notifications.xml |  21 +++++
 indra/newview/skins/default/xui/en/strings.xml     |   9 +-
 8 files changed, 49 insertions(+), 189 deletions(-)
 delete mode 100644 indra/newview/llfloatermfa.cpp
 delete mode 100644 indra/newview/llfloatermfa.h

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 6c976e3f2d..5a06106de3 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -275,7 +275,6 @@ set(viewer_SOURCE_FILES
     llfloatermap.cpp
     llfloatermediasettings.cpp
     llfloatermemleak.cpp
-    llfloatermfa.cpp
     llfloatermodelpreview.cpp
     llfloatermodeluploadbase.cpp
     llfloatermyscripts.cpp
@@ -919,7 +918,6 @@ set(viewer_HEADER_FILES
     llfloatermarketplacelistings.h
     llfloatermediasettings.h
     llfloatermemleak.h
-    llfloatermfa.h
     llfloatermodelpreview.h
     llfloatermodeluploadbase.h
     llfloatermyscripts.h
diff --git a/indra/newview/llfloatermfa.cpp b/indra/newview/llfloatermfa.cpp
deleted file mode 100644
index 7710817c23..0000000000
--- a/indra/newview/llfloatermfa.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * @file llfloatermfa.cpp
- * @brief Multi-Factor Auth token submission dialog
- *
- * $LicenseInfo:firstyear=2021&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2021, 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 "llfloatermfa.h"
-
-// viewer includes
-#include "llevents.h"
-
-
-LLFloaterMFA::LLFloaterMFA(const LLSD& data)
-:   LLModalDialog("mfa_challenge"),
-    mMessage(data["message"].asStringRef()),
-    mReplyPumpName(data["reply_pump"].asStringRef())
-{
-
-}
-
-LLFloaterMFA::~LLFloaterMFA()
-{
-}
-
-BOOL LLFloaterMFA::postBuild()
-{
-    centerOnScreen();
-
-    childSetAction("continue_btn", onContinue, this);
-    childSetAction("cancel_btn", onCancel, this);
-    childSetCommitCallback("token_edit", [](LLUICtrl*, void* userdata) { onContinue(userdata);}, this);
-
-    // this displays the prompt message
-    LLUICtrl *token_prompt = getChild<LLUICtrl>("token_prompt_text");
-    token_prompt->setEnabled( FALSE );
-    token_prompt->setValue(LLSD(mMessage));
-
-    LLUICtrl *token_edit = getChild<LLUICtrl>("token_edit");
-    token_edit->setFocus(TRUE);
-
-    return TRUE;
-}
-
-// static
-void LLFloaterMFA::onContinue(void* userdata )
-{
-    LLFloaterMFA* self = static_cast<LLFloaterMFA*>(userdata);
-
-    LLUICtrl *token_ctrl = self->getChild<LLUICtrl>("token_edit");
-
-    std::string token(token_ctrl->getValue().asStringRef());
-
-    if (!token.empty())
-    {
-        LL_INFOS("MFA") << "User submits MFA token for challenge." << LL_ENDL;
-        if(self->mReplyPumpName != "")
-        {
-            LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD(token));
-        }
-
-        self->closeFloater(); // destroys this object
-    }
-}
-
-// static
-void LLFloaterMFA::onCancel(void* userdata)
-{
-    LLFloaterMFA* self = static_cast<LLFloaterMFA*>(userdata);
-    LL_INFOS("MFA") << "User cancels MFA challenge attempt." << LL_ENDL;
-
-    if(self->mReplyPumpName != "")
-    {
-        LL_DEBUGS("MFA") << self->mReplyPumpName << LL_ENDL;
-        LLEventPumps::instance().obtain(self->mReplyPumpName).post(LLSD());
-    }
-
-    // destroys this object
-    self->closeFloater();
-}
diff --git a/indra/newview/llfloatermfa.h b/indra/newview/llfloatermfa.h
deleted file mode 100644
index 9332b35877..0000000000
--- a/indra/newview/llfloatermfa.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * @file llfloatermfa.h
- * @brief Multi-Factor Auth token submission dialog
- *
- * $LicenseInfo:firstyear=2021&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2021, 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_LLFLOATERMFA_H
-#define LL_LLFLOATERMFA_H
-
-#include "llmodaldialog.h"
-
-
-class LLFloaterMFA :
-    public LLModalDialog
-{
-public:
-    LLFloaterMFA(const LLSD& data);
-    virtual ~LLFloaterMFA();
-
-    BOOL postBuild();
-
-    static void onContinue(void* userdata);
-    static void onCancel(void* userdata);
-
-private:
-    std::string mMessage;
-    std::string mReplyPumpName;
-};
-
-#endif // LL_FLOATERMFA_H
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index a4c001ad8b..2b1dbc869a 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -75,8 +75,6 @@ public:
 
 static const char * const TOS_REPLY_PUMP = "lllogininstance_tos_callback";
 static const char * const TOS_LISTENER_NAME = "lllogininstance_tos";
-static const char * const MFA_REPLY_PUMP = "lllogininstance_mfa_callback";
-static const char * const MFA_LISTENER_NAME = "lllogininstance_mfa";
 
 std::string construct_start_string();
 
@@ -424,18 +422,30 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
     {
         LL_DEBUGS("LLLogin") << " MFA challenge" << LL_ENDL;
 
-        LLSD data(LLSD::emptyMap());
-        data["message"] = message_response;
-        data["reply_pump"] = MFA_REPLY_PUMP
         if (gViewerWindow)
         {
             gViewerWindow->setShowProgress(FALSE);
         }
-        LLFloaterReg::showInstance("message_mfa", data);
-        LLEventPumps::instance().obtain(MFA_REPLY_PUMP)
-            .listen(MFA_LISTENER_NAME, [=](const LLSD& token) {
-                return this->handleMFAResponse(token, "token");
-            });
+
+        LLSD args(llsd::map( "MESSAGE", LLTrans::getString(response["message_id"]) ));
+        LLSD payload;
+        LLNotificationsUtil::add("PromptMFAToken", args, payload, [=](LLSD const & notif, LLSD const & response) {
+            bool continue_clicked = response["continue"].asBoolean();
+            LLSD token = response["token"];
+            LL_DEBUGS("LLLogin") << "PromptMFAToken: response: " << response << " continue_clicked" << continue_clicked << LL_ENDL;
+
+            if (continue_clicked && !token.asString().empty())
+            {
+                LL_INFOS("LLLogin") << "PromptMFAToken: token submitted" << LL_ENDL;
+
+                // Set the request data to true and retry login.
+                mRequestData["params"]["token"] = token;
+                reconnect();
+            } else {
+                LL_INFOS("LLLogin") << "PromptMFAToken: no token, attemptComplete" << LL_ENDL;
+                attemptComplete();
+            }
+        });
     }
     else if(   reason_response == "key"
             || reason_response == "presence"
@@ -531,28 +541,6 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
 	return true;
 }
 
-bool LLLoginInstance::handleMFAResponse(const std::string& token, const std::string& key)
-{
-    LLEventPumps::instance().obtain(MFA_REPLY_PUMP).stopListening(MFA_LISTENER_NAME);
-
-    if(!token.empty())
-    {
-        LL_INFOS("LLLogin") << "LLLoginInstance::handleMFAResponse: token submitted" << LL_ENDL;
-
-        // Set the request data to true and retry login.
-        mRequestData["params"][key] = token;
-        reconnect();
-    }
-    else
-    {
-        LL_INFOS("LLLogin") << "LLLoginInstance::handleMFAResponse: no token, attemptComplete" << LL_ENDL;
-
-        attemptComplete();
-    }
-
-    return true;
-}
-
 std::string construct_start_string()
 {
 	std::string start;
diff --git a/indra/newview/lllogininstance.h b/indra/newview/lllogininstance.h
index ce64e9e3be..b759b43474 100644
--- a/indra/newview/lllogininstance.h
+++ b/indra/newview/lllogininstance.h
@@ -84,7 +84,6 @@ private:
 	void syncWithUpdater(ResponsePtr resp, const LLSD& notification, const LLSD& response);
 
 	bool handleTOSResponse(bool v, const std::string& key);
-	bool handleMFAResponse(const std::string& v, const std::string& key);
 
 	void attemptComplete() { mAttemptComplete = true; } // In the future an event?
 
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 677b55e49f..62d73063aa 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -92,7 +92,6 @@
 #include "llfloatermarketplacelistings.h"
 #include "llfloatermediasettings.h"
 #include "llfloatermemleak.h"
-#include "llfloatermfa.h"
 #include "llfloatermodelpreview.h"
 #include "llfloatermyscripts.h"
 #include "llfloatermyenvironment.h"
@@ -289,7 +288,6 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("marketplace_validation", "floater_marketplace_validation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMarketplaceValidation>);
 	LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>);
 	LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterTOS>);
-	LLFloaterReg::add("message_mfa", "floater_mfa.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMFA>);
 	LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMove>);
 	LLFloaterReg::add("mute_object_by_name", "floater_mute_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGetBlockedObjectName>);
 	LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterMap>);
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index d4f71fb370..b3c8f5f477 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -11778,4 +11778,25 @@ Unable to load the track from [TRACK1] into [TRACK2].
   <tag>fail</tag>
   </notification>
   
+  <notification
+   icon="alertmodal.tga"
+   label="Prompt for MFA Token"
+   name="PromptMFAToken"
+   type="alertmodal">
+    [MESSAGE]
+    <tag>confirm</tag>
+    <form name="form">
+      <input name="token" type="text" width="400" />
+      <button
+       default="true"
+       index="0"
+       name="continue"
+       text="Continue"/>
+      <button
+       index="1"
+       name="cancel"
+       text="Cancel"/>
+    </form>
+  </notification>
+
 </notifications>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index f26ee06e6b..0f045bd19c 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -192,7 +192,14 @@ Please try logging in again in a minute.</string>
 Please try logging in again in a minute.</string>
 	<string name="LoginFailedLoggingOutSession">The system has begun logging out your last session.
 Please try logging in again in a minute.</string>
-
+        <string name="LoginFailedAuthenticationMFARequired">To continue logging in, enter a new token from your multifactor authentication app.
+If you feel this is an error, please contact support@secondlife.com</string>
+	<string name="LoginFailedAuthenticationFailedMFA">Sorry! We couldn't log you in.
+Please check to make sure you entered the right
+    * Username (like bobsmith12 or steller.sunshine)
+    * Password
+    * Token
+Also, please make sure your Caps Lock key is off.</string>
 
 	<!-- Disconnection -->
 	<string name="AgentLostConnection">This region may be experiencing trouble.  Please check your connection to the Internet.</string>
-- 
cgit v1.2.3


From 0f9d4dddf0eac917c7433d0a6500494f98e0a1a6 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Fri, 14 Jan 2022 22:56:54 -0800
Subject: DRTVWR-550 unbreak debug build linking on DARWIN.  -d suffux libs
 havent existed for a while

---
 indra/cmake/Boost.cmake | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake
index 06a7ab6d75..26604d4913 100644
--- a/indra/cmake/Boost.cmake
+++ b/indra/cmake/Boost.cmake
@@ -103,28 +103,28 @@ else (USESYSTEMLIBS)
   elseif (DARWIN)
     set(BOOST_CONTEXT_LIBRARY
         optimized boost_context-mt${addrsfx}
-        debug boost_context-mt${addrsfx}-d)
+        debug boost_context-mt${addrsfx})
     set(BOOST_FIBER_LIBRARY
         optimized boost_fiber-mt${addrsfx}
-        debug boost_fiber-mt${addrsfx}-d)
+        debug boost_fiber-mt${addrsfx})
     set(BOOST_FILESYSTEM_LIBRARY
         optimized boost_filesystem-mt${addrsfx}
-        debug boost_filesystem-mt${addrsfx}-d)
+        debug boost_filesystem-mt${addrsfx})
     set(BOOST_PROGRAM_OPTIONS_LIBRARY
         optimized boost_program_options-mt${addrsfx}
-        debug boost_program_options-mt${addrsfx}-d)
+        debug boost_program_options-mt${addrsfx})
     set(BOOST_REGEX_LIBRARY
         optimized boost_regex-mt${addrsfx}
-        debug boost_regex-mt${addrsfx}-d)
+        debug boost_regex-mt${addrsfx})
     set(BOOST_SIGNALS_LIBRARY
         optimized boost_signals-mt${addrsfx}
-        debug boost_signals-mt${addrsfx}-d)
+        debug boost_signals-mt${addrsfx})
     set(BOOST_SYSTEM_LIBRARY
         optimized boost_system-mt${addrsfx}
-        debug boost_system-mt${addrsfx}-d)
+        debug boost_system-mt${addrsfx})
     set(BOOST_THREAD_LIBRARY
         optimized boost_thread-mt${addrsfx}
-        debug boost_thread-mt${addrsfx}-d)
+        debug boost_thread-mt${addrsfx})
   endif (WINDOWS)
 endif (USESYSTEMLIBS)
 
-- 
cgit v1.2.3


From b937e816e5722c54e7fbee4f471ced282b7472cb Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Tue, 18 Jan 2022 17:30:46 -0800
Subject: DRTVWR-550 moved viewer channel value out of BuildParams and into TC
 parameters

---
 BuildParams | 1 -
 1 file changed, 1 deletion(-)

diff --git a/BuildParams b/BuildParams
index 323ba9245e..27ae40767a 100644
--- a/BuildParams
+++ b/BuildParams
@@ -35,7 +35,6 @@ buildscripts_shared_more_NAMEs="build_secrets build_variables git_hooks"
 # should use a viewer_channel that begins with "Second Life"
 ################################################################
 viewer_channel = "Second Life Test"
-DRTVWR_550_mfa_viewer_channel = "Second Life Project MFA"
 
 ################################################################
 # Special packaging parameters.
-- 
cgit v1.2.3


From 8422183958a54e49c230bf85743336e0dd4dff71 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Fri, 4 Feb 2022 14:03:05 -0800
Subject: Related to fix for SL-16792, standardize on naming the filed simply
 mfa_hash end-to-end to avoid confusion

---
 indra/newview/app_settings/settings_per_account.xml | 2 +-
 indra/newview/lllogininstance.cpp                   | 8 ++++----
 indra/newview/llstartup.cpp                         | 4 ++--
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index 7d4af7db7f..c45e841b94 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -436,7 +436,7 @@
         <key>Value</key>
         <integer>2</integer>
       </map>
-      <key>SLMFAHash</key>
+      <key>MFAHash</key>
       <map>
         <key>Comment</key>
         <string>MFA state hash for authentication</string>
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 2b1dbc869a..06dbf97e51 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -230,15 +230,15 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
     // log request_params _before_ adding the credentials or sensitive MFA hash data
     LL_DEBUGS("LLLogin") << "Login parameters: " << LLSDOStreamer<LLSDNotationFormatter>(request_params) << LL_ENDL;
 
-    std::string slmfa_hash = gSavedPerAccountSettings.getString("SLMFAHash"); //non-persistent to enable testing
-    if(slmfa_hash.empty())
+    std::string mfa_hash = gSavedPerAccountSettings.getString("MFAHash"); //non-persistent to enable testing
+    if(mfa_hash.empty())
     {
         LLPointer<LLSecAPIHandler> basic_secure_store = getSecHandler(BASIC_SECHANDLER);
         std::string grid(LLGridManager::getInstance()->getGridId());
-        slmfa_hash = basic_secure_store->getProtectedData("slmfa_hash", grid).asString();
+        mfa_hash = basic_secure_store->getProtectedData("mfa_hash", grid).asString();
     }
 
-    request_params["slmfa_hash"] = slmfa_hash;
+    request_params["mfa_hash"] = mfa_hash;
 
     // Copy the credentials into the request after logging the rest
     LLSD credentials(user_credential->getLoginParams());
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 956ed2d212..b85c01a1f0 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -3598,11 +3598,11 @@ bool process_login_success_response()
 		LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token);
 	}
 
-	if(response.has("slmfa_hash"))
+	if(response.has("mfa_hash"))
 	{
 		LLPointer<LLSecAPIHandler> basic_secure_store = getSecHandler(BASIC_SECHANDLER);
 		std::string grid(LLGridManager::getInstance()->getGridId());
-		basic_secure_store->setProtectedData("slmfa_hash", grid, response["slmfa_hash"]);
+		basic_secure_store->setProtectedData("mfa_hash", grid, response["mfa_hash"]);
 	}
 
 	bool success = false;
-- 
cgit v1.2.3


From d7a15a63ff3961937cc6152d8fb22d767bb6a1a6 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Fri, 18 Feb 2022 14:30:57 -0800
Subject: SL-16869 Removed unused LoginFailedAuthenticationFailedMFA message
 id.

---
 indra/newview/skins/default/xui/en/strings.xml | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 0f045bd19c..c62b57c585 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -194,12 +194,6 @@ Please try logging in again in a minute.</string>
 Please try logging in again in a minute.</string>
         <string name="LoginFailedAuthenticationMFARequired">To continue logging in, enter a new token from your multifactor authentication app.
 If you feel this is an error, please contact support@secondlife.com</string>
-	<string name="LoginFailedAuthenticationFailedMFA">Sorry! We couldn't log you in.
-Please check to make sure you entered the right
-    * Username (like bobsmith12 or steller.sunshine)
-    * Password
-    * Token
-Also, please make sure your Caps Lock key is off.</string>
 
 	<!-- Disconnection -->
 	<string name="AgentLostConnection">This region may be experiencing trouble.  Please check your connection to the Internet.</string>
-- 
cgit v1.2.3


From 65a19a690c1fcc7d6e7c7449439eb2d93df3bf18 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Mon, 7 Mar 2022 00:10:00 -0800
Subject: Match error message updated on server side for SL-16869

---
 indra/newview/skins/default/xui/en/strings.xml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index c62b57c585..866196a760 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -133,6 +133,7 @@ http://secondlife.com/viewer-access-faq</string>
 Please check to make sure you entered the right
     * Username (like bobsmith12 or steller.sunshine)
     * Password
+    * Second Factor Token (if enabled)
 Also, please make sure your Caps Lock key is off.</string>
 	<string name="LoginFailedPasswordChanged">As a security precaution your password has been changed.
 Please go to your account page at http://secondlife.com/password
-- 
cgit v1.2.3


From 40b80251e48d5f0ae3695d9019261f9e472f3e16 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Mon, 7 Mar 2022 00:15:59 -0800
Subject: SL-16825 saving of mfa_hash data now obeys the 'Remember Me' setting

---
 indra/newview/llstartup.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index b85c01a1f0..27ec8214f6 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -3598,7 +3598,7 @@ bool process_login_success_response()
 		LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token);
 	}
 
-	if(response.has("mfa_hash"))
+	if(response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser"))
 	{
 		LLPointer<LLSecAPIHandler> basic_secure_store = getSecHandler(BASIC_SECHANDLER);
 		std::string grid(LLGridManager::getInstance()->getGridId());
-- 
cgit v1.2.3


From 87b494f585f14d6ecc8dbe2d0ce26ab79b62ce30 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Tue, 8 Mar 2022 17:29:45 -0800
Subject: Oops, forgot the other half of SL-16825 fix.  need to check both
 "RememberUser" and "RememberPassword" settings

---
 indra/newview/llstartup.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index d625ef2539..64e6042047 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -3617,7 +3617,9 @@ bool process_login_success_response()
 		LLViewerMedia::getInstance()->openIDSetup(openid_url, openid_token);
 	}
 
-	if(response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser"))
+
+	// Only save mfa_hash for future logins if the user wants their info remembered.
+	if(response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser") && gSavedSettings.getBOOL("RememberPassword"))
 	{
 		LLPointer<LLSecAPIHandler> basic_secure_store = getSecHandler(BASIC_SECHANDLER);
 		std::string grid(LLGridManager::getInstance()->getGridId());
-- 
cgit v1.2.3


From 9d1891aff1a350847b2242f341addf04b802929b Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Tue, 8 Mar 2022 17:48:49 -0800
Subject: SL-16888 debug setting MFAHash value now gets saved to mfa_hash
 secure storage as well.

---
 indra/newview/lllogininstance.cpp | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 06dbf97e51..fd186fcddc 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -231,11 +231,19 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
     LL_DEBUGS("LLLogin") << "Login parameters: " << LLSDOStreamer<LLSDNotationFormatter>(request_params) << LL_ENDL;
 
     std::string mfa_hash = gSavedPerAccountSettings.getString("MFAHash"); //non-persistent to enable testing
-    if(mfa_hash.empty())
+    LLPointer<LLSecAPIHandler> basic_secure_store = getSecHandler(BASIC_SECHANDLER);
+    std::string grid(LLGridManager::getInstance()->getGridId());
+    if (basic_secure_store)
     {
-        LLPointer<LLSecAPIHandler> basic_secure_store = getSecHandler(BASIC_SECHANDLER);
-        std::string grid(LLGridManager::getInstance()->getGridId());
-        mfa_hash = basic_secure_store->getProtectedData("mfa_hash", grid).asString();
+        if (mfa_hash.empty())
+        {
+            mfa_hash = basic_secure_store->getProtectedData("mfa_hash", grid).asString();
+        }
+        else
+        {
+            // SL-16888 the mfa_hash is being overridden for testing so save it for consistency for future login requests
+            basic_secure_store->setProtectedData("mfa_hash", grid, mfa_hash);
+        }
     }
 
     request_params["mfa_hash"] = mfa_hash;
-- 
cgit v1.2.3


From 27b02cac65cd18d19e84298576936b480e0d3125 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Wed, 9 Mar 2022 10:11:40 -0800
Subject: Fix DRTVWR-550 TeamCity build.  codesigning retry block had some
 leftover python2 syntax

---
 indra/newview/viewer_manifest.py | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index ae3ed56b3d..1809b707ef 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -1313,9 +1313,8 @@ class DarwinManifest(ViewerManifest):
                         ]
                     for attempt in range(3):
                         if attempt: # second or subsequent iteration
-                            print >> sys.stderr, \
-                                ("codesign failed, waiting %d seconds before retrying" %
-                                 sign_retry_wait)
+                            print("codesign failed, waiting {:d} seconds before retrying".format(sign_retry_wait),
+                                  file=sys.stderr)
                             time.sleep(sign_retry_wait)
                             sign_retry_wait*=2
 
-- 
cgit v1.2.3


From 6bdd744d78f2040767abe57afcb06f8a55a9dd83 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Wed, 9 Mar 2022 14:13:02 -0800
Subject: SL-17019 mfa_hash should get saved per-username

---
 indra/newview/app_settings/settings.xml            | 11 ++++++
 .../newview/app_settings/settings_per_account.xml  | 11 ------
 indra/newview/lllogininstance.cpp                  | 39 +++++++++++++---------
 indra/newview/llstartup.cpp                        |  4 +--
 indra/newview/tests/lllogininstance_test.cpp       | 11 +++---
 5 files changed, 43 insertions(+), 33 deletions(-)

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 6c36fa6f09..7d39a54c1d 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -16815,5 +16815,16 @@
   <key>Value</key>
   <integer>1</integer>
   </map>
+  <key>MFAHash</key>
+  <map>
+    <key>Comment</key>
+    <string>Override MFA state hash for authentication</string>
+    <key>Persist</key>
+    <integer>0</integer>
+    <key>Type</key>
+    <string>String</string>
+    <key>Value</key>
+    <string></string>
+  </map>
 </map>
 </llsd>
diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml
index c45e841b94..537744b44c 100644
--- a/indra/newview/app_settings/settings_per_account.xml
+++ b/indra/newview/app_settings/settings_per_account.xml
@@ -436,16 +436,5 @@
         <key>Value</key>
         <integer>2</integer>
       </map>
-      <key>MFAHash</key>
-      <map>
-        <key>Comment</key>
-        <string>MFA state hash for authentication</string>
-        <key>Persist</key>
-        <integer>0</integer>
-        <key>Type</key>
-        <string>String</string>
-        <key>Value</key>
-        <string></string>
-      </map>
     </map>
 </llsd>
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index fd186fcddc..2335674501 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -230,34 +230,43 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
     // log request_params _before_ adding the credentials or sensitive MFA hash data
     LL_DEBUGS("LLLogin") << "Login parameters: " << LLSDOStreamer<LLSDNotationFormatter>(request_params) << LL_ENDL;
 
-    std::string mfa_hash = gSavedPerAccountSettings.getString("MFAHash"); //non-persistent to enable testing
-    LLPointer<LLSecAPIHandler> basic_secure_store = getSecHandler(BASIC_SECHANDLER);
+    // Copy the credentials into the request after logging the rest
+    LLSD credentials(user_credential->getLoginParams());
+    for (LLSD::map_const_iterator it = credentials.beginMap();
+         it != credentials.endMap();
+         it++
+         )
+    {
+        request_params[it->first] = it->second;
+    }
+
+    std::string mfa_hash = gSavedSettings.getString("MFAHash"); //non-persistent to enable testing
     std::string grid(LLGridManager::getInstance()->getGridId());
-    if (basic_secure_store)
+    std::string user_id = user_credential->userID();
+    if (gSecAPIHandler)
     {
         if (mfa_hash.empty())
         {
-            mfa_hash = basic_secure_store->getProtectedData("mfa_hash", grid).asString();
+            // normal execution, mfa_hash was not set from debug setting so load from protected store
+            LLSD data_map = gSecAPIHandler->getProtectedData("mfa_hash", grid);
+            if (data_map.isMap() && data_map.has(user_id))
+            {
+                mfa_hash = data_map[user_id].asString();
+            }
         }
         else
         {
             // SL-16888 the mfa_hash is being overridden for testing so save it for consistency for future login requests
-            basic_secure_store->setProtectedData("mfa_hash", grid, mfa_hash);
+            gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, mfa_hash);
         }
     }
-
-    request_params["mfa_hash"] = mfa_hash;
-
-    // Copy the credentials into the request after logging the rest
-    LLSD credentials(user_credential->getLoginParams());
-    for (LLSD::map_const_iterator it = credentials.beginMap();
-         it != credentials.endMap();
-         it++
-         )
+    else
     {
-        request_params[it->first] = it->second;
+        LL_WARNS() << "unable to access protected store for mfa_hash" << LL_ENDL;
     }
 
+    request_params["mfa_hash"] = mfa_hash;
+
 	// Specify desired timeout/retry options
 	LLSD http_params;
 	F32 srv_timeout = llclamp(gSavedSettings.getF32("LoginSRVTimeout"), LOGIN_SRV_TIMEOUT_MIN, LOGIN_SRV_TIMEOUT_MAX);
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 64e6042047..e7a1622332 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -3621,9 +3621,9 @@ bool process_login_success_response()
 	// Only save mfa_hash for future logins if the user wants their info remembered.
 	if(response.has("mfa_hash") && gSavedSettings.getBOOL("RememberUser") && gSavedSettings.getBOOL("RememberPassword"))
 	{
-		LLPointer<LLSecAPIHandler> basic_secure_store = getSecHandler(BASIC_SECHANDLER);
 		std::string grid(LLGridManager::getInstance()->getGridId());
-		basic_secure_store->setProtectedData("mfa_hash", grid, response["mfa_hash"]);
+		std::string user_id(gUserCredential->userID());
+		gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]);
 	}
 
 	bool success = false;
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
index 9253516411..a8f57f975a 100644
--- a/indra/newview/tests/lllogininstance_test.cpp
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -191,15 +191,14 @@ std::string LLGridManager::getGridId(const std::string& grid)
     return std::string();
 }
 
-LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type)
-{
-    return nullptr;
-}
+//LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type)
+//{
+//    return nullptr;
+//}
 
 //-----------------------------------------------------------------------------
 #include "../llviewercontrol.h"
 LLControlGroup gSavedSettings("Global");
-LLControlGroup gSavedPerAccountSettings("PerAccount");
 
 LLControlGroup::LLControlGroup(const std::string& name) :
 	LLInstanceTracker<LLControlGroup, std::string>(name){}
@@ -236,6 +235,8 @@ LLAppViewer * LLAppViewer::sInstance = 0;
 static std::string gTOSType;
 static LLEventPump * gTOSReplyPump = NULL;
 
+LLPointer<LLSecAPIHandler> gSecAPIHandler;
+
 //static
 LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus)
 {
-- 
cgit v1.2.3


From 22a22d17b4c10606cb36a35c92ed627ba2d8aa69 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Fri, 18 Mar 2022 15:22:29 -0700
Subject: Fix SL-17034/BUG-231938 whitespace in token causes authentication
 failure

---
 indra/newview/lllogininstance.cpp | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 2335674501..523d39da58 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -61,6 +61,7 @@
 #include "lltrans.h"
 
 #include <boost/scoped_ptr.hpp>
+#include <boost/regex.hpp>
 #include <sstream>
 
 const S32 LOGIN_MAX_RETRIES = 0; // Viewer should not autmatically retry login
@@ -448,10 +449,13 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
         LLSD payload;
         LLNotificationsUtil::add("PromptMFAToken", args, payload, [=](LLSD const & notif, LLSD const & response) {
             bool continue_clicked = response["continue"].asBoolean();
-            LLSD token = response["token"];
+            std::string token = response["token"].asString();
             LL_DEBUGS("LLLogin") << "PromptMFAToken: response: " << response << " continue_clicked" << continue_clicked << LL_ENDL;
 
-            if (continue_clicked && !token.asString().empty())
+            // strip out whitespace - SL-17034/BUG-231938
+            token = boost::regex_replace(token, boost::regex("\\s"), "");
+
+            if (continue_clicked && !token.empty())
             {
                 LL_INFOS("LLLogin") << "PromptMFAToken: token submitted" << LL_ENDL;
 
-- 
cgit v1.2.3


From 3feb92046ff226c6d65a90ae948a0390e768ed48 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 24 Mar 2022 18:47:08 +0200
Subject: SL-16831 Viewer stalls for 10 seconds before displaying a login
 failure

# Conflicts:
#	indra/newview/llstartup.cpp
---
 indra/newview/lllogininstance.cpp         |  5 +++++
 indra/newview/llstartup.cpp               | 27 ++++++++++++++++++++--
 indra/viewer_components/login/lllogin.cpp | 37 ++++++++++++++++++++++---------
 3 files changed, 56 insertions(+), 13 deletions(-)

diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 523d39da58..267f1d03ea 100644
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -280,6 +280,11 @@ void LLLoginInstance::constructAuthParams(LLPointer<LLCredential> user_credentia
 	mRequestData["params"] = request_params;
 	mRequestData["options"] = requested_options;
 	mRequestData["http_params"] = http_params;
+#if LL_RELEASE_FOR_DOWNLOAD
+    mRequestData["wait_for_updater"] = !gSavedSettings.getBOOL("CmdLineSkipUpdater") && !LLAppViewer::instance()->isUpdaterMissing();
+#else
+    mRequestData["wait_for_updater"] = false;
+#endif
 }
 
 bool LLLoginInstance::handleLoginEvent(const LLSD& event)
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index e7a1622332..3f825e4e43 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -2354,8 +2354,31 @@ void show_release_notes_if_required()
         && gSavedSettings.getBOOL("UpdaterShowReleaseNotes")
         && !gSavedSettings.getBOOL("FirstLoginThisInstall"))
     {
-        LLSD info(LLAppViewer::instance()->getViewerInfo());
-        LLWeb::loadURLInternal(info["VIEWER_RELEASE_NOTES_URL"]);
+
+#if LL_RELEASE_FOR_DOWNLOAD
+        if (!gSavedSettings.getBOOL("CmdLineSkipUpdater")
+            && !LLAppViewer::instance()->isUpdaterMissing())
+        {
+            // Instantiate a "relnotes" listener which assumes any arriving event
+            // is the release notes URL string. Since "relnotes" is an
+            // LLEventMailDrop, this listener will be invoked whether or not the
+            // URL has already been posted. If so, it will fire immediately;
+            // otherwise it will fire whenever the URL is (later) posted. Either
+            // way, it will display the release notes as soon as the URL becomes
+            // available.
+            LLEventPumps::instance().obtain("relnotes").listen(
+                "showrelnotes",
+                [](const LLSD& url) {
+                LLWeb::loadURLInternal(url.asString());
+                return false;
+            });
+        }
+        else
+#endif // LL_RELEASE_FOR_DOWNLOAD
+        {
+            LLSD info(LLAppViewer::instance()->getViewerInfo());
+            LLWeb::loadURLInternal(info["VIEWER_RELEASE_NOTES_URL"]);
+        }
         release_notes_shown = true;
     }
 }
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index 168880dc12..5d50d1e182 100644
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -251,20 +251,35 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
                 // Since sSyncPoint is an LLEventMailDrop, we DEFINITELY want to
                 // consume the posted event.
                 LLCoros::OverrideConsuming oc(true);
-                // Timeout should produce the isUndefined() object passed here.
-                LL_DEBUGS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL;
-                LLSD updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 10, LLSD());
-                if (updater.isUndefined())
-                {
-                    LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login"
-                                        << LL_ENDL;
-                }
-                else
+                LLSD responses(mAuthResponse["responses"]);
+                LLSD updater;
+
+                if (printable_params["wait_for_updater"].asBoolean())
                 {
-                    LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL;
+                    std::string reason_response = responses["data"]["reason"].asString();
+                    // Timeout should produce the isUndefined() object passed here.
+                    if (reason_response == "update")
+                    {
+                        LL_INFOS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL;
+                        updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 10, LLSD());
+                    }
+                    else
+                    {
+                        LL_DEBUGS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL;
+                        updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 3, LLSD());
+                    }
+                    if (updater.isUndefined())
+                    {
+                        LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login"
+                                            << LL_ENDL;
+                    }
+                    else
+                    {
+                        LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL;
+                    }
                 }
+
                 // Let the fail.login handler deal with empty updater response.
-                LLSD responses(mAuthResponse["responses"]);
                 responses["updater"] = updater;
                 sendProgressEvent("offline", "fail.login", responses);
             }
-- 
cgit v1.2.3


From d5f2537764655022247c639ce1cf2aa8d703bb94 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 25 Mar 2022 17:08:34 +0200
Subject: SL-16831 Fix unit test

---
 indra/newview/llappviewer.cpp                | 5 +++++
 indra/newview/llappviewer.h                  | 2 +-
 indra/newview/tests/lllogininstance_test.cpp | 2 ++
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 254bf05d05..d46dc2ff35 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -3086,6 +3086,11 @@ bool LLAppViewer::initWindow()
 	return true;
 }
 
+bool LLAppViewer::isUpdaterMissing()
+{
+    return mUpdaterNotFound;
+}
+
 void LLAppViewer::writeDebugInfo(bool isStatic)
 {
 #if LL_WINDOWS && LL_BUGSPLAT
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 0f06889d20..21fa23dfa8 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -98,7 +98,7 @@ public:
     bool quitRequested() { return mQuitRequested; }
     bool logoutRequestSent() { return mLogoutRequestSent; }
 	bool isSecondInstance() { return mSecondInstance; }
-    bool isUpdaterMissing() { return mUpdaterNotFound; }
+    bool isUpdaterMissing(); // In use by tests
 
 	void writeDebugInfo(bool isStatic=true);
 
diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp
index a8f57f975a..7259e66265 100644
--- a/indra/newview/tests/lllogininstance_test.cpp
+++ b/indra/newview/tests/lllogininstance_test.cpp
@@ -227,6 +227,7 @@ bool llHashedUniqueID(unsigned char* id)
 //-----------------------------------------------------------------------------
 #include "../llappviewer.h"
 void LLAppViewer::forceQuit(void) {}
+bool LLAppViewer::isUpdaterMissing() { return true; }
 LLAppViewer * LLAppViewer::sInstance = 0;
 
 //-----------------------------------------------------------------------------
@@ -354,6 +355,7 @@ namespace tut
 			gSavedSettings.declareString("ClientSettingsFile", "test_settings.xml", "", LLControlVariable::PERSIST_NO);
 			gSavedSettings.declareString("NextLoginLocation", "", "", LLControlVariable::PERSIST_NO);
 			gSavedSettings.declareBOOL("LoginLastLocation", FALSE, "", LLControlVariable::PERSIST_NO);
+            gSavedSettings.declareBOOL("CmdLineSkipUpdater", TRUE, "", LLControlVariable::PERSIST_NO);
 
 			LLSD authenticator = LLSD::emptyMap();
 			LLSD identifier = LLSD::emptyMap();
-- 
cgit v1.2.3


From efb9df04c3899c269f0c17d2473b4472d5f31ee5 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Fri, 15 Apr 2022 20:53:21 +0300
Subject: SL-16831 Don't wait for an updater on login failure unles it's the
 cause of failure

---
 indra/viewer_components/login/lllogin.cpp | 28 ++++++++++++----------------
 1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index 5d50d1e182..8a7e6407ed 100644
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -257,25 +257,21 @@ void LLLogin::Impl::loginCoro(std::string uri, LLSD login_params)
                 if (printable_params["wait_for_updater"].asBoolean())
                 {
                     std::string reason_response = responses["data"]["reason"].asString();
-                    // Timeout should produce the isUndefined() object passed here.
-                    if (reason_response == "update")
+                    if (reason_response == "update") // No point waiting if not an update
                     {
+                        // Timeout should produce the isUndefined() object passed here.
                         LL_INFOS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL;
                         updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 10, LLSD());
-                    }
-                    else
-                    {
-                        LL_DEBUGS("LLLogin") << "Login failure, waiting for sync from updater" << LL_ENDL;
-                        updater = llcoro::suspendUntilEventOnWithTimeout(sSyncPoint, 3, LLSD());
-                    }
-                    if (updater.isUndefined())
-                    {
-                        LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login"
-                                            << LL_ENDL;
-                    }
-                    else
-                    {
-                        LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL;
+
+                        if (updater.isUndefined())
+                        {
+                            LL_WARNS("LLLogin") << "Failed to hear from updater, proceeding with fail.login"
+                                << LL_ENDL;
+                        }
+                        else
+                        {
+                            LL_DEBUGS("LLLogin") << "Got responses from updater and login.cgi" << LL_ENDL;
+                        }
                     }
                 }
 
-- 
cgit v1.2.3


From 372a04dd51939d658cef93076651527318a89e33 Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Mon, 25 Apr 2022 12:35:07 -0700
Subject: Fix for SL-17223 save mfa_hash protected store immediately so it
 doesn't get lost in case of crash

---
 indra/newview/llsecapi.h             | 3 +++
 indra/newview/llsechandler_basic.cpp | 5 +++++
 indra/newview/llsechandler_basic.h   | 3 +++
 indra/newview/llstartup.cpp          | 2 ++
 4 files changed, 13 insertions(+)

diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h
index e1320375ab..d8831fee93 100644
--- a/indra/newview/llsecapi.h
+++ b/indra/newview/llsecapi.h
@@ -485,6 +485,9 @@ public:
 										const std::string& data_id,
 										const std::string& map_elem)=0;
 
+	// ensure protected store's map is written to storage
+	virtual void syncProtectedMap() = 0;
+
 public:
 	virtual LLPointer<LLCredential> createCredential(const std::string& grid,
 													 const LLSD& identifier, 
diff --git a/indra/newview/llsechandler_basic.cpp b/indra/newview/llsechandler_basic.cpp
index 6b06abaf99..d0da3387ec 100644
--- a/indra/newview/llsechandler_basic.cpp
+++ b/indra/newview/llsechandler_basic.cpp
@@ -1608,6 +1608,11 @@ void LLSecAPIBasicHandler::removeFromProtectedMap(const std::string& data_type,
     }
 }
 
+void LLSecAPIBasicHandler::syncProtectedMap()
+{
+    // TODO - consider unifing these functions
+    _writeProtectedData();
+}
 //
 // Create a credential object from an identifier and authenticator.  credentials are
 // per grid.
diff --git a/indra/newview/llsechandler_basic.h b/indra/newview/llsechandler_basic.h
index 17e9f72f07..bd1a8f640c 100644
--- a/indra/newview/llsechandler_basic.h
+++ b/indra/newview/llsechandler_basic.h
@@ -278,6 +278,9 @@ public:
 										const std::string& data_id,
 										const std::string& map_elem);
 
+	// ensure protected store's map is written to storage
+	virtual void syncProtectedMap();
+
 	// credential management routines
 	
 	virtual LLPointer<LLCredential> createCredential(const std::string& grid,
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 8b4c91615c..9a191b31bb 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -3671,6 +3671,8 @@ bool process_login_success_response()
 		std::string grid(LLGridManager::getInstance()->getGridId());
 		std::string user_id(gUserCredential->userID());
 		gSecAPIHandler->addToProtectedMap("mfa_hash", grid, user_id, response["mfa_hash"]);
+		// TODO(brad) - related to SL-17223 consider building a better interface that sync's automatically
+		gSecAPIHandler->syncProtectedMap();
 	}
 
 	bool success = false;
-- 
cgit v1.2.3


From 56a1bc850b446410a5cb444727774231892e3ceb Mon Sep 17 00:00:00 2001
From: Brad Kittenbrink <brad@lindenlab.com>
Date: Mon, 25 Apr 2022 13:44:38 -0700
Subject: SL-17223 fix unit tests with new method stub implementation

---
 indra/newview/tests/llsecapi_test.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/indra/newview/tests/llsecapi_test.cpp b/indra/newview/tests/llsecapi_test.cpp
index 37fbbb449b..7d2a9a436f 100644
--- a/indra/newview/tests/llsecapi_test.cpp
+++ b/indra/newview/tests/llsecapi_test.cpp
@@ -62,6 +62,7 @@ LLPointer<LLCertificateStore> LLSecAPIBasicHandler::getCertificateStore(const st
 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) {}
+void LLSecAPIBasicHandler::syncProtectedMap() {}
 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; }
-- 
cgit v1.2.3


From bc7e2fb7e7f7527b522bdf6f4c791f3b660485e2 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 4 May 2022 11:37:24 -0400
Subject: Increment viewer version to 6.5.6 following promotion of DRTVWR-550

---
 indra/newview/VIEWER_VERSION.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index cc81d718c3..32c568aee0 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-6.5.5
+6.5.6
-- 
cgit v1.2.3