1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "extensions/browser/info_map.h" 6 7#include "base/strings/string_util.h" 8#include "content/public/browser/browser_thread.h" 9#include "extensions/browser/content_verifier.h" 10#include "extensions/common/constants.h" 11#include "extensions/common/extension.h" 12#include "extensions/common/extension_resource.h" 13#include "extensions/common/extension_set.h" 14#include "extensions/common/manifest_handlers/incognito_info.h" 15#include "extensions/common/manifest_handlers/shared_module_info.h" 16#include "extensions/common/permissions/permissions_data.h" 17#include "url/gurl.h" 18 19using content::BrowserThread; 20 21namespace extensions { 22 23namespace { 24 25void CheckOnValidThread() { DCHECK_CURRENTLY_ON(BrowserThread::IO); } 26 27} // namespace 28 29struct InfoMap::ExtraData { 30 // When the extension was installed. 31 base::Time install_time; 32 33 // True if the user has allowed this extension to run in incognito mode. 34 bool incognito_enabled; 35 36 // True if the user has disabled notifications for this extension manually. 37 bool notifications_disabled; 38 39 ExtraData(); 40 ~ExtraData(); 41}; 42 43InfoMap::ExtraData::ExtraData() 44 : incognito_enabled(false), notifications_disabled(false) { 45} 46 47InfoMap::ExtraData::~ExtraData() {} 48 49InfoMap::InfoMap() : signin_process_id_(-1) { 50} 51 52void InfoMap::AddExtension(const Extension* extension, 53 base::Time install_time, 54 bool incognito_enabled, 55 bool notifications_disabled) { 56 CheckOnValidThread(); 57 extensions_.Insert(extension); 58 disabled_extensions_.Remove(extension->id()); 59 60 extra_data_[extension->id()].install_time = install_time; 61 extra_data_[extension->id()].incognito_enabled = incognito_enabled; 62 extra_data_[extension->id()].notifications_disabled = notifications_disabled; 63} 64 65void InfoMap::RemoveExtension(const std::string& extension_id, 66 const UnloadedExtensionInfo::Reason reason) { 67 CheckOnValidThread(); 68 const Extension* extension = extensions_.GetByID(extension_id); 69 extra_data_.erase(extension_id); // we don't care about disabled extra data 70 bool was_uninstalled = (reason != UnloadedExtensionInfo::REASON_DISABLE && 71 reason != UnloadedExtensionInfo::REASON_TERMINATE); 72 if (extension) { 73 if (!was_uninstalled) 74 disabled_extensions_.Insert(extension); 75 extensions_.Remove(extension_id); 76 } else if (was_uninstalled) { 77 // If the extension was uninstalled, make sure it's removed from the map of 78 // disabled extensions. 79 disabled_extensions_.Remove(extension_id); 80 } else { 81 // NOTE: This can currently happen if we receive multiple unload 82 // notifications, e.g. setting incognito-enabled state for a 83 // disabled extension (e.g., via sync). See 84 // http://code.google.com/p/chromium/issues/detail?id=50582 . 85 NOTREACHED() << extension_id; 86 } 87} 88 89base::Time InfoMap::GetInstallTime(const std::string& extension_id) const { 90 ExtraDataMap::const_iterator iter = extra_data_.find(extension_id); 91 if (iter != extra_data_.end()) 92 return iter->second.install_time; 93 return base::Time(); 94} 95 96bool InfoMap::IsIncognitoEnabled(const std::string& extension_id) const { 97 // Keep in sync with duplicate in extensions/browser/process_manager.cc. 98 ExtraDataMap::const_iterator iter = extra_data_.find(extension_id); 99 if (iter != extra_data_.end()) 100 return iter->second.incognito_enabled; 101 return false; 102} 103 104bool InfoMap::CanCrossIncognito(const Extension* extension) const { 105 // This is duplicated from ExtensionService :(. 106 return IsIncognitoEnabled(extension->id()) && 107 !IncognitoInfo::IsSplitMode(extension); 108} 109 110void InfoMap::RegisterExtensionProcess(const std::string& extension_id, 111 int process_id, 112 int site_instance_id) { 113 if (!process_map_.Insert(extension_id, process_id, site_instance_id)) { 114 NOTREACHED() << "Duplicate extension process registration for: " 115 << extension_id << "," << process_id << "."; 116 } 117} 118 119void InfoMap::UnregisterExtensionProcess(const std::string& extension_id, 120 int process_id, 121 int site_instance_id) { 122 if (!process_map_.Remove(extension_id, process_id, site_instance_id)) { 123 NOTREACHED() << "Unknown extension process registration for: " 124 << extension_id << "," << process_id << "."; 125 } 126} 127 128void InfoMap::UnregisterAllExtensionsInProcess(int process_id) { 129 process_map_.RemoveAllFromProcess(process_id); 130} 131 132void InfoMap::GetExtensionsWithAPIPermissionForSecurityOrigin( 133 const GURL& origin, 134 int process_id, 135 APIPermission::ID permission, 136 ExtensionSet* extensions) const { 137 DCHECK(extensions); 138 139 if (origin.SchemeIs(kExtensionScheme)) { 140 const std::string& id = origin.host(); 141 const Extension* extension = extensions_.GetByID(id); 142 if (extension && 143 extension->permissions_data()->HasAPIPermission(permission) && 144 process_map_.Contains(id, process_id)) { 145 extensions->Insert(extension); 146 } 147 return; 148 } 149 150 ExtensionSet::const_iterator i = extensions_.begin(); 151 for (; i != extensions_.end(); ++i) { 152 if ((*i)->web_extent().MatchesSecurityOrigin(origin) && 153 process_map_.Contains((*i)->id(), process_id) && 154 (*i)->permissions_data()->HasAPIPermission(permission)) { 155 extensions->Insert(*i); 156 } 157 } 158} 159 160bool InfoMap::SecurityOriginHasAPIPermission(const GURL& origin, 161 int process_id, 162 APIPermission::ID permission) 163 const { 164 ExtensionSet extensions; 165 GetExtensionsWithAPIPermissionForSecurityOrigin( 166 origin, process_id, permission, &extensions); 167 return !extensions.is_empty(); 168} 169 170// This function is security sensitive. Bugs could cause problems that break 171// restrictions on local file access or NaCl's validation caching. If you modify 172// this function, please get a security review from a NaCl person. 173bool InfoMap::MapUrlToLocalFilePath(const GURL& file_url, 174 bool use_blocking_api, 175 base::FilePath* file_path) { 176 // Check that the URL is recognized by the extension system. 177 const Extension* extension = extensions_.GetExtensionOrAppByURL(file_url); 178 if (!extension) 179 return false; 180 181 // This is a short-cut which avoids calling a blocking file operation 182 // (GetFilePath()), so that this can be called on the IO thread. It only 183 // handles a subset of the urls. 184 if (!use_blocking_api) { 185 if (file_url.SchemeIs(extensions::kExtensionScheme)) { 186 std::string path = file_url.path(); 187 base::TrimString(path, "/", &path); // Remove first slash 188 *file_path = extension->path().AppendASCII(path); 189 return true; 190 } 191 return false; 192 } 193 194 std::string path = file_url.path(); 195 ExtensionResource resource; 196 197 if (SharedModuleInfo::IsImportedPath(path)) { 198 // Check if this is a valid path that is imported for this extension. 199 std::string new_extension_id; 200 std::string new_relative_path; 201 SharedModuleInfo::ParseImportedPath( 202 path, &new_extension_id, &new_relative_path); 203 const Extension* new_extension = extensions_.GetByID(new_extension_id); 204 if (!new_extension) 205 return false; 206 207 if (!SharedModuleInfo::ImportsExtensionById(extension, new_extension_id) || 208 !SharedModuleInfo::IsExportAllowed(new_extension, new_relative_path)) { 209 return false; 210 } 211 212 resource = new_extension->GetResource(new_relative_path); 213 } else { 214 // Check that the URL references a resource in the extension. 215 resource = extension->GetResource(path); 216 } 217 218 if (resource.empty()) 219 return false; 220 221 // GetFilePath is a blocking function call. 222 const base::FilePath resource_file_path = resource.GetFilePath(); 223 if (resource_file_path.empty()) 224 return false; 225 226 *file_path = resource_file_path; 227 return true; 228} 229 230QuotaService* InfoMap::GetQuotaService() { 231 CheckOnValidThread(); 232 if (!quota_service_) 233 quota_service_.reset(new QuotaService()); 234 return quota_service_.get(); 235} 236 237void InfoMap::SetSigninProcess(int process_id) { 238 signin_process_id_ = process_id; 239} 240 241bool InfoMap::IsSigninProcess(int process_id) const { 242 return process_id == signin_process_id_; 243} 244 245void InfoMap::SetNotificationsDisabled( 246 const std::string& extension_id, 247 bool notifications_disabled) { 248 ExtraDataMap::iterator iter = extra_data_.find(extension_id); 249 if (iter != extra_data_.end()) 250 iter->second.notifications_disabled = notifications_disabled; 251} 252 253bool InfoMap::AreNotificationsDisabled( 254 const std::string& extension_id) const { 255 ExtraDataMap::const_iterator iter = extra_data_.find(extension_id); 256 if (iter != extra_data_.end()) 257 return iter->second.notifications_disabled; 258 return false; 259} 260 261void InfoMap::SetContentVerifier(ContentVerifier* verifier) { 262 content_verifier_ = verifier; 263} 264 265InfoMap::~InfoMap() { 266 if (quota_service_) { 267 BrowserThread::DeleteSoon( 268 BrowserThread::IO, FROM_HERE, quota_service_.release()); 269 } 270} 271 272} // namespace extensions 273