• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/sync/glue/extension_util.h"
6 
7 #include <sstream>
8 
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/stl_util-inl.h"
12 #include "base/version.h"
13 #include "chrome/browser/extensions/extension_prefs.h"
14 #include "chrome/browser/extensions/extension_service.h"
15 #include "chrome/browser/extensions/extension_sync_data.h"
16 #include "chrome/browser/sync/protocol/extension_specifics.pb.h"
17 #include "chrome/common/extensions/extension.h"
18 #include "chrome/common/extensions/extension_constants.h"
19 
20 namespace browser_sync {
21 
IsExtensionValid(const Extension & extension)22 bool IsExtensionValid(const Extension& extension) {
23   // TODO(akalin): Figure out if we need to allow some other types.
24   if (extension.location() != Extension::INTERNAL) {
25     // We have a non-standard location.
26     return false;
27   }
28 
29   // Disallow extensions with non-gallery auto-update URLs for now.
30   //
31   // TODO(akalin): Relax this restriction once we've put in UI to
32   // approve synced extensions.
33   if (!extension.update_url().is_empty() &&
34       (extension.update_url() != Extension::GalleryUpdateUrl(false)) &&
35       (extension.update_url() != Extension::GalleryUpdateUrl(true))) {
36     return false;
37   }
38 
39   // Disallow extensions with native code plugins.
40   //
41   // TODO(akalin): Relax this restriction once we've put in UI to
42   // approve synced extensions.
43   if (!extension.plugins().empty()) {
44     return false;
45   }
46 
47   return true;
48 }
49 
ExtensionSpecificsToString(const sync_pb::ExtensionSpecifics & specifics)50 std::string ExtensionSpecificsToString(
51     const sync_pb::ExtensionSpecifics& specifics) {
52   std::stringstream ss;
53   ss << "{ ";
54   ss << "id: "                   << specifics.id()                << ", ";
55   ss << "version: "              << specifics.version()           << ", ";
56   ss << "update_url: "           << specifics.update_url()        << ", ";
57   ss << "enabled: "              << specifics.enabled()           << ", ";
58   ss << "incognito_enabled: "    << specifics.incognito_enabled() << ", ";
59   ss << "name: "                 << specifics.name();
60   ss << " }";
61   return ss.str();
62 }
63 
IsExtensionSpecificsValid(const sync_pb::ExtensionSpecifics & specifics)64 bool IsExtensionSpecificsValid(
65     const sync_pb::ExtensionSpecifics& specifics) {
66   if (!Extension::IdIsValid(specifics.id())) {
67     return false;
68   }
69 
70   scoped_ptr<Version> version(
71       Version::GetVersionFromString(specifics.version()));
72   if (!version.get()) {
73     return false;
74   }
75 
76   // The update URL must be either empty or valid.
77   GURL update_url(specifics.update_url());
78   if (!update_url.is_empty() && !update_url.is_valid()) {
79     return false;
80   }
81 
82   return true;
83 }
84 
DcheckIsExtensionSpecificsValid(const sync_pb::ExtensionSpecifics & specifics)85 void DcheckIsExtensionSpecificsValid(
86     const sync_pb::ExtensionSpecifics& specifics) {
87   DCHECK(IsExtensionSpecificsValid(specifics))
88       << ExtensionSpecificsToString(specifics);
89 }
90 
AreExtensionSpecificsEqual(const sync_pb::ExtensionSpecifics & a,const sync_pb::ExtensionSpecifics & b)91 bool AreExtensionSpecificsEqual(const sync_pb::ExtensionSpecifics& a,
92                                 const sync_pb::ExtensionSpecifics& b) {
93   // TODO(akalin): Figure out if we have to worry about version/URL
94   // strings that are not identical but map to the same object.
95   return ((a.id() == b.id()) &&
96           (a.version() == b.version()) &&
97           (a.update_url() == b.update_url()) &&
98           (a.enabled() == b.enabled()) &&
99           (a.incognito_enabled() == b.incognito_enabled()) &&
100           (a.name() == b.name()));
101 }
102 
IsExtensionSpecificsUnset(const sync_pb::ExtensionSpecifics & specifics)103 bool IsExtensionSpecificsUnset(
104     const sync_pb::ExtensionSpecifics& specifics) {
105   return AreExtensionSpecificsEqual(specifics,
106                                     sync_pb::ExtensionSpecifics());
107 }
108 
CopyUserProperties(const sync_pb::ExtensionSpecifics & specifics,sync_pb::ExtensionSpecifics * dest_specifics)109 void CopyUserProperties(
110     const sync_pb::ExtensionSpecifics& specifics,
111     sync_pb::ExtensionSpecifics* dest_specifics) {
112   DCHECK(dest_specifics);
113   dest_specifics->set_enabled(specifics.enabled());
114   dest_specifics->set_incognito_enabled(specifics.incognito_enabled());
115 }
116 
CopyNonUserProperties(const sync_pb::ExtensionSpecifics & specifics,sync_pb::ExtensionSpecifics * dest_specifics)117 void CopyNonUserProperties(
118     const sync_pb::ExtensionSpecifics& specifics,
119     sync_pb::ExtensionSpecifics* dest_specifics) {
120   DCHECK(dest_specifics);
121   sync_pb::ExtensionSpecifics old_dest_specifics(*dest_specifics);
122   *dest_specifics = specifics;
123   CopyUserProperties(old_dest_specifics, dest_specifics);
124 }
125 
AreExtensionSpecificsUserPropertiesEqual(const sync_pb::ExtensionSpecifics & a,const sync_pb::ExtensionSpecifics & b)126 bool AreExtensionSpecificsUserPropertiesEqual(
127     const sync_pb::ExtensionSpecifics& a,
128     const sync_pb::ExtensionSpecifics& b) {
129   sync_pb::ExtensionSpecifics a_user_properties, b_user_properties;
130   CopyUserProperties(a, &a_user_properties);
131   CopyUserProperties(b, &b_user_properties);
132   return AreExtensionSpecificsEqual(a_user_properties, b_user_properties);
133 }
134 
AreExtensionSpecificsNonUserPropertiesEqual(const sync_pb::ExtensionSpecifics & a,const sync_pb::ExtensionSpecifics & b)135 bool AreExtensionSpecificsNonUserPropertiesEqual(
136     const sync_pb::ExtensionSpecifics& a,
137     const sync_pb::ExtensionSpecifics& b) {
138   sync_pb::ExtensionSpecifics a_non_user_properties, b_non_user_properties;
139   CopyNonUserProperties(a, &a_non_user_properties);
140   CopyNonUserProperties(b, &b_non_user_properties);
141   return AreExtensionSpecificsEqual(
142       a_non_user_properties, b_non_user_properties);
143 }
144 
GetExtensionSpecifics(const Extension & extension,const ExtensionServiceInterface & extension_service,sync_pb::ExtensionSpecifics * specifics)145 void GetExtensionSpecifics(const Extension& extension,
146                            const ExtensionServiceInterface& extension_service,
147                            sync_pb::ExtensionSpecifics* specifics) {
148   DCHECK(IsExtensionValid(extension));
149   const std::string& id = extension.id();
150   bool enabled = extension_service.IsExtensionEnabled(id);
151   bool incognito_enabled = extension_service.IsIncognitoEnabled(id);
152   specifics->set_id(id);
153   specifics->set_version(extension.VersionString());
154   specifics->set_update_url(extension.update_url().spec());
155   specifics->set_enabled(enabled);
156   specifics->set_incognito_enabled(incognito_enabled);
157   specifics->set_name(extension.name());
158   DcheckIsExtensionSpecificsValid(*specifics);
159 }
160 
MergeExtensionSpecifics(const sync_pb::ExtensionSpecifics & specifics,bool merge_user_properties,sync_pb::ExtensionSpecifics * merged_specifics)161 void MergeExtensionSpecifics(
162     const sync_pb::ExtensionSpecifics& specifics,
163     bool merge_user_properties,
164     sync_pb::ExtensionSpecifics* merged_specifics) {
165   DcheckIsExtensionSpecificsValid(*merged_specifics);
166   DcheckIsExtensionSpecificsValid(specifics);
167   DCHECK_EQ(specifics.id(), merged_specifics->id());
168   // TODO(akalin): Merge enabled permissions when we sync those.
169   scoped_ptr<Version> version(
170       Version::GetVersionFromString(specifics.version()));
171   CHECK(version.get());
172   scoped_ptr<Version> merged_version(
173       Version::GetVersionFromString(merged_specifics->version()));
174   CHECK(merged_version.get());
175   if (version->CompareTo(*merged_version) >= 0) {
176     // |specifics| has a more recent or the same version, so merge it
177     // in.
178     CopyNonUserProperties(specifics, merged_specifics);
179     if (merge_user_properties) {
180       CopyUserProperties(specifics, merged_specifics);
181     }
182   }
183 }
184 
GetExtensionSyncData(const sync_pb::ExtensionSpecifics & specifics,ExtensionSyncData * sync_data)185 bool GetExtensionSyncData(
186     const sync_pb::ExtensionSpecifics& specifics,
187     ExtensionSyncData* sync_data) {
188   if (!Extension::IdIsValid(specifics.id())) {
189     return false;
190   }
191 
192   scoped_ptr<Version> version(
193       Version::GetVersionFromString(specifics.version()));
194   if (!version.get()) {
195     return false;
196   }
197 
198   // The update URL must be either empty or valid.
199   GURL update_url(specifics.update_url());
200   if (!update_url.is_empty() && !update_url.is_valid()) {
201     return false;
202   }
203 
204   sync_data->id = specifics.id();
205   sync_data->update_url = update_url;
206   sync_data->version = *version;
207   sync_data->enabled = specifics.enabled();
208   sync_data->incognito_enabled = specifics.incognito_enabled();
209   return true;
210 }
211 
212 }  // namespace browser_sync
213