Skip to content

Commit

Permalink
Merge pull request #4731 from brave/pr4530_issue_2710_1.5.x
Browse files Browse the repository at this point in the history
Show dialog when Brave tries to import Safari data w/o disk permission (uplift to 1.5.x)
  • Loading branch information
kjozwiak authored Mar 4, 2020
2 parents 71edd51 + 3221ed9 commit 4f09229
Show file tree
Hide file tree
Showing 13 changed files with 374 additions and 46 deletions.
12 changes: 12 additions & 0 deletions app/brave_generated_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,18 @@ By installing this extension, you are agreeing to the Google Widevine Terms of U
<message name="IDS_BRAVE_BOOKMARK_MANAGER_EMPTY_LIST" desc="">
To add a bookmark, click the bookmark button next to the address bar
</message>
<message name="IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_TITLE" desc="The label for full disk access dialog title">
Full Disk Access required
</message>
<message name="IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_MESSAGE" desc="The label for full disk access dialog message">
Brave needs Full Disk Access to import your Bookmarks from Safari.
</message>
<message name="IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_LINK_TEXT" desc="The label for full disk access dialog link text">
Learn how to grant Full Disk Access from your System Preferences.
</message>
<message name="IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_OPEN_PREFS_BUTTON_TEXT" desc="The label for open privacy panel">
Open System Preferences
</message>
</messages>
</release>
</grit>
12 changes: 12 additions & 0 deletions browser/ui/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,21 @@ source_set("ui") {
"webui/settings/brave_appearance_handler.h",
"webui/settings/brave_privacy_handler.cc",
"webui/settings/brave_privacy_handler.h",
"webui/settings/brave_settings_import_data_handler.h",
"webui/settings/default_brave_shields_handler.cc",
"webui/settings/default_brave_shields_handler.h",
]

if (is_mac) {
sources += [
"webui/settings/brave_settings_import_data_handler_mac.mm",
]
} else {
sources += [
"webui/settings/brave_settings_import_data_handler.cc",
]
}

if (enable_sparkle) {
sources += [
"webui/settings/brave_relaunch_handler_mac.h",
Expand Down Expand Up @@ -215,6 +226,7 @@ source_set("ui") {
"//ui/base",
"//ui/gfx",
"//ui/resources",
"//url",
]

# This is no longer compiled into Chromium on Android, but we still
Expand Down
5 changes: 3 additions & 2 deletions browser/ui/webui/brave_welcome_ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@

#include "base/metrics/histogram_macros.h"
#include "brave/browser/brave_browser_process_impl.h"
#include "brave/browser/ui/webui/settings/brave_settings_import_data_handler.h"
#include "brave/common/pref_names.h"
#include "brave/common/webui_url_constants.h"
#include "brave/components/brave_welcome/resources/grit/brave_welcome_generated_map.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/webui/settings/search_engines_handler.h"
#include "chrome/browser/ui/webui/settings/settings_import_data_handler.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/webui_url_constants.h"
#include "components/grit/brave_components_resources.h"
Expand Down Expand Up @@ -107,7 +107,8 @@ BraveWelcomeUI::BraveWelcomeUI(content::WebUI* web_ui, const std::string& name)
: BasicUI(web_ui, name, kBraveWelcomeGenerated,
kBraveWelcomeGeneratedSize, IDR_BRAVE_WELCOME_HTML) {
web_ui->AddMessageHandler(std::make_unique<WelcomeDOMHandler>());
web_ui->AddMessageHandler(std::make_unique<settings::ImportDataHandler>());
web_ui->AddMessageHandler(
std::make_unique<settings::BraveImportDataHandler>());

Profile* profile = Profile::FromWebUI(web_ui);

Expand Down
13 changes: 13 additions & 0 deletions browser/ui/webui/settings/brave_settings_import_data_handler.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* Copyright (c) 2020 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "brave/browser/ui/webui/settings/brave_settings_import_data_handler.h"

namespace settings {

BraveImportDataHandler::BraveImportDataHandler() {}
BraveImportDataHandler::~BraveImportDataHandler() = default;

} // namespace settings
59 changes: 59 additions & 0 deletions browser/ui/webui/settings/brave_settings_import_data_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* Copyright (c) 2020 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_SETTINGS_IMPORT_DATA_HANDLER_H_
#define BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_SETTINGS_IMPORT_DATA_HANDLER_H_

#include "base/memory/weak_ptr.h"
#include "chrome/browser/ui/webui/settings/settings_import_data_handler.h"
#include "content/public/browser/web_contents_observer.h"

namespace settings {

// This class checks whether Brave has full disk access permission to import
// safari data on macOS. ImportDataHandler::StartImport() will be run after
// checking disk access permission. If Brave doesn't have that permission, this
// will launch tab modal dialog to notify users about this lack of permission.

// We should display tab modal dialog after import dialog is closed from webui.
// To do that, this observes web contents to launch dialog after import dialog
// closed. If dialog is launched right after notifying import failure,
// dialog will be closed immediately because tab modal dialog is closed with
// new navigation start and tab is newly loaded for closing webui import dialog.
// The reason why native tab modal dialog is used here is to avoid modifying
// upstream import html/js source code.

// NOTE: This is no-op class for other platforms except macOS.
class BraveImportDataHandler : public ImportDataHandler,
content::WebContentsObserver {
public:
BraveImportDataHandler();
~BraveImportDataHandler() override;

BraveImportDataHandler(const BraveImportDataHandler&) = delete;
BraveImportDataHandler& operator=(const BraveImportDataHandler&) = delete;

private:
#if defined(OS_MACOSX)
// ImportDataHandler overrides:
void StartImport(const importer::SourceProfile& source_profile,
uint16_t imported_items) override;

void OnGetDiskAccessPermission(const importer::SourceProfile& source_profile,
uint16_t imported_items,
bool allowed);

// content::WebContentsObserver overrides:
void DidStopLoading() override;

bool guide_dialog_is_requested_ = false;

base::WeakPtrFactory<BraveImportDataHandler> weak_factory_;
#endif
};

} // namespace settings

#endif // BRAVE_BROWSER_UI_WEBUI_SETTINGS_BRAVE_SETTINGS_IMPORT_DATA_HANDLER_H_
195 changes: 195 additions & 0 deletions browser/ui/webui/settings/brave_settings_import_data_handler_mac.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
/* Copyright (c) 2020 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "brave/browser/ui/webui/settings/brave_settings_import_data_handler.h"

#import <AppKit/AppKit.h>

#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/mac/foundation_util.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/values.h"
#include "brave/common/url_constants.h"
#include "chrome/browser/importer/external_process_importer_host.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/tab_modal_confirm_dialog.h"
#include "chrome/browser/ui/tab_modal_confirm_dialog_delegate.h"
#include "chrome/common/importer/importer_data_types.h"
#include "chrome/grit/generated_resources.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_ui.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_types.h"
#include "url/gurl.h"

namespace {

using content::BrowserThread;

class FullDiskAccessConfirmDialogDelegate
: public TabModalConfirmDialogDelegate {
public:
FullDiskAccessConfirmDialogDelegate(content::WebContents* web_contents,
Browser* browser);
~FullDiskAccessConfirmDialogDelegate() override;

FullDiskAccessConfirmDialogDelegate(
const FullDiskAccessConfirmDialogDelegate&) = delete;
FullDiskAccessConfirmDialogDelegate& operator=(
const FullDiskAccessConfirmDialogDelegate&) = delete;

private:
// TabModalConfirmDialogDelegate overrides:
base::string16 GetTitle() override;
base::string16 GetDialogMessage() override;
base::string16 GetLinkText() const override;
base::string16 GetAcceptButtonTitle() override;
void OnAccepted() override;
void OnLinkClicked(WindowOpenDisposition disposition) override;

Browser* browser_;
};

FullDiskAccessConfirmDialogDelegate::FullDiskAccessConfirmDialogDelegate(
content::WebContents* web_contents,
Browser* browser)
: TabModalConfirmDialogDelegate(web_contents),
browser_(browser) {}

FullDiskAccessConfirmDialogDelegate::
~FullDiskAccessConfirmDialogDelegate() = default;

base::string16 FullDiskAccessConfirmDialogDelegate::GetTitle() {
return l10n_util::GetStringUTF16(IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_TITLE);
}

base::string16 FullDiskAccessConfirmDialogDelegate::GetDialogMessage() {
return l10n_util::GetStringUTF16(IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_MESSAGE);
}

base::string16 FullDiskAccessConfirmDialogDelegate::GetLinkText() const {
return l10n_util::GetStringUTF16(IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_LINK_TEXT);
}

base::string16 FullDiskAccessConfirmDialogDelegate::GetAcceptButtonTitle() {
return l10n_util::GetStringUTF16(
IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_OPEN_PREFS_BUTTON_TEXT);
}

void FullDiskAccessConfirmDialogDelegate::OnAccepted() {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:
@"x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"]]; // NOLINT
}

void FullDiskAccessConfirmDialogDelegate::OnLinkClicked(
WindowOpenDisposition disposition) {
const int target_index =
browser_->tab_strip_model()->active_index() + 1;
// Add import help tab right after current settings tab.
chrome::AddTabAt(browser_, GURL(kImportDataHelpURL),
target_index, true /* foreground */);
}

bool HasProperDiskAccessPermission(uint16_t imported_items) {
DCHECK(imported_items);

const base::FilePath& library_dir = base::mac::GetUserLibraryPath();
const base::FilePath safari_dir = library_dir.Append("Safari");

if (imported_items & importer::FAVORITES) {
const base::FilePath bookmarks_path = safari_dir.Append("Bookmarks.plist");
if(!PathIsWritable(bookmarks_path)) {
LOG(ERROR) << __func__ << " " << bookmarks_path << " is not accessible."
<< " Please check full disk access permission.";
return false;
}
}

if (imported_items & importer::HISTORY) {
const base::FilePath history_path = safari_dir.Append("History.plist");
if(!PathIsWritable(history_path)) {
LOG(ERROR) << __func__ << " " << history_path << " is not accessible."
<< " Please check full disk access permission.";
return false;
}
}

return true;
}

} // namespace

namespace settings {

BraveImportDataHandler::BraveImportDataHandler() : weak_factory_(this) {}
BraveImportDataHandler::~BraveImportDataHandler() = default;

void BraveImportDataHandler::StartImport(
const importer::SourceProfile& source_profile,
uint16_t imported_items) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);

guide_dialog_is_requested_ = false;

if (!imported_items)
return;

if (source_profile.importer_type == importer::TYPE_SAFARI) {
// Start import if Brave has full disk access permission.
// If not, show dialog that has infos about that permission.
base::PostTaskAndReplyWithResult(
FROM_HERE, {base::ThreadPool(), base::MayBlock()},
base::BindOnce(&HasProperDiskAccessPermission, imported_items),
base::BindOnce(&BraveImportDataHandler::OnGetDiskAccessPermission,
weak_factory_.GetWeakPtr(),
source_profile, imported_items));
return;
}

ImportDataHandler::StartImport(source_profile, imported_items);
}

void BraveImportDataHandler::OnGetDiskAccessPermission(
const importer::SourceProfile& source_profile,
uint16_t imported_items,
bool allowed) {
if (!allowed) {
// Notify to webui to finish import process and launch tab modal dialog
// to guide full disk access information to users.
// Guide dialog will be opened after import dialog is closed.
FireWebUIListener("import-data-status-changed", base::Value("failed"));

// Observing web_contents is started here to know the closing timing of
// import dialog.
Observe(web_ui()->GetWebContents());

guide_dialog_is_requested_ = true;
return;
}

return ImportDataHandler::StartImport(source_profile, imported_items);
}

void BraveImportDataHandler::DidStopLoading() {
Observe(nullptr);

if (!guide_dialog_is_requested_)
return;

guide_dialog_is_requested_ = false;

auto* web_contents = web_ui()->GetWebContents();
TabModalConfirmDialog::Create(
std::make_unique<FullDiskAccessConfirmDialogDelegate>(
web_contents,
chrome::FindBrowserWithWebContents(web_contents)),
web_contents);
}

} // namespace settings
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* Copyright (c) 2020 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "brave/browser/importer/brave_external_process_importer_host.h"
#include "brave/browser/importer/brave_profile_writer.h"

#define ProfileWriter BraveProfileWriter
#define ExternalProcessImporterHost BraveExternalProcessImporterHost

#define BRAVE_IMPORT_DATA \
if (prefs->GetBoolean(prefs::kImportDialogCookies)) \
selected_items |= importer::COOKIES; \
if (prefs->GetBoolean(prefs::kImportDialogStats)) \
selected_items |= importer::STATS; \
if (prefs->GetBoolean(prefs::kImportDialogLedger)) \
selected_items |= importer::LEDGER; \
if (prefs->GetBoolean(prefs::kImportDialogWindows)) \
selected_items |= importer::WINDOWS;

#define BRAVE_SEND_BROWSER_PROFILE_DATA \
browser_profile->SetBoolean("cookies", \
(browser_services & importer::COOKIES) != 0); \
browser_profile->SetBoolean("stats", \
(browser_services & importer::STATS) != 0); \
browser_profile->SetBoolean("ledger", \
(browser_services & importer::LEDGER) != 0); \
browser_profile->SetBoolean("windows", \
(browser_services & importer::WINDOWS) != 0);

#include "../../../../../../../chrome/browser/ui/webui/settings/settings_import_data_handler.cc" // NOLINT
#undef ProfileWriter
#undef ExternalProcessImporterHost
#undef BRAVE_IMPORT_DATA
#undef BRAVE_SEND_BROWSER_PROFILE_DATA
Loading

0 comments on commit 4f09229

Please sign in to comment.