Implement App-Scoped Security scoped bookmarks (#11711)

* implementation of security scoped bookmarks

* option is now only available on mas builds
This commit is contained in:
acheronfail 2018-02-13 05:25:06 +11:00 committed by shelley vohr
parent 9f78ef0179
commit d1d50a4c92
11 changed files with 226 additions and 42 deletions

View file

@ -1262,6 +1262,10 @@ void App::BuildPrototype(
.SetMethod("moveToApplicationsFolder", &App::MoveToApplicationsFolder)
.SetMethod("isInApplicationsFolder", &App::IsInApplicationsFolder)
#endif
#if defined(MAS_BUILD)
.SetMethod("startAccessingSecurityScopedResource",
&App::StartAccessingSecurityScopedResource)
#endif
.SetMethod("getAppMemoryInfo", &App::GetAppMetrics);
}

View file

@ -209,6 +209,10 @@ class App : public AtomBrowserClient::Delegate,
bool MoveToApplicationsFolder(mate::Arguments* args);
bool IsInApplicationsFolder();
#endif
#if defined(MAS_BUILD)
base::Callback<void()> StartAccessingSecurityScopedResource(
mate::Arguments* args);
#endif
#if defined(OS_WIN)
// Get the current Jump List settings.

View file

@ -0,0 +1,59 @@
// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/browser/api/atom_api_app.h"
#import <Cocoa/Cocoa.h>
#include "base/strings/sys_string_conversions.h"
namespace atom {
namespace api {
// Callback passed to js which will stop accessing the given bookmark.
void OnStopAccessingSecurityScopedResource(NSURL* bookmarkUrl) {
[bookmarkUrl stopAccessingSecurityScopedResource];
[bookmarkUrl release];
}
// Get base64 encoded NSData, create a bookmark for it and start accessing it.
base::Callback<void ()> App::StartAccessingSecurityScopedResource(mate::Arguments* args) {
std::string data;
args->GetNext(&data);
NSString *base64str = base::SysUTF8ToNSString(data);
NSData *bookmarkData = [[NSData alloc] initWithBase64EncodedString: base64str options: 0];
// Create bookmarkUrl from NSData.
BOOL isStale = false;
NSError *error = nil;
NSURL *bookmarkUrl = [NSURL URLByResolvingBookmarkData: bookmarkData
options: NSURLBookmarkResolutionWithSecurityScope
relativeToURL: nil
bookmarkDataIsStale: &isStale
error: &error];
if (error != nil) {
NSString *err = [NSString stringWithFormat: @"NSError: %@ %@", error, [error userInfo]];
args->ThrowError(base::SysNSStringToUTF8(err));
}
if (isStale) {
args->ThrowError("bookmarkDataIsStale - try recreating the bookmark");
}
if (error == nil && isStale == false) {
[bookmarkUrl startAccessingSecurityScopedResource];
}
// Stop the NSURL from being GC'd.
[bookmarkUrl retain];
// Return a js callback which will close the bookmark.
return base::Bind(&OnStopAccessingSecurityScopedResource, bookmarkUrl);
}
} // namespace atom
} // namespace api

View file

@ -54,6 +54,9 @@ struct Converter<file_dialog::DialogSettings> {
dict.Get("filters", &(out->filters));
dict.Get("properties", &(out->properties));
dict.Get("showsTagField", &(out->shows_tag_field));
#if defined(MAS_BUILD)
dict.Get("securityScopedBookmarks", &(out->security_scoped_bookmarks));
#endif
return true;
}
};

View file

@ -33,11 +33,25 @@ enum FileDialogProperty {
FILE_DIALOG_TREAT_PACKAGE_APP_AS_DIRECTORY = 1 << 7,
};
typedef base::Callback<void(
bool result, const std::vector<base::FilePath>& paths)> OpenDialogCallback;
#if defined(MAS_BUILD)
typedef base::Callback<void(
bool result,
const std::vector<base::FilePath>& paths,
const std::vector<std::string>& bookmarkData)> OpenDialogCallback;
typedef base::Callback<void(
bool result, const base::FilePath& path)> SaveDialogCallback;
typedef base::Callback<void(
bool result,
const base::FilePath& path,
const std::string& bookmarkData)> SaveDialogCallback;
#else
typedef base::Callback<void(
bool result,
const std::vector<base::FilePath>& paths)> OpenDialogCallback;
typedef base::Callback<void(
bool result,
const base::FilePath& path)> SaveDialogCallback;
#endif
struct DialogSettings {
atom::NativeWindow* parent_window = nullptr;
@ -50,6 +64,7 @@ struct DialogSettings {
int properties = 0;
bool shows_tag_field = true;
bool force_detached = false;
bool security_scoped_bookmarks = false;
};
bool ShowOpenDialog(const DialogSettings& settings,

View file

@ -185,11 +185,44 @@ int RunModalDialog(NSSavePanel* dialog, const DialogSettings& settings) {
return chosen;
}
void ReadDialogPaths(NSOpenPanel* dialog, std::vector<base::FilePath>* paths) {
// Create bookmark data and serialise it into a base64 string.
std::string GetBookmarkDataFromNSURL(NSURL* url) {
// Create the file if it doesn't exist (necessary for NSSavePanel options).
NSFileManager *defaultManager = [NSFileManager defaultManager];
if (![defaultManager fileExistsAtPath: [url path]]) {
[defaultManager createFileAtPath: [url path] contents: nil attributes: nil];
}
NSError *error = nil;
NSData *bookmarkData = [url bookmarkDataWithOptions: NSURLBookmarkCreationWithSecurityScope
includingResourceValuesForKeys: nil
relativeToURL: nil
error: &error];
if (error != nil) {
// Send back an empty string if there was an error.
return "";
} else {
// Encode NSData in base64 then convert to NSString.
NSString *base64data = [[NSString alloc] initWithData: [bookmarkData base64EncodedDataWithOptions: 0]
encoding: NSUTF8StringEncoding];
return base::SysNSStringToUTF8(base64data);
}
}
void ReadDialogPathsWithBookmarks(NSOpenPanel* dialog,
std::vector<base::FilePath>* paths,
std::vector<std::string>* bookmarks) {
NSArray* urls = [dialog URLs];
for (NSURL* url in urls)
if ([url isFileURL])
if ([url isFileURL]) {
paths->push_back(base::FilePath(base::SysNSStringToUTF8([url path])));
bookmarks->push_back(GetBookmarkDataFromNSURL(url));
}
}
void ReadDialogPaths(NSOpenPanel* dialog, std::vector<base::FilePath>* paths) {
std::vector<std::string> ignored_bookmarks;
ReadDialogPathsWithBookmarks(dialog, paths, &ignored_bookmarks);
}
} // namespace
@ -210,6 +243,33 @@ bool ShowOpenDialog(const DialogSettings& settings,
return true;
}
void OpenDialogCompletion(int chosen, NSOpenPanel* dialog,
const DialogSettings& settings,
const OpenDialogCallback& callback) {
if (chosen == NSFileHandlingPanelCancelButton) {
#if defined(MAS_BUILD)
callback.Run(false, std::vector<base::FilePath>(),
std::vector<std::string>());
#else
callback.Run(false, std::vector<base::FilePath>());
#endif
} else {
std::vector<base::FilePath> paths;
#if defined(MAS_BUILD)
std::vector<std::string> bookmarks;
if (settings.security_scoped_bookmarks) {
ReadDialogPathsWithBookmarks(dialog, &paths, &bookmarks);
} else {
ReadDialogPaths(dialog, &paths);
}
callback.Run(true, paths, bookmarks);
#else
ReadDialogPaths(dialog, &paths);
callback.Run(true, paths);
#endif
}
}
void ShowOpenDialog(const DialogSettings& settings,
const OpenDialogCallback& c) {
NSOpenPanel* dialog = [NSOpenPanel openPanel];
@ -224,24 +284,12 @@ void ShowOpenDialog(const DialogSettings& settings,
if (!settings.parent_window || !settings.parent_window->GetNativeWindow() ||
settings.force_detached) {
int chosen = [dialog runModal];
if (chosen == NSFileHandlingPanelCancelButton) {
callback.Run(false, std::vector<base::FilePath>());
} else {
std::vector<base::FilePath> paths;
ReadDialogPaths(dialog, &paths);
callback.Run(true, paths);
}
OpenDialogCompletion(chosen, dialog, settings, callback);
} else {
NSWindow* window = settings.parent_window->GetNativeWindow();
[dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) {
if (chosen == NSFileHandlingPanelCancelButton) {
callback.Run(false, std::vector<base::FilePath>());
} else {
std::vector<base::FilePath> paths;
ReadDialogPaths(dialog, &paths);
callback.Run(true, paths);
}
OpenDialogCompletion(chosen, dialog, settings, callback);
}];
}
}
@ -261,6 +309,29 @@ bool ShowSaveDialog(const DialogSettings& settings,
return true;
}
void SaveDialogCompletion(int chosen, NSSavePanel* dialog,
const DialogSettings& settings,
const SaveDialogCallback& callback) {
if (chosen == NSFileHandlingPanelCancelButton) {
#if defined(MAS_BUILD)
callback.Run(false, base::FilePath(), "");
#else
callback.Run(false, base::FilePath());
#endif
} else {
std::string path = base::SysNSStringToUTF8([[dialog URL] path]);
#if defined(MAS_BUILD)
std::string bookmark;
if (settings.security_scoped_bookmarks) {
bookmark = GetBookmarkDataFromNSURL([dialog URL]);
}
callback.Run(true, base::FilePath(path), bookmark);
#else
callback.Run(true, base::FilePath(path));
#endif
}
}
void ShowSaveDialog(const DialogSettings& settings,
const SaveDialogCallback& c) {
NSSavePanel* dialog = [NSSavePanel savePanel];
@ -273,22 +344,12 @@ void ShowSaveDialog(const DialogSettings& settings,
if (!settings.parent_window || !settings.parent_window->GetNativeWindow() ||
settings.force_detached) {
int chosen = [dialog runModal];
if (chosen == NSFileHandlingPanelCancelButton) {
callback.Run(false, base::FilePath());
} else {
std::string path = base::SysNSStringToUTF8([[dialog URL] path]);
callback.Run(true, base::FilePath(path));
}
SaveDialogCompletion(chosen, dialog, settings, callback);
} else {
NSWindow* window = settings.parent_window->GetNativeWindow();
[dialog beginSheetModalForWindow:window
completionHandler:^(NSInteger chosen) {
if (chosen == NSFileHandlingPanelCancelButton) {
callback.Run(false, base::FilePath());
} else {
std::string path = base::SysNSStringToUTF8([[dialog URL] path]);
callback.Run(true, base::FilePath(path));
}
SaveDialogCompletion(chosen, dialog, settings, callback);
}];
}
}

View file

@ -53,7 +53,13 @@ class FileSelectHelper : public base::RefCounted<FileSelectHelper>,
~FileSelectHelper() override {}
void OnOpenDialogDone(bool result, const std::vector<base::FilePath>& paths) {
#if defined(MAS_BUILD)
void OnOpenDialogDone(bool result, const std::vector<base::FilePath>& paths,
const std::vector<std::string>& bookmarks)
#else
void OnOpenDialogDone(bool result, const std::vector<base::FilePath>& paths)
#endif
{
std::vector<content::FileChooserFileInfo> file_info;
if (result) {
for (auto& path : paths) {
@ -73,7 +79,13 @@ class FileSelectHelper : public base::RefCounted<FileSelectHelper>,
OnFilesSelected(file_info);
}
void OnSaveDialogDone(bool result, const base::FilePath& path) {
#if defined(MAS_BUILD)
void OnSaveDialogDone(bool result, const base::FilePath& path,
const std::string& bookmark)
#else
void OnSaveDialogDone(bool result, const base::FilePath& path)
#endif
{
std::vector<content::FileChooserFileInfo> file_info;
if (result) {
content::FileChooserFileInfo info;