1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
// Copyright 2024 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/sync/sync_passphrase_dialog.h"
#include <functional>
#include <string>
#include <string_view>
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/branded_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/google/core/common/google_util.h"
#include "components/strings/grit/components_strings.h"
#include "components/sync/service/sync_service.h"
#include "components/sync/service/sync_user_settings.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/dialog_model.h"
#include "ui/base/models/dialog_model_field.h"
#include "ui/base/models/dialog_model_host.h"
#include "ui/base/window_open_disposition.h"
#include "url/gurl.h"
namespace {
// Opens the sync dashboard webpage where the user may clear their sync data.
void OpenSyncDashboardAndCloseDialog(BrowserWindowInterface& browser,
ui::DialogModel* model) {
GURL sync_dashboard_url = google_util::AppendGoogleLocaleParam(
GURL(chrome::kSyncGoogleDashboardURL),
g_browser_process->GetApplicationLocale());
browser.OpenGURL(sync_dashboard_url,
WindowOpenDisposition::NEW_FOREGROUND_TAB);
model->host()->Close();
}
// Returns the content of the password field.
const std::u16string GetSyncPassphraseFieldText(ui::DialogModel* model) {
return model->GetPasswordFieldByUniqueId(kSyncPassphrasePasswordFieldId)
->text();
}
// Callback for the password field. Disables the button when the field is
// empty.
void OnPasswordFieldChanged(ui::DialogModel* model) {
std::u16string passphrase = GetSyncPassphraseFieldText(model);
ui::DialogModel::Button* ok_button =
model->GetButtonByUniqueId(kSyncPassphraseOkButtonFieldId);
model->SetButtonEnabled(ok_button, !passphrase.empty());
}
// Callback for the password field. Invalidates the field if the passphrase is
// incorrect. `decrypt_data_callback` is piped into this function.
bool HandlePassphraseError(ui::DialogModel* model, bool passphrase_is_valid) {
if (!passphrase_is_valid) {
ui::DialogModelPasswordField* password_field =
model->GetPasswordFieldByUniqueId(kSyncPassphrasePasswordFieldId);
password_field->Invalidate();
}
return passphrase_is_valid;
}
} // namespace
DEFINE_ELEMENT_IDENTIFIER_VALUE(kSyncPassphrasePasswordFieldId);
DEFINE_ELEMENT_IDENTIFIER_VALUE(kSyncPassphraseOkButtonFieldId);
void ShowSyncPassphraseDialog(
Browser& browser,
base::RepeatingCallback<bool(std::u16string_view)> decrypt_data_callback) {
ui::DialogModel::Builder dialog_builder;
// Link for the footnote.
base::RepeatingClosure link_closure =
base::BindRepeating(&OpenSyncDashboardAndCloseDialog, std::ref(browser),
dialog_builder.model());
ui::DialogModelLabel::TextReplacement link_replacement =
ui::DialogModelLabel::CreateLink(
IDS_SYNC_PASSPHRASE_DIALOG_FOOTER_LINK, std::move(link_closure),
l10n_util::GetStringUTF16(
IDS_SYNC_PASSPHRASE_DIALOG_FOOTER_LINK_ACC));
// The OK button is initially disabled, as the passphrase must be non-empty.
ui::DialogModel::Button::Params ok_button_params;
ok_button_params.SetEnabled(false)
.SetLabel(l10n_util::GetStringUTF16(IDS_SYNC_PASSPHRASE_DIALOG_OK_BUTTON))
.SetId(kSyncPassphraseOkButtonFieldId);
// Callback for the OK button.
// If the passphrase is correct, the dialog is closed. If it's incorrect, the
// text field is cleared but remains open for the user to try again.
base::RepeatingCallback<bool()> ok_callback =
base::BindRepeating(&GetSyncPassphraseFieldText,
base::Unretained(dialog_builder.model()))
.Then(decrypt_data_callback)
.Then(base::BindRepeating(&HandlePassphraseError,
base::Unretained(dialog_builder.model())));
dialog_builder.SetInternalName("SyncPassphraseDialog")
.SetTitle(l10n_util::GetStringUTF16(IDS_SYNC_PASSPHRASE_DIALOG_TITLE))
.AddParagraph(ui::DialogModelLabel(IDS_SYNC_PASSPHRASE_DIALOG_BODY))
.AddPasswordField(
kSyncPassphrasePasswordFieldId,
/*label=*/std::u16string(),
/*accessible_text=*/
l10n_util::GetStringUTF16(IDS_SYNC_PASSPHRASE_LABEL),
l10n_util::GetStringUTF16(IDS_SETTINGS_INCORRECT_PASSPHRASE_ERROR))
.AddOkButton(std::move(ok_callback), ok_button_params)
.AddCancelButton(base::DoNothing())
.SetFootnote(ui::DialogModelLabel::CreateWithReplacement(
IDS_SYNC_PASSPHRASE_DIALOG_FOOTER, std::move(link_replacement)));
// Listen to password field change events, to disable the OK button when the
// passphrase is empty.
ui::DialogModel* model = dialog_builder.model();
auto subscription =
model->GetPasswordFieldByUniqueId(kSyncPassphrasePasswordFieldId)
->AddOnFieldChangedCallback(base::BindRepeating(
&OnPasswordFieldChanged, base::Unretained(model)));
// Dummy callback to own the subscription.
dialog_builder.SetDialogDestroyingCallback(
base::BindOnce([](base::CallbackListSubscription subscription) {},
std::move(subscription)));
chrome::ShowBrowserModal(&browser, dialog_builder.Build());
}
bool SyncPassphraseDialogDecryptData(syncer::SyncService* sync_service,
std::u16string_view passphrase) {
if (!sync_service || !sync_service->IsEngineInitialized()) {
// Even though this is a failure, return true so that the dialog closes and
// the user does not need to try again.
return true;
}
syncer::SyncUserSettings* sync_user_settings =
sync_service->GetUserSettings();
if (!sync_user_settings->IsPassphraseRequired()) {
return true;
}
if (passphrase.empty()) {
// Empty passphrases are not allowed.
return false;
}
return sync_user_settings->SetDecryptionPassphrase(
base::UTF16ToUTF8(passphrase));
}
|