ced52c9e978fe4da666c8e0e0f2aff3cd0044d6e
[platform/framework/web/crosswalk.git] / src / extensions / browser / info_map.cc
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
19 using content::BrowserThread;
20
21 namespace extensions {
22
23 namespace {
24
25 void CheckOnValidThread() { DCHECK_CURRENTLY_ON(BrowserThread::IO); }
26
27 }  // namespace
28
29 struct 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
43 InfoMap::ExtraData::ExtraData()
44     : incognito_enabled(false), notifications_disabled(false) {
45 }
46
47 InfoMap::ExtraData::~ExtraData() {}
48
49 InfoMap::InfoMap() : signin_process_id_(-1) {
50 }
51
52 void 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
65 void 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
89 base::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
96 bool 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
104 bool InfoMap::CanCrossIncognito(const Extension* extension) const {
105   // This is duplicated from ExtensionService :(.
106   return IsIncognitoEnabled(extension->id()) &&
107          !IncognitoInfo::IsSplitMode(extension);
108 }
109
110 void 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
119 void 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
128 void InfoMap::UnregisterAllExtensionsInProcess(int process_id) {
129   process_map_.RemoveAllFromProcess(process_id);
130 }
131
132 void InfoMap::RegisterExtensionWorkerProcess(const std::string& extension_id,
133                                              int process_id,
134                                              int site_instance_id) {
135   if (!worker_process_map_.Insert(extension_id, process_id, site_instance_id)) {
136     NOTREACHED() << "Duplicate extension worker process registration for: "
137                  << extension_id << "," << process_id << ".";
138   }
139 }
140
141 void InfoMap::UnregisterExtensionWorkerProcess(int process_id) {
142   worker_process_map_.RemoveAllFromProcess(process_id);
143 }
144
145 void InfoMap::GetExtensionsWithAPIPermissionForSecurityOrigin(
146     const GURL& origin,
147     int process_id,
148     APIPermission::ID permission,
149     ExtensionSet* extensions) const {
150   DCHECK(extensions);
151
152   if (origin.SchemeIs(kExtensionScheme)) {
153     const std::string& id = origin.host();
154     const Extension* extension = extensions_.GetByID(id);
155     if (extension &&
156         extension->permissions_data()->HasAPIPermission(permission) &&
157         process_map_.Contains(id, process_id)) {
158       extensions->Insert(extension);
159     }
160     return;
161   }
162
163   ExtensionSet::const_iterator i = extensions_.begin();
164   for (; i != extensions_.end(); ++i) {
165     if ((*i)->web_extent().MatchesSecurityOrigin(origin) &&
166         process_map_.Contains((*i)->id(), process_id) &&
167         (*i)->permissions_data()->HasAPIPermission(permission)) {
168       extensions->Insert(*i);
169     }
170   }
171 }
172
173 bool InfoMap::SecurityOriginHasAPIPermission(const GURL& origin,
174                                              int process_id,
175                                              APIPermission::ID permission)
176     const {
177   ExtensionSet extensions;
178   GetExtensionsWithAPIPermissionForSecurityOrigin(
179       origin, process_id, permission, &extensions);
180   return !extensions.is_empty();
181 }
182
183 // This function is security sensitive. Bugs could cause problems that break
184 // restrictions on local file access or NaCl's validation caching. If you modify
185 // this function, please get a security review from a NaCl person.
186 bool InfoMap::MapUrlToLocalFilePath(const GURL& file_url,
187                                     bool use_blocking_api,
188                                     base::FilePath* file_path) {
189   // Check that the URL is recognized by the extension system.
190   const Extension* extension = extensions_.GetExtensionOrAppByURL(file_url);
191   if (!extension)
192     return false;
193
194   // This is a short-cut which avoids calling a blocking file operation
195   // (GetFilePath()), so that this can be called on the IO thread. It only
196   // handles a subset of the urls.
197   if (!use_blocking_api) {
198     if (file_url.SchemeIs(extensions::kExtensionScheme)) {
199       std::string path = file_url.path();
200       base::TrimString(path, "/", &path);  // Remove first slash
201       *file_path = extension->path().AppendASCII(path);
202       return true;
203     }
204     return false;
205   }
206
207   std::string path = file_url.path();
208   ExtensionResource resource;
209
210   if (SharedModuleInfo::IsImportedPath(path)) {
211     // Check if this is a valid path that is imported for this extension.
212     std::string new_extension_id;
213     std::string new_relative_path;
214     SharedModuleInfo::ParseImportedPath(
215         path, &new_extension_id, &new_relative_path);
216     const Extension* new_extension = extensions_.GetByID(new_extension_id);
217     if (!new_extension)
218       return false;
219
220     if (!SharedModuleInfo::ImportsExtensionById(extension, new_extension_id) ||
221         !SharedModuleInfo::IsExportAllowed(new_extension, new_relative_path)) {
222       return false;
223     }
224
225     resource = new_extension->GetResource(new_relative_path);
226   } else {
227     // Check that the URL references a resource in the extension.
228     resource = extension->GetResource(path);
229   }
230
231   if (resource.empty())
232     return false;
233
234   // GetFilePath is a blocking function call.
235   const base::FilePath resource_file_path = resource.GetFilePath();
236   if (resource_file_path.empty())
237     return false;
238
239   *file_path = resource_file_path;
240   return true;
241 }
242
243 QuotaService* InfoMap::GetQuotaService() {
244   CheckOnValidThread();
245   if (!quota_service_)
246     quota_service_.reset(new QuotaService());
247   return quota_service_.get();
248 }
249
250 void InfoMap::SetSigninProcess(int process_id) {
251   signin_process_id_ = process_id;
252 }
253
254 bool InfoMap::IsSigninProcess(int process_id) const {
255   return process_id == signin_process_id_;
256 }
257
258 void InfoMap::SetNotificationsDisabled(
259     const std::string& extension_id,
260     bool notifications_disabled) {
261   ExtraDataMap::iterator iter = extra_data_.find(extension_id);
262   if (iter != extra_data_.end())
263     iter->second.notifications_disabled = notifications_disabled;
264 }
265
266 bool InfoMap::AreNotificationsDisabled(
267     const std::string& extension_id) const {
268   ExtraDataMap::const_iterator iter = extra_data_.find(extension_id);
269   if (iter != extra_data_.end())
270     return iter->second.notifications_disabled;
271   return false;
272 }
273
274 void InfoMap::SetContentVerifier(ContentVerifier* verifier) {
275   content_verifier_ = verifier;
276 }
277
278 InfoMap::~InfoMap() {
279   if (quota_service_) {
280     BrowserThread::DeleteSoon(
281         BrowserThread::IO, FROM_HERE, quota_service_.release());
282   }
283 }
284
285 }  // namespace extensions