| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "extensions/browser/extension_util.h" |
| |
| #include "base/no_destructor.h" |
| #include "build/chromeos_buildflags.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/site_instance.h" |
| #include "content/public/browser/storage_partition_config.h" |
| #include "extensions/browser/extension_prefs.h" |
| #include "extensions/browser/extension_registry.h" |
| #include "extensions/browser/extensions_browser_client.h" |
| #include "extensions/browser/ui_util.h" |
| #include "extensions/common/extension.h" |
| #include "extensions/common/features/behavior_feature.h" |
| #include "extensions/common/features/feature.h" |
| #include "extensions/common/features/feature_provider.h" |
| #include "extensions/common/manifest.h" |
| #include "extensions/common/manifest_handlers/incognito_info.h" |
| #include "extensions/common/manifest_handlers/shared_module_info.h" |
| #include "extensions/common/permissions/permissions_data.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| #include "base/system/sys_info.h" |
| #endif |
| |
| namespace extensions { |
| namespace util { |
| |
| namespace { |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| bool IsSigninProfileTestExtensionOnTestImage(const Extension* extension) { |
| if (extension->id() != extension_misc::kSigninProfileTestExtensionId) |
| return false; |
| base::SysInfo::CrashIfChromeOSNonTestImage(); |
| return true; |
| } |
| #endif |
| |
| } // namespace |
| |
| bool CanBeIncognitoEnabled(const Extension* extension) { |
| return IncognitoInfo::IsIncognitoAllowed(extension) && |
| (!extension->is_platform_app() || |
| extension->location() == Manifest::COMPONENT); |
| } |
| |
| bool IsIncognitoEnabled(const std::string& extension_id, |
| content::BrowserContext* context) { |
| const Extension* extension = |
| ExtensionRegistry::Get(context)->GetExtensionById( |
| extension_id, ExtensionRegistry::ENABLED); |
| if (extension) { |
| if (!CanBeIncognitoEnabled(extension)) |
| return false; |
| // If this is an existing component extension we always allow it to |
| // work in incognito mode. |
| if (Manifest::IsComponentLocation(extension->location())) |
| return true; |
| if (extension->is_login_screen_extension()) |
| return true; |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| if (IsSigninProfileTestExtensionOnTestImage(extension)) |
| return true; |
| #endif |
| } |
| return ExtensionPrefs::Get(context)->IsIncognitoEnabled(extension_id); |
| } |
| |
| bool CanCrossIncognito(const Extension* extension, |
| content::BrowserContext* context) { |
| // We allow the extension to see events and data from another profile iff it |
| // uses "spanning" behavior and it has incognito access. "split" mode |
| // extensions only see events for a matching profile. |
| CHECK(extension); |
| return IsIncognitoEnabled(extension->id(), context) && |
| !IncognitoInfo::IsSplitMode(extension); |
| } |
| |
| const std::string& GetPartitionDomainForExtension(const Extension* extension) { |
| // Extensions use their own ID for a partition domain. |
| return extension->id(); |
| } |
| |
| content::StoragePartitionConfig GetStoragePartitionConfigForExtensionId( |
| const std::string& extension_id, |
| content::BrowserContext* browser_context) { |
| if (ExtensionsBrowserClient::Get()->HasIsolatedStorage(extension_id, |
| browser_context)) { |
| // For extensions with isolated storage, the |extension_id| is |
| // the |partition_domain|. The |in_memory| and |partition_name| are only |
| // used in guest schemes so they are cleared here. |
| return content::StoragePartitionConfig::Create( |
| extension_id, std::string() /* partition_name */, false /*in_memory */); |
| } |
| |
| return content::StoragePartitionConfig::CreateDefault(); |
| } |
| |
| content::StoragePartition* GetStoragePartitionForExtensionId( |
| const std::string& extension_id, |
| content::BrowserContext* browser_context, |
| bool can_create) { |
| auto storage_partition_config = |
| GetStoragePartitionConfigForExtensionId(extension_id, browser_context); |
| content::StoragePartition* storage_partition = |
| content::BrowserContext::GetStoragePartition( |
| browser_context, storage_partition_config, can_create); |
| return storage_partition; |
| } |
| |
| // This function is security sensitive. Bugs could cause problems that break |
| // restrictions on local file access or NaCl's validation caching. If you modify |
| // this function, please get a security review from a NaCl person. |
| bool MapUrlToLocalFilePath(const ExtensionSet* extensions, |
| const GURL& file_url, |
| bool use_blocking_api, |
| base::FilePath* file_path) { |
| // Check that the URL is recognized by the extension system. |
| const Extension* extension = extensions->GetExtensionOrAppByURL(file_url); |
| if (!extension) |
| return false; |
| |
| // This is a short-cut which avoids calling a blocking file operation |
| // (GetFilePath()), so that this can be called on the non blocking threads. It |
| // only handles a subset of the urls. |
| if (!use_blocking_api) { |
| if (file_url.SchemeIs(extensions::kExtensionScheme)) { |
| std::string path = file_url.path(); |
| base::TrimString(path, "/", &path); // Remove first slash |
| *file_path = extension->path().AppendASCII(path); |
| return true; |
| } |
| return false; |
| } |
| |
| std::string path = file_url.path(); |
| ExtensionResource resource; |
| |
| if (SharedModuleInfo::IsImportedPath(path)) { |
| // Check if this is a valid path that is imported for this extension. |
| std::string new_extension_id; |
| std::string new_relative_path; |
| SharedModuleInfo::ParseImportedPath(path, &new_extension_id, |
| &new_relative_path); |
| const Extension* new_extension = extensions->GetByID(new_extension_id); |
| if (!new_extension) |
| return false; |
| |
| if (!SharedModuleInfo::ImportsExtensionById(extension, new_extension_id)) |
| return false; |
| |
| resource = new_extension->GetResource(new_relative_path); |
| } else { |
| // Check that the URL references a resource in the extension. |
| resource = extension->GetResource(path); |
| } |
| |
| if (resource.empty()) |
| return false; |
| |
| // GetFilePath is a blocking function call. |
| const base::FilePath resource_file_path = resource.GetFilePath(); |
| if (resource_file_path.empty()) |
| return false; |
| |
| *file_path = resource_file_path; |
| return true; |
| } |
| |
| bool CanWithholdPermissionsFromExtension(const Extension& extension) { |
| return CanWithholdPermissionsFromExtension( |
| extension.id(), extension.GetType(), extension.location()); |
| } |
| |
| bool CanWithholdPermissionsFromExtension(const ExtensionId& extension_id, |
| Manifest::Type type, |
| Manifest::Location location) { |
| // Some extensions must retain privilege to all requested host permissions. |
| // Specifically, extensions that don't show up in chrome:extensions (where |
| // withheld permissions couldn't be granted), extensions that are part of |
| // chrome or corporate policy, and extensions that are whitelisted to script |
| // everywhere must always have permission to run on a page. |
| return ui_util::ShouldDisplayInExtensionSettings(type, location) && |
| !Manifest::IsPolicyLocation(location) && |
| !Manifest::IsComponentLocation(location) && |
| !PermissionsData::CanExecuteScriptEverywhere(extension_id, location); |
| } |
| |
| // The below functionality maps a context to a unique id by increasing a static |
| // counter. |
| int GetBrowserContextId(content::BrowserContext* context) { |
| using ContextIdMap = std::map<content::BrowserContext*, int>; |
| |
| static int next_id = 0; |
| static base::NoDestructor<ContextIdMap> context_map; |
| |
| // we need to get the original context to make sure we take the right context. |
| content::BrowserContext* original_context = |
| ExtensionsBrowserClient::Get()->GetOriginalContext(context); |
| auto iter = context_map->find(original_context); |
| if (iter == context_map->end()) { |
| iter = |
| context_map->insert(std::make_pair(original_context, next_id++)).first; |
| } |
| return iter->second; |
| } |
| |
| } // namespace util |
| } // namespace extensions |