chromium/chrome/browser/ui/webui/ash/in_session_password_change/confirm_password_change_handler.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/ash/in_session_password_change/confirm_password_change_handler.h"

#include <string>

#include "base/check.h"
#include "base/values.h"
#include "chrome/browser/ash/login/saml/in_session_password_change_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chromeos/ash/components/login/auth/public/saml_password_attributes.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/user_manager.h"

namespace ash {

namespace {

const InSessionPasswordChangeManager::Event kIncorrectPasswordEvent =
    InSessionPasswordChangeManager::Event::CRYPTOHOME_PASSWORD_CHANGE_FAILURE;

const InSessionPasswordChangeManager::PasswordSource kPasswordSource =
    InSessionPasswordChangeManager::PasswordSource::PASSWORDS_RETYPED;

// Returns one if it is non-empty, otherwise returns two.
const std::string& FirstNonEmpty(const std::string& one,
                                 const std::string& two) {
  return !one.empty() ? one : two;
}

}  // namespace

ConfirmPasswordChangeHandler::ConfirmPasswordChangeHandler(
    const std::string& scraped_old_password,
    const std::string& scraped_new_password,
    const bool show_spinner_initially)
    : scraped_old_password_(scraped_old_password),
      scraped_new_password_(scraped_new_password),
      show_spinner_initially_(show_spinner_initially) {
  if (InSessionPasswordChangeManager::IsInitialized()) {
    InSessionPasswordChangeManager::Get()->AddObserver(this);
  }
}

ConfirmPasswordChangeHandler::~ConfirmPasswordChangeHandler() {
  if (InSessionPasswordChangeManager::IsInitialized()) {
    InSessionPasswordChangeManager::Get()->RemoveObserver(this);
  }
}

void ConfirmPasswordChangeHandler::HandleGetInitialState(
    const base::Value::List& params) {
  const std::string callback_id = params[0].GetString();

  base::Value::Dict state;
  state.Set("showOldPasswordPrompt", scraped_old_password_.empty());
  state.Set("showNewPasswordPrompt", scraped_new_password_.empty());
  state.Set("showSpinner", show_spinner_initially_);

  AllowJavascript();
  ResolveJavascriptCallback(callback_id, state);
}

void ConfirmPasswordChangeHandler::HandleChangePassword(
    const base::Value::List& params) {
  const std::string old_password =
      FirstNonEmpty(params[0].GetString(), scraped_old_password_);
  const std::string new_password =
      FirstNonEmpty(params[1].GetString(), scraped_new_password_);
  DCHECK(!old_password.empty() && !new_password.empty());

  InSessionPasswordChangeManager::Get()->ChangePassword(
      old_password, new_password, kPasswordSource);
}

void ConfirmPasswordChangeHandler::OnEvent(
    InSessionPasswordChangeManager::Event event) {
  if (event == kIncorrectPasswordEvent) {
    // If this event comes before getInitialState, then don't show the spinner
    // initially after all - the initial password change attempt using scraped
    // passwords already failed before the dialog finished loading.
    show_spinner_initially_ = false;
    // Discard the scraped old password and ask the user what it really is.
    scraped_old_password_.clear();
    if (IsJavascriptAllowed()) {
      FireWebUIListener("incorrect-old-password");
    }
  }
}

void ConfirmPasswordChangeHandler::RegisterMessages() {
  web_ui()->RegisterMessageCallback(
      "getInitialState",
      base::BindRepeating(&ConfirmPasswordChangeHandler::HandleGetInitialState,
                          weak_factory_.GetWeakPtr()));
  web_ui()->RegisterMessageCallback(
      "changePassword",
      base::BindRepeating(&ConfirmPasswordChangeHandler::HandleChangePassword,
                          weak_factory_.GetWeakPtr()));
}

}  // namespace ash