chromium/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc

// Copyright 2019 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/file_system_access/chrome_file_system_access_permission_context.h"

#include <iterator>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <utility>

#include "base/base_paths.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/json/values_util.h"
#include "base/metrics/histogram_functions.h"
#include "base/notreached.h"
#include "base/path_service.h"
#include "base/ranges/algorithm.h"
#include "base/strings/strcat.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/enterprise/connectors/analysis/content_analysis_delegate.h"
#include "chrome/browser/file_system_access/file_system_access_permission_request_manager.h"
#include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/file_system_access/file_system_access_dangerous_file_dialog.h"
#include "chrome/browser/ui/file_system_access/file_system_access_dialogs.h"
#include "chrome/browser/ui/file_system_access/file_system_access_restricted_directory_dialog.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/grit/generated_resources.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/pdf/common/pdf_util.h"
#include "components/permissions/features.h"
#include "components/permissions/object_permission_context_base.h"
#include "components/permissions/permission_decision_auto_blocker.h"
#include "components/permissions/permission_uma_util.h"
#include "components/permissions/permission_util.h"
#include "components/safe_browsing/buildflags.h"
#include "components/safe_browsing/content/common/file_type_policies.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/disallow_activation_reason.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.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"

#if !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/permissions/one_time_permissions_tracker_factory.h"
#include "chrome/browser/permissions/one_time_permissions_tracker_observer.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_install_manager_observer.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#endif

#if BUILDFLAG(FULL_SAFE_BROWSING)
#include "chrome/browser/safe_browsing/download_protection/download_protection_service.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#endif

namespace {

FileRequestData;
RequestAccess;
HandleType;
PersistedGrantStatus;
GrantType;
PermissionStatus;
PermissionAction;

// This long after the last top-level tab or window for an origin is closed (or
// is navigated to another origin), all the permissions for that origin will be
// revoked.
constexpr base::TimeDelta kPermissionRevocationTimeout =;

// Dictionary keys for the FILE_SYSTEM_ACCESS_CHOOSER_DATA setting.
// `kPermissionPathKey[] = "path"` is defined in the header file.
const char kPermissionIsDirectoryKey[] =;
const char kPermissionWritableKey[] =;
const char kPermissionReadableKey[] =;
const char kDeprecatedPermissionLastUsedTimeKey[] =;

// Dictionary keys for the FILE_SYSTEM_LAST_PICKED_DIRECTORY website setting.
// Schema (per origin):
// {
//  ...
//   {
//     "default-id" : { "path" : <path> , "path-type" : <type>}
//     "custom-id-fruit" : { "path" : <path> , "path-type" : <type> }
//     "custom-id-flower" : { "path" : <path> , "path-type" : <type> }
//     ...
//   }
//  ...
// }
const char kDefaultLastPickedDirectoryKey[] =;
const char kCustomLastPickedDirectoryKey[] =;
const char kPathKey[] =;
const char kPathTypeKey[] =;
const char kTimestampKey[] =;

void ShowFileSystemAccessRestrictedDirectoryDialogOnUIThread(
    content::GlobalRenderFrameHostId frame_id,
    const url::Origin& origin,
    HandleType handle_type,
    base::OnceCallback<
        void(ChromeFileSystemAccessPermissionContext::SensitiveEntryResult)>
        callback) {}

void ShowFileSystemAccessDangerousFileDialogOnUIThread(
    content::GlobalRenderFrameHostId frame_id,
    const url::Origin& origin,
    const base::FilePath& path,
    base::OnceCallback<
        void(ChromeFileSystemAccessPermissionContext::SensitiveEntryResult)>
        callback) {}

#if BUILDFLAG(IS_WIN)
bool ContainsInvalidDNSCharacter(base::FilePath::StringType hostname) {
  for (base::FilePath::CharType c : hostname) {
    if (!((c >= L'A' && c <= L'Z') || (c >= L'a' && c <= L'z') ||
          (c >= L'0' && c <= L'9') || (c == L'.') || (c == L'-'))) {
      return true;
    }
  }
  return false;
}

bool MaybeIsLocalUNCPath(const base::FilePath& path) {
  if (!path.IsNetwork()) {
    return false;
  }

  const std::vector<base::FilePath::StringType> components =
      path.GetComponents();

  // Check for server name that could represent a local system. We only
  // check for a very short list, as it is impossible to cover all different
  // variants on Windows.
  if (components.size() >= 2 &&
      (base::FilePath::CompareEqualIgnoreCase(components[1],
                                              FILE_PATH_LITERAL("localhost")) ||
       components[1] == FILE_PATH_LITERAL("127.0.0.1") ||
       components[1] == FILE_PATH_LITERAL(".") ||
       components[1] == FILE_PATH_LITERAL("?") ||
       ContainsInvalidDNSCharacter(components[1]))) {
    return true;
  }

  // In case we missed the server name check above, we also check for shares
  // ending with '$' as they represent pre-defined shares, including the local
  // drives.
  for (size_t i = 2; i < components.size(); ++i) {
    if (components[i].back() == L'$') {
      return true;
    }
  }

  return false;
}
#endif

// Sentinel used to indicate that no PathService key is specified for a path in
// the struct below.
constexpr const int kNoBasePathKey =;

enum BlockType {};

const struct {} kBlockedPaths[] =;

// Describes a rule for blocking a directory, which can be constructed
// dynamically (based on state) or statically (from kBlockedPaths).
struct BlockPathRule {};

bool ShouldBlockAccessToPath(const base::FilePath& path,
                             HandleType handle_type,
                             std::vector<BlockPathRule> rules) {}

void DoSafeBrowsingCheckOnUIThread(
    content::GlobalRenderFrameHostId frame_id,
    std::unique_ptr<content::FileSystemAccessWriteItem> item,
    safe_browsing::CheckDownloadCallback callback) {}

ChromeFileSystemAccessPermissionContext::AfterWriteCheckResult
InterpretSafeBrowsingResult(safe_browsing::DownloadCheckResult result) {}

std::string GenerateLastPickedDirectoryKey(const std::string& id) {}

std::string_view PathAsPermissionKey(const base::FilePath& path) {}

std::string_view GetGrantKeyFromGrantType(GrantType type) {}

bool FileHasDangerousExtension(const url::Origin& origin,
                               const base::FilePath& path,
                               Profile* profile) {}

}  // namespace

ChromeFileSystemAccessPermissionContext::Grants::Grants() = default;
ChromeFileSystemAccessPermissionContext::Grants::~Grants() = default;
ChromeFileSystemAccessPermissionContext::Grants::Grants(Grants&&) = default;
ChromeFileSystemAccessPermissionContext::Grants&
ChromeFileSystemAccessPermissionContext::Grants::operator=(Grants&&) = default;

class ChromeFileSystemAccessPermissionContext::PermissionGrantImpl
    : public content::FileSystemAccessPermissionGrant {};

struct ChromeFileSystemAccessPermissionContext::OriginState {};

ChromeFileSystemAccessPermissionContext::
    ChromeFileSystemAccessPermissionContext(content::BrowserContext* context,
                                            const base::Clock* clock)
    :{}

ChromeFileSystemAccessPermissionContext::
    ~ChromeFileSystemAccessPermissionContext() = default;

bool ChromeFileSystemAccessPermissionContext::RevokeActiveGrants(
    const url::Origin& origin,
    base::FilePath file_path) {}

void ChromeFileSystemAccessPermissionContext::RevokeAllActiveGrants() {}

scoped_refptr<content::FileSystemAccessPermissionGrant>
ChromeFileSystemAccessPermissionContext::GetReadPermissionGrant(
    const url::Origin& origin,
    const base::FilePath& path,
    HandleType handle_type,
    UserAction user_action) {}

scoped_refptr<content::FileSystemAccessPermissionGrant>
ChromeFileSystemAccessPermissionContext::GetWritePermissionGrant(
    const url::Origin& origin,
    const base::FilePath& path,
    HandleType handle_type,
    UserAction user_action) {}

// Return extended permission grants for an origin.
std::vector<std::unique_ptr<permissions::ObjectPermissionContextBase::Object>>
ChromeFileSystemAccessPermissionContext::GetExtendedPersistedObjects(
    const url::Origin& origin) {}

// Returns extended grants or active grants for an origin.
std::vector<std::unique_ptr<permissions::ObjectPermissionContextBase::Object>>
ChromeFileSystemAccessPermissionContext::GetGrantedObjects(
    const url::Origin& origin) {}

// Returns all origins' extended grants or active grants.
std::vector<std::unique_ptr<permissions::ObjectPermissionContextBase::Object>>
ChromeFileSystemAccessPermissionContext::GetAllGrantedObjects() {}

// Returns origins that have either extended grants or active grants.
std::set<url::Origin>
ChromeFileSystemAccessPermissionContext::GetOriginsWithGrants() {}

std::string ChromeFileSystemAccessPermissionContext::GetKeyForObject(
    const base::Value::Dict& object) {}

bool ChromeFileSystemAccessPermissionContext::IsValidObject(
    const base::Value::Dict& dict) {}

std::u16string ChromeFileSystemAccessPermissionContext::GetObjectDisplayName(
    const base::Value::Dict& object) {}

ContentSetting
ChromeFileSystemAccessPermissionContext::GetReadGuardContentSetting(
    const url::Origin& origin) const {}

ContentSetting
ChromeFileSystemAccessPermissionContext::GetWriteGuardContentSetting(
    const url::Origin& origin) const {}

std::vector<base::FilePath>
ChromeFileSystemAccessPermissionContext::GetGrantedPaths(
    const url::Origin& origin) {}

bool ChromeFileSystemAccessPermissionContext::CanObtainReadPermission(
    const url::Origin& origin) {}

bool ChromeFileSystemAccessPermissionContext::CanObtainWritePermission(
    const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::ConfirmSensitiveEntryAccess(
    const url::Origin& origin,
    PathType path_type,
    const base::FilePath& path,
    HandleType handle_type,
    UserAction user_action,
    content::GlobalRenderFrameHostId frame_id,
    base::OnceCallback<void(SensitiveEntryResult)> callback) {}

void ChromeFileSystemAccessPermissionContext::CheckPathsAgainstEnterprisePolicy(
    std::vector<PathInfo> entries,
    content::GlobalRenderFrameHostId frame_id,
    EntriesAllowedByEnterprisePolicyCallback callback) {}

#if BUILDFLAG(ENTERPRISE_CLOUD_CONTENT_ANALYSIS)

void ChromeFileSystemAccessPermissionContext::OnContentAnalysisComplete(
    std::vector<PathInfo> entries,
    EntriesAllowedByEnterprisePolicyCallback callback,
    std::vector<base::FilePath> paths,
    std::vector<bool> allowed) {}

#endif  // BUILDFLAG(ENTERPRISE_CLOUD_CONTENT_ANALYSIS)

void ChromeFileSystemAccessPermissionContext::CheckPathAgainstBlocklist(
    PathType path_type,
    const base::FilePath& path,
    HandleType handle_type,
    base::OnceCallback<void(bool)> callback) {}

void ChromeFileSystemAccessPermissionContext::PerformAfterWriteChecks(
    std::unique_ptr<content::FileSystemAccessWriteItem> item,
    content::GlobalRenderFrameHostId frame_id,
    base::OnceCallback<void(AfterWriteCheckResult)> callback) {}

void ChromeFileSystemAccessPermissionContext::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 ChromeFileSystemAccessPermissionContext::MaybeEvictEntries(
    base::Value::Dict& dict) {}

void ChromeFileSystemAccessPermissionContext::SetLastPickedDirectory(
    const url::Origin& origin,
    const std::string& id,
    const base::FilePath& path,
    const PathType type) {}

ChromeFileSystemAccessPermissionContext::PathInfo
ChromeFileSystemAccessPermissionContext::GetLastPickedDirectory(
    const url::Origin& origin,
    const std::string& id) {}

base::FilePath
ChromeFileSystemAccessPermissionContext::GetWellKnownDirectoryPath(
    blink::mojom::WellKnownDirectory directory,
    const url::Origin& origin) {}

std::u16string ChromeFileSystemAccessPermissionContext::GetPickerTitle(
    const blink::mojom::FilePickerOptionsPtr& options) {}

void ChromeFileSystemAccessPermissionContext::NotifyEntryMoved(
    const url::Origin& origin,
    const base::FilePath& old_path,
    const base::FilePath& new_path) {}

void ChromeFileSystemAccessPermissionContext::
    OnFileCreatedFromShowSaveFilePicker(const GURL& file_picker_binding_context,
                                        const storage::FileSystemURL& url) {}

base::CallbackListSubscription ChromeFileSystemAccessPermissionContext::
    AddFileCreatedFromShowSaveFilePickerCallback(
        FileCreatedFromShowSaveFilePickerCallbackList::CallbackType callback) {}

ChromeFileSystemAccessPermissionContext::Grants
ChromeFileSystemAccessPermissionContext::ConvertObjectsToGrants(
    const std::vector<std::unique_ptr<Object>> objects) {}

void ChromeFileSystemAccessPermissionContext::
    CreatePersistedGrantsFromActiveGrants(const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::RevokeGrant(
    const url::Origin& origin,
    const base::FilePath& file_path) {}

void ChromeFileSystemAccessPermissionContext::RevokeGrants(
    const url::Origin& origin) {}

bool ChromeFileSystemAccessPermissionContext::OriginHasReadAccess(
    const url::Origin& origin) {}

bool ChromeFileSystemAccessPermissionContext::OriginHasWriteAccess(
    const url::Origin& origin) {}

// All tabs for a given origin have been backgrounded or cleared in the past
// 16 hours. When this happens, we update the given origin's `OriginState` to
// note that all tabs were recently backgrounded.
#if !BUILDFLAG(IS_ANDROID)
void ChromeFileSystemAccessPermissionContext::OnAllTabsInBackgroundTimerExpired(
    const url::Origin& origin,
    const OneTimePermissionsTrackerObserver::BackgroundExpiryType&
        expiry_type) {}

void ChromeFileSystemAccessPermissionContext::OnLastPageFromOriginClosed(
    const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::OnShutdown() {}

void ChromeFileSystemAccessPermissionContext::OnWebAppInstalled(
    const webapps::AppId& app_id) {}

void ChromeFileSystemAccessPermissionContext::OnWebAppInstalledWithOsHooks(
    const webapps::AppId& app_id) {}

void ChromeFileSystemAccessPermissionContext::OnWebAppWillBeUninstalled(
    const webapps::AppId& app_id) {}

void ChromeFileSystemAccessPermissionContext::
    OnWebAppInstallManagerDestroyed() {}
#endif

void ChromeFileSystemAccessPermissionContext::NavigatedAwayFromOrigin(
    const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::TriggerTimersForTesting() {}

void ChromeFileSystemAccessPermissionContext::MaybeCleanupPermissions(
    const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::CleanupPermissions(
    const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::
    OnRestorePermissionAllowedEveryTime(const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::OnRestorePermissionAllowedOnce(
    const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::
    UpdateGrantsOnRestorePermissionAllowed(const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::
    OnRestorePermissionDeniedOrDismissed(const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::OnRestorePermissionIgnored(
    const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::
    UpdateGrantsOnRestorePermissionNotAllowed(const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::
    UpdateGrantsOnPermissionRequestResult(const url::Origin& origin) {}

bool ChromeFileSystemAccessPermissionContext::AncestorHasActivePermission(
    const url::Origin& origin,
    const base::FilePath& path,
    GrantType grant_type) const {}

bool ChromeFileSystemAccessPermissionContext::HasGrantedActivePermissionStatus(
    PermissionGrantImpl* grant) const {}

bool ChromeFileSystemAccessPermissionContext::
    IsEligibleToUpgradePermissionRequestToRestorePrompt(
        const url::Origin& origin,
        const base::FilePath& file_path,
        HandleType handle_type,
        UserAction user_action,
        GrantType grant_type) {}

std::vector<FileRequestData> ChromeFileSystemAccessPermissionContext::
    GetFileRequestDataForRestorePermissionPrompt(const url::Origin& origin) {}

bool ChromeFileSystemAccessPermissionContext::HasPersistedGrantObject(
    const url::Origin& origin,
    const base::FilePath& file_path,
    HandleType handle_type,
    GrantType grant_type) {}

bool ChromeFileSystemAccessPermissionContext::HasMatchingValue(
    const base::Value::Dict& value,
    const base::FilePath& file_path,
    HandleType handle_type,
    GrantType grant_type) {}

void ChromeFileSystemAccessPermissionContext::
    SetOriginHasExtendedPermissionForTesting(const url::Origin& origin) {}

scoped_refptr<content::FileSystemAccessPermissionGrant>
ChromeFileSystemAccessPermissionContext::
    GetExtendedReadPermissionGrantForTesting(  // IN-TEST
        const url::Origin& origin,
        const base::FilePath& path,
        HandleType handle_type) {}

scoped_refptr<content::FileSystemAccessPermissionGrant>
ChromeFileSystemAccessPermissionContext::
    GetExtendedWritePermissionGrantForTesting(  // IN-TEST
        const url::Origin& origin,
        const base::FilePath& path,
        HandleType handle_type) {}

void ChromeFileSystemAccessPermissionContext::Shutdown() {}

bool ChromeFileSystemAccessPermissionContext::
    CanAutoGrantViaPersistentPermission(const url::Origin& origin,
                                        const base::FilePath& path,
                                        HandleType handle_type,
                                        GrantType grant_type) {}

bool ChromeFileSystemAccessPermissionContext::
    CanAutoGrantViaAncestorPersistentPermission(const url::Origin& origin,
                                                const base::FilePath& path,
                                                GrantType grant_type) {}

bool ChromeFileSystemAccessPermissionContext::OriginHasExtendedPermission(
    const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::SetOriginExtendedPermissionByUser(
    const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::
    RemoveOriginExtendedPermissionByUser(const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::RemoveExtendedPermission(
    const url::Origin& origin) {}

void ChromeFileSystemAccessPermissionContext::UpgradeToExtendedPermission(
    const url::Origin& origin) {}

ChromeFileSystemAccessPermissionContext::PersistedGrantType
ChromeFileSystemAccessPermissionContext::GetPersistedGrantType(
    const url::Origin& origin) {}

PersistedGrantStatus
ChromeFileSystemAccessPermissionContext::GetPersistedGrantStatus(
    const url::Origin& origin) const {}

void ChromeFileSystemAccessPermissionContext::SetPersistedGrantStatus(
    const url::Origin& origin,
    PersistedGrantStatus persisted_grant_status) {}

void ChromeFileSystemAccessPermissionContext::PermissionGrantDestroyed(
    PermissionGrantImpl* grant) {}

void ChromeFileSystemAccessPermissionContext::ScheduleUsageIconUpdate() {}

void ChromeFileSystemAccessPermissionContext::DoUsageIconUpdate() {}

base::WeakPtr<ChromeFileSystemAccessPermissionContext>
ChromeFileSystemAccessPermissionContext::GetWeakPtr() {}