File: sync_passphrase_dialog.cc

package info (click to toggle)
chromium 139.0.7258.138-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,120,676 kB
  • sloc: cpp: 35,100,869; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (159 lines) | stat: -rw-r--r-- 6,498 bytes parent folder | download | duplicates (8)
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));
}