Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show dialog when Brave tries to import Safari data w/o disk permission #4530

Merged
merged 1 commit into from
Feb 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 and History from Safari.
</message>
<message name="IDS_FULL_DISK_ACCESS_CONFIRM_DIALOG_LINK_TEXT" desc="The label for full disk access dialog link text">
Learn to 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,6 +93,7 @@ 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",
]
Expand Down Expand Up @@ -173,6 +174,16 @@ source_set("ui") {
]
}

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

deps = [
"//base",
"//brave/app:command_ids",
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