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 "extensions/browser/extension_pref_value_map.h"
6
7 #include "base/prefs/pref_value_map.h"
8 #include "base/stl_util.h"
9 #include "base/values.h"
10
11 using extensions::ExtensionPrefsScope;
12
13 struct ExtensionPrefValueMap::ExtensionEntry {
14 // Installation time of the extension.
15 base::Time install_time;
16 // Whether extension is enabled in the profile.
17 bool enabled;
18 // Whether the extension has access to the incognito profile.
19 bool incognito_enabled;
20 // Extension controlled preferences for the regular profile.
21 PrefValueMap regular_profile_preferences;
22 // Extension controlled preferences that should *only* apply to the regular
23 // profile.
24 PrefValueMap regular_only_profile_preferences;
25 // Persistent extension controlled preferences for the incognito profile,
26 // empty for regular profile ExtensionPrefStore.
27 PrefValueMap incognito_profile_preferences_persistent;
28 // Session only extension controlled preferences for the incognito profile.
29 // These preferences are deleted when the incognito profile is destroyed.
30 PrefValueMap incognito_profile_preferences_session_only;
31 };
32
ExtensionPrefValueMap()33 ExtensionPrefValueMap::ExtensionPrefValueMap() : destroyed_(false) {
34 }
35
~ExtensionPrefValueMap()36 ExtensionPrefValueMap::~ExtensionPrefValueMap() {
37 if (!destroyed_) {
38 NotifyOfDestruction();
39 destroyed_ = true;
40 }
41 STLDeleteValues(&entries_);
42 entries_.clear();
43 }
44
Shutdown()45 void ExtensionPrefValueMap::Shutdown() {
46 NotifyOfDestruction();
47 destroyed_ = true;
48 }
49
SetExtensionPref(const std::string & ext_id,const std::string & key,ExtensionPrefsScope scope,base::Value * value)50 void ExtensionPrefValueMap::SetExtensionPref(const std::string& ext_id,
51 const std::string& key,
52 ExtensionPrefsScope scope,
53 base::Value* value) {
54 PrefValueMap* prefs = GetExtensionPrefValueMap(ext_id, scope);
55
56 if (prefs->SetValue(key, value))
57 NotifyPrefValueChanged(key);
58 }
59
RemoveExtensionPref(const std::string & ext_id,const std::string & key,ExtensionPrefsScope scope)60 void ExtensionPrefValueMap::RemoveExtensionPref(
61 const std::string& ext_id,
62 const std::string& key,
63 ExtensionPrefsScope scope) {
64 PrefValueMap* prefs = GetExtensionPrefValueMap(ext_id, scope);
65 if (prefs->RemoveValue(key))
66 NotifyPrefValueChanged(key);
67 }
68
CanExtensionControlPref(const std::string & extension_id,const std::string & pref_key,bool incognito) const69 bool ExtensionPrefValueMap::CanExtensionControlPref(
70 const std::string& extension_id,
71 const std::string& pref_key,
72 bool incognito) const {
73 ExtensionEntryMap::const_iterator ext = entries_.find(extension_id);
74 if (ext == entries_.end()) {
75 NOTREACHED();
76 return false;
77 }
78
79 if (incognito && !ext->second->incognito_enabled)
80 return false;
81
82 ExtensionEntryMap::const_iterator winner =
83 GetEffectivePrefValueController(pref_key, incognito, NULL);
84 if (winner == entries_.end())
85 return true;
86
87 return winner->second->install_time <= ext->second->install_time;
88 }
89
ClearAllIncognitoSessionOnlyPreferences()90 void ExtensionPrefValueMap::ClearAllIncognitoSessionOnlyPreferences() {
91 typedef std::set<std::string> KeySet;
92 KeySet deleted_keys;
93
94 ExtensionEntryMap::iterator i;
95 for (i = entries_.begin(); i != entries_.end(); ++i) {
96 PrefValueMap& inc_prefs =
97 i->second->incognito_profile_preferences_session_only;
98 PrefValueMap::iterator j;
99 for (j = inc_prefs.begin(); j != inc_prefs.end(); ++j)
100 deleted_keys.insert(j->first);
101 inc_prefs.Clear();
102 }
103
104 KeySet::iterator k;
105 for (k = deleted_keys.begin(); k != deleted_keys.end(); ++k)
106 NotifyPrefValueChanged(*k);
107 }
108
DoesExtensionControlPref(const std::string & extension_id,const std::string & pref_key,bool * from_incognito) const109 bool ExtensionPrefValueMap::DoesExtensionControlPref(
110 const std::string& extension_id,
111 const std::string& pref_key,
112 bool* from_incognito) const {
113 bool incognito = (from_incognito != NULL);
114 ExtensionEntryMap::const_iterator winner =
115 GetEffectivePrefValueController(pref_key, incognito, from_incognito);
116 if (winner == entries_.end())
117 return false;
118 return winner->first == extension_id;
119 }
120
RegisterExtension(const std::string & ext_id,const base::Time & install_time,bool is_enabled,bool is_incognito_enabled)121 void ExtensionPrefValueMap::RegisterExtension(const std::string& ext_id,
122 const base::Time& install_time,
123 bool is_enabled,
124 bool is_incognito_enabled) {
125 if (entries_.find(ext_id) == entries_.end()) {
126 entries_[ext_id] = new ExtensionEntry;
127
128 // Only update the install time if the extension is newly installed.
129 entries_[ext_id]->install_time = install_time;
130 }
131
132 entries_[ext_id]->enabled = is_enabled;
133 entries_[ext_id]->incognito_enabled = is_incognito_enabled;
134 }
135
UnregisterExtension(const std::string & ext_id)136 void ExtensionPrefValueMap::UnregisterExtension(const std::string& ext_id) {
137 ExtensionEntryMap::iterator i = entries_.find(ext_id);
138 if (i == entries_.end())
139 return;
140 std::set<std::string> keys; // keys set by this extension
141 GetExtensionControlledKeys(*(i->second), &keys);
142
143 delete i->second;
144 entries_.erase(i);
145
146 NotifyPrefValueChanged(keys);
147 }
148
SetExtensionState(const std::string & ext_id,bool is_enabled)149 void ExtensionPrefValueMap::SetExtensionState(const std::string& ext_id,
150 bool is_enabled) {
151 ExtensionEntryMap::const_iterator i = entries_.find(ext_id);
152 // This may happen when sync sets the extension state for an
153 // extension that is not installed.
154 if (i == entries_.end())
155 return;
156 if (i->second->enabled == is_enabled)
157 return;
158 std::set<std::string> keys; // keys set by this extension
159 GetExtensionControlledKeys(*(i->second), &keys);
160 i->second->enabled = is_enabled;
161 NotifyPrefValueChanged(keys);
162 }
163
SetExtensionIncognitoState(const std::string & ext_id,bool is_incognito_enabled)164 void ExtensionPrefValueMap::SetExtensionIncognitoState(
165 const std::string& ext_id,
166 bool is_incognito_enabled) {
167 ExtensionEntryMap::const_iterator i = entries_.find(ext_id);
168 // This may happen when sync sets the extension state for an
169 // extension that is not installed.
170 if (i == entries_.end())
171 return;
172 if (i->second->incognito_enabled == is_incognito_enabled)
173 return;
174 std::set<std::string> keys; // keys set by this extension
175 GetExtensionControlledKeys(*(i->second), &keys);
176 i->second->incognito_enabled = is_incognito_enabled;
177 NotifyPrefValueChanged(keys);
178 }
179
GetExtensionPrefValueMap(const std::string & ext_id,ExtensionPrefsScope scope)180 PrefValueMap* ExtensionPrefValueMap::GetExtensionPrefValueMap(
181 const std::string& ext_id,
182 ExtensionPrefsScope scope) {
183 ExtensionEntryMap::const_iterator i = entries_.find(ext_id);
184 CHECK(i != entries_.end());
185 switch (scope) {
186 case extensions::kExtensionPrefsScopeRegular:
187 return &(i->second->regular_profile_preferences);
188 case extensions::kExtensionPrefsScopeRegularOnly:
189 return &(i->second->regular_only_profile_preferences);
190 case extensions::kExtensionPrefsScopeIncognitoPersistent:
191 return &(i->second->incognito_profile_preferences_persistent);
192 case extensions::kExtensionPrefsScopeIncognitoSessionOnly:
193 return &(i->second->incognito_profile_preferences_session_only);
194 }
195 NOTREACHED();
196 return NULL;
197 }
198
GetExtensionPrefValueMap(const std::string & ext_id,ExtensionPrefsScope scope) const199 const PrefValueMap* ExtensionPrefValueMap::GetExtensionPrefValueMap(
200 const std::string& ext_id,
201 ExtensionPrefsScope scope) const {
202 ExtensionEntryMap::const_iterator i = entries_.find(ext_id);
203 CHECK(i != entries_.end());
204 switch (scope) {
205 case extensions::kExtensionPrefsScopeRegular:
206 return &(i->second->regular_profile_preferences);
207 case extensions::kExtensionPrefsScopeRegularOnly:
208 return &(i->second->regular_only_profile_preferences);
209 case extensions::kExtensionPrefsScopeIncognitoPersistent:
210 return &(i->second->incognito_profile_preferences_persistent);
211 case extensions::kExtensionPrefsScopeIncognitoSessionOnly:
212 return &(i->second->incognito_profile_preferences_session_only);
213 }
214 NOTREACHED();
215 return NULL;
216 }
217
GetExtensionControlledKeys(const ExtensionEntry & entry,std::set<std::string> * out) const218 void ExtensionPrefValueMap::GetExtensionControlledKeys(
219 const ExtensionEntry& entry,
220 std::set<std::string>* out) const {
221 PrefValueMap::const_iterator i;
222
223 const PrefValueMap& regular_prefs = entry.regular_profile_preferences;
224 for (i = regular_prefs.begin(); i != regular_prefs.end(); ++i)
225 out->insert(i->first);
226
227 const PrefValueMap& regular_only_prefs =
228 entry.regular_only_profile_preferences;
229 for (i = regular_only_prefs.begin(); i != regular_only_prefs.end(); ++i)
230 out->insert(i->first);
231
232 const PrefValueMap& inc_prefs_pers =
233 entry.incognito_profile_preferences_persistent;
234 for (i = inc_prefs_pers.begin(); i != inc_prefs_pers.end(); ++i)
235 out->insert(i->first);
236
237 const PrefValueMap& inc_prefs_session =
238 entry.incognito_profile_preferences_session_only;
239 for (i = inc_prefs_session.begin(); i != inc_prefs_session.end(); ++i)
240 out->insert(i->first);
241 }
242
GetEffectivePrefValue(const std::string & key,bool incognito,bool * from_incognito) const243 const base::Value* ExtensionPrefValueMap::GetEffectivePrefValue(
244 const std::string& key,
245 bool incognito,
246 bool* from_incognito) const {
247 ExtensionEntryMap::const_iterator winner =
248 GetEffectivePrefValueController(key, incognito, from_incognito);
249 if (winner == entries_.end())
250 return NULL;
251
252 const base::Value* value = NULL;
253 const std::string& ext_id = winner->first;
254
255 // First search for incognito session only preferences.
256 if (incognito) {
257 DCHECK(winner->second->incognito_enabled);
258 const PrefValueMap* prefs = GetExtensionPrefValueMap(
259 ext_id, extensions::kExtensionPrefsScopeIncognitoSessionOnly);
260 prefs->GetValue(key, &value);
261 if (value)
262 return value;
263
264 // If no incognito session only preference exists, fall back to persistent
265 // incognito preference.
266 prefs = GetExtensionPrefValueMap(
267 ext_id,
268 extensions::kExtensionPrefsScopeIncognitoPersistent);
269 prefs->GetValue(key, &value);
270 if (value)
271 return value;
272 } else {
273 // Regular-only preference.
274 const PrefValueMap* prefs = GetExtensionPrefValueMap(
275 ext_id, extensions::kExtensionPrefsScopeRegularOnly);
276 prefs->GetValue(key, &value);
277 if (value)
278 return value;
279 }
280
281 // Regular preference.
282 const PrefValueMap* prefs = GetExtensionPrefValueMap(
283 ext_id, extensions::kExtensionPrefsScopeRegular);
284 prefs->GetValue(key, &value);
285 return value;
286 }
287
288 ExtensionPrefValueMap::ExtensionEntryMap::const_iterator
GetEffectivePrefValueController(const std::string & key,bool incognito,bool * from_incognito) const289 ExtensionPrefValueMap::GetEffectivePrefValueController(
290 const std::string& key,
291 bool incognito,
292 bool* from_incognito) const {
293 ExtensionEntryMap::const_iterator winner = entries_.end();
294 base::Time winners_install_time;
295
296 ExtensionEntryMap::const_iterator i;
297 for (i = entries_.begin(); i != entries_.end(); ++i) {
298 const std::string& ext_id = i->first;
299 const base::Time& install_time = i->second->install_time;
300 const bool enabled = i->second->enabled;
301 const bool incognito_enabled = i->second->incognito_enabled;
302
303 if (!enabled)
304 continue;
305 if (install_time < winners_install_time)
306 continue;
307 if (incognito && !incognito_enabled)
308 continue;
309
310 const base::Value* value = NULL;
311 const PrefValueMap* prefs = GetExtensionPrefValueMap(
312 ext_id, extensions::kExtensionPrefsScopeRegular);
313 if (prefs->GetValue(key, &value)) {
314 winner = i;
315 winners_install_time = install_time;
316 if (from_incognito)
317 *from_incognito = false;
318 }
319
320 if (!incognito) {
321 const PrefValueMap* prefs = GetExtensionPrefValueMap(
322 ext_id, extensions::kExtensionPrefsScopeRegularOnly);
323 if (prefs->GetValue(key, &value)) {
324 winner = i;
325 winners_install_time = install_time;
326 if (from_incognito)
327 *from_incognito = false;
328 }
329 // Ignore the following prefs, because they're incognito-only.
330 continue;
331 }
332
333 prefs = GetExtensionPrefValueMap(
334 ext_id, extensions::kExtensionPrefsScopeIncognitoPersistent);
335 if (prefs->GetValue(key, &value)) {
336 winner = i;
337 winners_install_time = install_time;
338 if (from_incognito)
339 *from_incognito = true;
340 }
341
342 prefs = GetExtensionPrefValueMap(
343 ext_id, extensions::kExtensionPrefsScopeIncognitoSessionOnly);
344 if (prefs->GetValue(key, &value)) {
345 winner = i;
346 winners_install_time = install_time;
347 if (from_incognito)
348 *from_incognito = true;
349 }
350 }
351 return winner;
352 }
353
AddObserver(ExtensionPrefValueMap::Observer * observer)354 void ExtensionPrefValueMap::AddObserver(
355 ExtensionPrefValueMap::Observer* observer) {
356 observers_.AddObserver(observer);
357
358 // Collect all currently used keys and notify the new observer.
359 std::set<std::string> keys;
360 ExtensionEntryMap::const_iterator i;
361 for (i = entries_.begin(); i != entries_.end(); ++i)
362 GetExtensionControlledKeys(*(i->second), &keys);
363
364 std::set<std::string>::const_iterator j;
365 for (j = keys.begin(); j != keys.end(); ++j)
366 observer->OnPrefValueChanged(*j);
367 }
368
RemoveObserver(ExtensionPrefValueMap::Observer * observer)369 void ExtensionPrefValueMap::RemoveObserver(
370 ExtensionPrefValueMap::Observer* observer) {
371 observers_.RemoveObserver(observer);
372 }
373
GetExtensionControllingPref(const std::string & pref_key) const374 std::string ExtensionPrefValueMap::GetExtensionControllingPref(
375 const std::string& pref_key) const {
376 ExtensionEntryMap::const_iterator winner =
377 GetEffectivePrefValueController(pref_key, false, NULL);
378 if (winner == entries_.end())
379 return std::string();
380 return winner->first;
381 }
382
NotifyInitializationCompleted()383 void ExtensionPrefValueMap::NotifyInitializationCompleted() {
384 FOR_EACH_OBSERVER(ExtensionPrefValueMap::Observer, observers_,
385 OnInitializationCompleted());
386 }
387
NotifyPrefValueChanged(const std::set<std::string> & keys)388 void ExtensionPrefValueMap::NotifyPrefValueChanged(
389 const std::set<std::string>& keys) {
390 std::set<std::string>::const_iterator i;
391 for (i = keys.begin(); i != keys.end(); ++i)
392 NotifyPrefValueChanged(*i);
393 }
394
NotifyPrefValueChanged(const std::string & key)395 void ExtensionPrefValueMap::NotifyPrefValueChanged(const std::string& key) {
396 FOR_EACH_OBSERVER(ExtensionPrefValueMap::Observer, observers_,
397 OnPrefValueChanged(key));
398 }
399
NotifyOfDestruction()400 void ExtensionPrefValueMap::NotifyOfDestruction() {
401 FOR_EACH_OBSERVER(ExtensionPrefValueMap::Observer, observers_,
402 OnExtensionPrefValueMapDestruction());
403 }
404