feat: emit an event when accessing restricted path in File System Access API (#43162)

* fix: show a dialog when accessing restricted path in File System Access API

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* fix: allow overriding initial blocked paths

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* docs: fix doc

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* Update docs/api/session.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* fix: change block to deny for consistency

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
This commit is contained in:
trop[bot] 2024-08-13 12:47:53 -04:00 committed by GitHub
parent e39c0f9dae
commit ff3d3e6944
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 149 additions and 18 deletions

View file

@ -11,6 +11,7 @@
#include "base/files/file_path.h"
#include "base/json/values_util.h"
#include "base/path_service.h"
#include "base/task/bind_post_task.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
@ -26,18 +27,52 @@
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
#include "gin/data_object_builder.h"
#include "shell/browser/api/electron_api_session.h"
#include "shell/browser/electron_permission_manager.h"
#include "shell/browser/web_contents_permission_helper.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_converters/file_path_converter.h"
#include "third_party/blink/public/mojom/file_system_access/file_system_access_manager.mojom.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/origin.h"
namespace gin {
template <>
struct Converter<
ChromeFileSystemAccessPermissionContext::SensitiveEntryResult> {
static bool FromV8(
v8::Isolate* isolate,
v8::Local<v8::Value> val,
ChromeFileSystemAccessPermissionContext::SensitiveEntryResult* out) {
std::string type;
if (!ConvertFromV8(isolate, val, &type))
return false;
if (type == "allow")
*out = ChromeFileSystemAccessPermissionContext::SensitiveEntryResult::
kAllowed;
else if (type == "tryAgain")
*out = ChromeFileSystemAccessPermissionContext::SensitiveEntryResult::
kTryAgain;
else if (type == "deny")
*out =
ChromeFileSystemAccessPermissionContext::SensitiveEntryResult::kAbort;
else
return false;
return true;
}
};
} // namespace gin
namespace {
using BlockType = ChromeFileSystemAccessPermissionContext::BlockType;
using HandleType = content::FileSystemAccessPermissionContext::HandleType;
using GrantType = electron::FileSystemAccessPermissionContext::GrantType;
using SensitiveEntryResult =
ChromeFileSystemAccessPermissionContext::SensitiveEntryResult;
using blink::mojom::PermissionStatus;
// Dictionary keys for the FILE_SYSTEM_LAST_PICKED_DIRECTORY website setting.
@ -527,11 +562,11 @@ void FileSystemAccessPermissionContext::ConfirmSensitiveEntryAccess(
content::GlobalRenderFrameHostId frame_id,
base::OnceCallback<void(SensitiveEntryResult)> callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
callback_ = std::move(callback);
auto after_blocklist_check_callback = base::BindOnce(
&FileSystemAccessPermissionContext::DidCheckPathAgainstBlocklist,
GetWeakPtr(), origin, path, handle_type, user_action, frame_id,
std::move(callback));
GetWeakPtr(), origin, path, handle_type, user_action, frame_id);
CheckPathAgainstBlocklist(path_type, path, handle_type,
std::move(after_blocklist_check_callback));
}
@ -570,31 +605,54 @@ void FileSystemAccessPermissionContext::PerformAfterWriteChecks(
std::move(callback).Run(AfterWriteCheckResult::kAllow);
}
void FileSystemAccessPermissionContext::RunRestrictedPathCallback(
SensitiveEntryResult result) {
if (callback_)
std::move(callback_).Run(result);
}
void FileSystemAccessPermissionContext::OnRestrictedPathResult(
gin::Arguments* args) {
SensitiveEntryResult result = SensitiveEntryResult::kAbort;
args->GetNext(&result);
RunRestrictedPathCallback(result);
}
void FileSystemAccessPermissionContext::DidCheckPathAgainstBlocklist(
const url::Origin& origin,
const base::FilePath& path,
HandleType handle_type,
UserAction user_action,
content::GlobalRenderFrameHostId frame_id,
base::OnceCallback<void(SensitiveEntryResult)> callback,
bool should_block) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (user_action == UserAction::kNone) {
std::move(callback).Run(should_block ? SensitiveEntryResult::kAbort
: SensitiveEntryResult::kAllowed);
RunRestrictedPathCallback(should_block ? SensitiveEntryResult::kAbort
: SensitiveEntryResult::kAllowed);
return;
}
// Chromium opens a dialog here, but in Electron's case we log and abort.
if (should_block) {
LOG(INFO) << path.value()
<< " is blocked by the blocklis and cannot be accessed";
std::move(callback).Run(SensitiveEntryResult::kAbort);
auto* session =
electron::api::Session::FromBrowserContext(browser_context());
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Object> details =
gin::DataObjectBuilder(isolate)
.Set("origin", origin.GetURL().spec())
.Set("isDirectory", handle_type == HandleType::kDirectory)
.Set("path", path)
.Build();
session->Emit(
"file-system-access-restricted", details,
base::BindRepeating(
&FileSystemAccessPermissionContext::OnRestrictedPathResult,
weak_factory_.GetWeakPtr()));
return;
}
std::move(callback).Run(SensitiveEntryResult::kAllowed);
RunRestrictedPathCallback(SensitiveEntryResult::kAllowed);
}
void FileSystemAccessPermissionContext::MaybeEvictEntries(

View file

@ -21,6 +21,10 @@
class GURL;
namespace gin {
class Arguments;
} // namespace gin
namespace base {
class FilePath;
} // namespace base
@ -128,14 +132,16 @@ class FileSystemAccessPermissionContext
const base::FilePath& path,
HandleType handle_type,
base::OnceCallback<void(bool)> callback);
void DidCheckPathAgainstBlocklist(
const url::Origin& origin,
const base::FilePath& path,
HandleType handle_type,
UserAction user_action,
content::GlobalRenderFrameHostId frame_id,
base::OnceCallback<void(SensitiveEntryResult)> callback,
bool should_block);
void DidCheckPathAgainstBlocklist(const url::Origin& origin,
const base::FilePath& path,
HandleType handle_type,
UserAction user_action,
content::GlobalRenderFrameHostId frame_id,
bool should_block);
void RunRestrictedPathCallback(SensitiveEntryResult result);
void OnRestrictedPathResult(gin::Arguments* args);
void MaybeEvictEntries(base::Value::Dict& dict);
@ -159,6 +165,8 @@ class FileSystemAccessPermissionContext
std::map<url::Origin, base::Value::Dict> id_pathinfo_map_;
base::OnceCallback<void(SensitiveEntryResult)> callback_;
base::WeakPtrFactory<FileSystemAccessPermissionContext> weak_factory_{this};
};