• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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 "chrome/browser/extensions/pending_extension_manager.h"
6 
7 #include <algorithm>
8 
9 #include "base/logging.h"
10 #include "base/version.h"
11 #include "chrome/common/extensions/extension_constants.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "extensions/browser/extension_prefs.h"
14 #include "extensions/browser/extension_registry.h"
15 #include "extensions/common/extension.h"
16 #include "url/gurl.h"
17 
18 using content::BrowserThread;
19 
20 namespace {
21 
22 // Install predicate used by AddFromExternalUpdateUrl().
AlwaysInstall(const extensions::Extension * extension)23 bool AlwaysInstall(const extensions::Extension* extension) {
24   return true;
25 }
26 
GetVersionString(const Version & version)27 std::string GetVersionString(const Version& version) {
28   return version.IsValid() ? version.GetString() : "invalid";
29 }
30 
31 }  // namespace
32 
33 namespace extensions {
34 
PendingExtensionManager(content::BrowserContext * context)35 PendingExtensionManager::PendingExtensionManager(
36     content::BrowserContext* context)
37     : context_(context) {}
38 
~PendingExtensionManager()39 PendingExtensionManager::~PendingExtensionManager() {}
40 
GetById(const std::string & id) const41 const PendingExtensionInfo* PendingExtensionManager::GetById(
42     const std::string& id) const {
43   PendingExtensionList::const_iterator iter;
44   for (iter = pending_extension_list_.begin();
45        iter != pending_extension_list_.end();
46        ++iter) {
47     if (id == iter->id())
48       return &(*iter);
49   }
50 
51   return NULL;
52 }
53 
Remove(const std::string & id)54 bool PendingExtensionManager::Remove(const std::string& id) {
55   PendingExtensionList::iterator iter;
56   for (iter = pending_extension_list_.begin();
57        iter != pending_extension_list_.end();
58        ++iter) {
59     if (id == iter->id()) {
60       pending_extension_list_.erase(iter);
61       return true;
62     }
63   }
64 
65   return false;
66 }
67 
IsIdPending(const std::string & id) const68 bool PendingExtensionManager::IsIdPending(const std::string& id) const {
69   return GetById(id) != NULL;
70 }
71 
HasPendingExtensions() const72 bool PendingExtensionManager::HasPendingExtensions() const {
73   return !pending_extension_list_.empty();
74 }
75 
HasPendingExtensionFromSync() const76 bool PendingExtensionManager::HasPendingExtensionFromSync() const {
77   PendingExtensionList::const_iterator iter;
78   for (iter = pending_extension_list_.begin();
79        iter != pending_extension_list_.end();
80        ++iter) {
81     if (iter->is_from_sync())
82       return true;
83   }
84 
85   return false;
86 }
87 
AddFromSync(const std::string & id,const GURL & update_url,PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,bool install_silently,bool remote_install)88 bool PendingExtensionManager::AddFromSync(
89     const std::string& id,
90     const GURL& update_url,
91     PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
92     bool install_silently,
93     bool remote_install) {
94   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
95 
96   if (ExtensionRegistry::Get(context_)->GetExtensionById(
97           id, ExtensionRegistry::EVERYTHING)) {
98     LOG(ERROR) << "Trying to add pending extension " << id
99                << " which already exists";
100     return false;
101   }
102 
103   // Make sure we don't ever try to install the CWS app, because even though
104   // it is listed as a syncable app (because its values need to be synced) it
105   // should already be installed on every instance.
106   if (id == extension_misc::kWebStoreAppId) {
107     NOTREACHED();
108     return false;
109   }
110 
111   static const bool kIsFromSync = true;
112   static const Manifest::Location kSyncLocation = Manifest::INTERNAL;
113   static const bool kMarkAcknowledged = false;
114 
115   return AddExtensionImpl(id,
116                           std::string(),
117                           update_url,
118                           Version(),
119                           should_allow_install,
120                           kIsFromSync,
121                           install_silently,
122                           kSyncLocation,
123                           Extension::NO_FLAGS,
124                           kMarkAcknowledged,
125                           remote_install);
126 }
127 
AddFromExtensionImport(const std::string & id,const GURL & update_url,PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install)128 bool PendingExtensionManager::AddFromExtensionImport(
129     const std::string& id,
130     const GURL& update_url,
131     PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install) {
132   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
133 
134   if (ExtensionRegistry::Get(context_)->GetExtensionById(
135           id, ExtensionRegistry::EVERYTHING)) {
136     LOG(ERROR) << "Trying to add pending extension " << id
137                << " which already exists";
138     return false;
139   }
140 
141   static const bool kIsFromSync = false;
142   static const bool kInstallSilently = true;
143   static const Manifest::Location kManifestLocation = Manifest::INTERNAL;
144   static const bool kMarkAcknowledged = false;
145   static const bool kRemoteInstall = false;
146 
147   return AddExtensionImpl(id,
148                           std::string(),
149                           update_url,
150                           Version(),
151                           should_allow_install,
152                           kIsFromSync,
153                           kInstallSilently,
154                           kManifestLocation,
155                           Extension::NO_FLAGS,
156                           kMarkAcknowledged,
157                           kRemoteInstall);
158 }
159 
AddFromExternalUpdateUrl(const std::string & id,const std::string & install_parameter,const GURL & update_url,Manifest::Location location,int creation_flags,bool mark_acknowledged)160 bool PendingExtensionManager::AddFromExternalUpdateUrl(
161     const std::string& id,
162     const std::string& install_parameter,
163     const GURL& update_url,
164     Manifest::Location location,
165     int creation_flags,
166     bool mark_acknowledged) {
167   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
168 
169   static const bool kIsFromSync = false;
170   static const bool kInstallSilently = true;
171   static const bool kRemoteInstall = false;
172 
173   const Extension* extension = ExtensionRegistry::Get(context_)
174       ->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
175   if (extension && location == Manifest::GetHigherPriorityLocation(
176                                    location, extension->location())) {
177     // If the new location has higher priority than the location of an existing
178     // extension, let the update process overwrite the existing extension.
179   } else {
180     if (ExtensionPrefs::Get(context_)->IsExternalExtensionUninstalled(id))
181       return false;
182 
183     if (extension) {
184       LOG(DFATAL) << "Trying to add extension " << id
185                   << " by external update, but it is already installed.";
186       return false;
187     }
188   }
189 
190   return AddExtensionImpl(id,
191                           install_parameter,
192                           update_url,
193                           Version(),
194                           &AlwaysInstall,
195                           kIsFromSync,
196                           kInstallSilently,
197                           location,
198                           creation_flags,
199                           mark_acknowledged,
200                           kRemoteInstall);
201 }
202 
203 
AddFromExternalFile(const std::string & id,Manifest::Location install_source,const Version & version,int creation_flags,bool mark_acknowledged)204 bool PendingExtensionManager::AddFromExternalFile(
205     const std::string& id,
206     Manifest::Location install_source,
207     const Version& version,
208     int creation_flags,
209     bool mark_acknowledged) {
210   // TODO(skerner): AddFromSync() checks to see if the extension is
211   // installed, but this method assumes that the caller already
212   // made sure it is not installed.  Make all AddFrom*() methods
213   // consistent.
214   const GURL& kUpdateUrl = GURL::EmptyGURL();
215   static const bool kIsFromSync = false;
216   static const bool kInstallSilently = true;
217   static const bool kRemoteInstall = false;
218 
219   return AddExtensionImpl(id,
220                           std::string(),
221                           kUpdateUrl,
222                           version,
223                           &AlwaysInstall,
224                           kIsFromSync,
225                           kInstallSilently,
226                           install_source,
227                           creation_flags,
228                           mark_acknowledged,
229                           kRemoteInstall);
230 }
231 
GetPendingIdsForUpdateCheck(std::list<std::string> * out_ids_for_update_check) const232 void PendingExtensionManager::GetPendingIdsForUpdateCheck(
233     std::list<std::string>* out_ids_for_update_check) const {
234   PendingExtensionList::const_iterator iter;
235   for (iter = pending_extension_list_.begin();
236        iter != pending_extension_list_.end();
237        ++iter) {
238     Manifest::Location install_source = iter->install_source();
239 
240     // Some install sources read a CRX from the filesystem.  They can
241     // not be fetched from an update URL, so don't include them in the
242     // set of ids.
243     if (install_source == Manifest::EXTERNAL_PREF ||
244         install_source == Manifest::EXTERNAL_REGISTRY)
245       continue;
246 
247     out_ids_for_update_check->push_back(iter->id());
248   }
249 }
250 
AddExtensionImpl(const std::string & id,const std::string & install_parameter,const GURL & update_url,const Version & version,PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,bool is_from_sync,bool install_silently,Manifest::Location install_source,int creation_flags,bool mark_acknowledged,bool remote_install)251 bool PendingExtensionManager::AddExtensionImpl(
252     const std::string& id,
253     const std::string& install_parameter,
254     const GURL& update_url,
255     const Version& version,
256     PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
257     bool is_from_sync,
258     bool install_silently,
259     Manifest::Location install_source,
260     int creation_flags,
261     bool mark_acknowledged,
262     bool remote_install) {
263   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
264 
265   PendingExtensionInfo info(id,
266                             install_parameter,
267                             update_url,
268                             version,
269                             should_allow_install,
270                             is_from_sync,
271                             install_silently,
272                             install_source,
273                             creation_flags,
274                             mark_acknowledged,
275                             remote_install);
276 
277   if (const PendingExtensionInfo* pending = GetById(id)) {
278     // Bugs in this code will manifest as sporadic incorrect extension
279     // locations in situations where multiple install sources run at the
280     // same time. For example, on first login to a chrome os machine, an
281     // extension may be requested by sync and the default extension set.
282     // The following logging will help diagnose such issues.
283     VLOG(1) << "Extension id " << id
284             << " was entered for update more than once."
285             << "  old location: " << pending->install_source()
286             << "  new location: " << install_source
287             << "  old version: " << GetVersionString(pending->version())
288             << "  new version: " << GetVersionString(version);
289 
290     // Never override an existing extension with an older version. Only
291     // extensions from local CRX files have a known version; extensions from an
292     // update URL will get the latest version.
293 
294     // If |pending| has the same or higher precedence than |info| then don't
295     // install |info| over |pending|.
296     if (pending->CompareTo(info) >= 0)
297       return false;
298 
299     VLOG(1) << "Overwrite existing record.";
300 
301     std::replace(pending_extension_list_.begin(),
302                  pending_extension_list_.end(),
303                  *pending,
304                  info);
305   } else {
306     pending_extension_list_.push_back(info);
307   }
308 
309   return true;
310 }
311 
AddForTesting(const PendingExtensionInfo & pending_extension_info)312 void PendingExtensionManager::AddForTesting(
313     const PendingExtensionInfo& pending_extension_info) {
314   pending_extension_list_.push_back(pending_extension_info);
315 }
316 
317 }  // namespace extensions
318