Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/extension_preference_api.h" | 5 #include "chrome/browser/extensions/extension_preference_api.h" |
| 6 | 6 |
| 7 #include "base/json/json_writer.h" | |
| 7 #include "base/singleton.h" | 8 #include "base/singleton.h" |
| 8 #include "base/stringprintf.h" | 9 #include "base/stringprintf.h" |
| 9 #include "base/values.h" | 10 #include "base/values.h" |
| 11 #include "chrome/browser/extensions/extension_event_router.h" | |
| 10 #include "chrome/browser/extensions/extension_prefs.h" | 12 #include "chrome/browser/extensions/extension_prefs.h" |
| 11 #include "chrome/browser/extensions/extension_service.h" | 13 #include "chrome/browser/extensions/extension_service.h" |
| 12 #include "chrome/browser/profiles/profile.h" | 14 #include "chrome/browser/profiles/profile.h" |
| 15 #include "chrome/common/notification_type.h" | |
| 16 #include "chrome/common/notification_service.h" | |
| 13 #include "chrome/common/pref_names.h" | 17 #include "chrome/common/pref_names.h" |
| 14 | 18 |
| 15 namespace { | 19 namespace { |
| 16 | 20 |
| 17 struct PrefMappingEntry { | |
| 18 const char* extension_pref; | |
| 19 const char* browser_pref; | |
| 20 const char* permission; | |
| 21 }; | |
| 22 | |
| 23 const char kNotControllable[] = "NotControllable"; | 21 const char kNotControllable[] = "NotControllable"; |
| 24 const char kControlledByOtherExtensions[] = "ControlledByOtherExtensions"; | 22 const char kControlledByOtherExtensions[] = "ControlledByOtherExtensions"; |
| 25 const char kControllableByThisExtension[] = "ControllableByThisExtension"; | 23 const char kControllableByThisExtension[] = "ControllableByThisExtension"; |
| 26 const char kControlledByThisExtension[] = "ControlledByThisExtension"; | 24 const char kControlledByThisExtension[] = "ControlledByThisExtension"; |
| 27 | 25 |
| 28 const char kIncognito[] = "incognito"; | 26 const char kIncognito[] = "incognito"; |
| 29 const char kIncognitoSpecific[] = "incognitoSpecific"; | 27 const char kIncognitoSpecific[] = "incognitoSpecific"; |
| 30 const char kLevelOfControl[] = "levelOfControl"; | 28 const char kLevelOfControl[] = "levelOfControl"; |
| 31 const char kValue[] = "value"; | 29 const char kValue[] = "value"; |
| 32 | 30 |
| 31 const char kOnPrefChangeFormat[] = "experimental.preferences.%s.onChange"; | |
| 32 | |
| 33 const char kPermissionErrorMessage[] = | |
| 34 "You do not have permission to access the preference '%s'. " | |
| 35 "Be sure to declare in your manifest what permissions you need."; | |
| 36 | |
| 33 const char kIncognitoErrorMessage[] = | 37 const char kIncognitoErrorMessage[] = |
| 34 "You do not have permission to access incognito preferences."; | 38 "You do not have permission to access incognito preferences."; |
| 35 | 39 |
| 36 PrefMappingEntry pref_mapping[] = { | 40 struct PrefMappingEntry { |
| 41 const char* extension_pref; | |
| 42 const char* browser_pref; | |
| 43 const char* permission; | |
| 44 }; | |
| 45 | |
| 46 PrefMappingEntry kPrefMapping[] = { | |
| 37 { "blockThirdPartyCookies", | 47 { "blockThirdPartyCookies", |
| 38 prefs::kBlockThirdPartyCookies, | 48 prefs::kBlockThirdPartyCookies, |
| 39 Extension::kContentSettingsPermission | 49 Extension::kContentSettingsPermission |
| 40 }, | 50 }, |
| 41 { "proxy", | 51 { "proxy", |
| 42 prefs::kProxy, | 52 prefs::kProxy, |
| 43 Extension::kProxyPermission | 53 Extension::kProxyPermission |
| 44 }, | 54 }, |
| 45 }; | 55 }; |
| 46 | 56 |
| 47 class PrefMapping { | 57 class PrefMapping { |
| 48 public: | 58 public: |
| 49 static PrefMapping* GetInstance() { | 59 static PrefMapping* GetInstance() { |
| 50 return Singleton<PrefMapping>::get(); | 60 return Singleton<PrefMapping>::get(); |
| 51 } | 61 } |
| 52 | 62 |
| 53 bool FindBrowserPrefForExtensionPref(const std::string& extension_pref, | 63 bool FindBrowserPrefForExtensionPref(const std::string& extension_pref, |
| 54 std::string* browser_pref, | 64 std::string* browser_pref, |
| 55 std::string* permission) { | 65 std::string* permission) { |
| 56 std::map<std::string, std::pair<std::string, std::string> >::iterator it = | 66 std::map<std::string, std::pair<std::string, std::string> >::iterator it = |
| 57 mapping_.find(extension_pref); | 67 mapping_.find(extension_pref); |
| 58 if (it != mapping_.end()) { | 68 if (it != mapping_.end()) { |
| 59 *browser_pref = it->second.first; | 69 *browser_pref = it->second.first; |
| 60 *permission = it->second.second; | 70 *permission = it->second.second; |
| 61 return true; | 71 return true; |
| 62 } | 72 } |
| 63 return false; | 73 return false; |
| 64 } | 74 } |
| 65 | 75 |
| 76 bool FindEventForBrowserPref(const std::string& browser_pref, | |
| 77 std::string* event_name, | |
| 78 std::string* permission) { | |
| 79 std::map<std::string, std::pair<std::string, std::string> >::iterator it = | |
| 80 event_mapping_.find(browser_pref); | |
| 81 if (it != event_mapping_.end()) { | |
| 82 *event_name = it->second.first; | |
| 83 *permission = it->second.second; | |
| 84 return true; | |
| 85 } | |
| 86 return false; | |
| 87 } | |
| 88 | |
| 66 private: | 89 private: |
| 67 friend struct DefaultSingletonTraits<PrefMapping>; | 90 friend struct DefaultSingletonTraits<PrefMapping>; |
| 68 | 91 |
| 92 // Mapping from extension pref keys to browser pref keys. | |
|
battre
2011/03/10 13:07:28
Thanks you :-)
| |
| 69 std::map<std::string, std::pair<std::string, std::string> > mapping_; | 93 std::map<std::string, std::pair<std::string, std::string> > mapping_; |
| 70 | 94 |
| 95 // Mapping from browser pref keys to extension event names. | |
| 96 std::map<std::string, std::pair<std::string, std::string> > event_mapping_; | |
| 97 | |
| 71 PrefMapping() { | 98 PrefMapping() { |
| 72 for (size_t i = 0; i < arraysize(pref_mapping); ++i) { | 99 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) { |
| 73 mapping_[pref_mapping[i].extension_pref] = | 100 mapping_[kPrefMapping[i].extension_pref] = |
| 74 std::make_pair(pref_mapping[i].browser_pref, | 101 std::make_pair(kPrefMapping[i].browser_pref, |
| 75 pref_mapping[i].permission); | 102 kPrefMapping[i].permission); |
| 103 std::string event_name = | |
| 104 base::StringPrintf(kOnPrefChangeFormat, | |
| 105 kPrefMapping[i].extension_pref); | |
| 106 event_mapping_[kPrefMapping[i].browser_pref] = | |
| 107 std::make_pair(event_name, kPrefMapping[i].permission); | |
| 76 } | 108 } |
|
battre
2011/03/10 13:07:28
DCHECK(mapping_.size()==arraysize(kPrefMapping) &&
Bernhard Bauer
2011/03/10 14:51:15
Done.
| |
| 77 } | 109 } |
| 78 }; | 110 }; |
| 79 | 111 |
| 80 const char kPermissionErrorMessage[] = | 112 // Returns a string constant (defined in the API) indicating the level of |
| 81 "You do not have permission to access the preference '%s'. " | 113 // control this extension has over the specified preference. |
| 82 "Be sure to declare in your manifest what permissions you need."; | 114 const char* GetLevelOfControl( |
| 115 Profile* profile, | |
| 116 const std::string& extension_id, | |
| 117 const std::string& browser_pref, | |
| 118 bool incognito) { | |
| 119 PrefService* prefs = incognito ? profile->GetOffTheRecordPrefs() | |
| 120 : profile->GetPrefs(); | |
| 121 const PrefService::Preference* pref = | |
| 122 prefs->FindPreference(browser_pref.c_str()); | |
| 123 CHECK(pref); | |
| 124 ExtensionPrefs* ep = profile->GetExtensionService()->extension_prefs(); | |
| 125 | |
| 126 if (!pref->IsExtensionModifiable()) | |
| 127 return kNotControllable; | |
| 128 | |
| 129 if (ep->DoesExtensionControlPref(extension_id, browser_pref, incognito)) | |
| 130 return kControlledByThisExtension; | |
| 131 | |
| 132 if (ep->CanExtensionControlPref(extension_id, browser_pref, incognito)) | |
| 133 return kControllableByThisExtension; | |
| 134 | |
| 135 return kControlledByOtherExtensions; | |
| 136 } | |
| 83 | 137 |
| 84 } // namespace | 138 } // namespace |
| 85 | 139 |
| 140 ExtensionPreferenceEventRouter::ExtensionPreferenceEventRouter( | |
| 141 Profile* profile) : profile_(profile) { | |
| 142 registrar_.Init(profile_->GetPrefs()); | |
| 143 incognito_registrar_.Init(profile_->GetOffTheRecordPrefs()); | |
| 144 for (size_t i = 0; i < arraysize(kPrefMapping); ++i) { | |
| 145 registrar_.Add(kPrefMapping[i].browser_pref, this); | |
| 146 incognito_registrar_.Add(kPrefMapping[i].browser_pref, this); | |
| 147 } | |
| 148 } | |
| 149 | |
| 150 ExtensionPreferenceEventRouter::~ExtensionPreferenceEventRouter() { } | |
| 151 | |
| 152 void ExtensionPreferenceEventRouter::Observe( | |
| 153 NotificationType type, | |
| 154 const NotificationSource& source, | |
| 155 const NotificationDetails& details) { | |
| 156 if (type == NotificationType::PREF_CHANGED) { | |
| 157 const std::string* pref_key = | |
| 158 Details<const std::string>(details).ptr(); | |
| 159 OnPrefChanged(Source<PrefService>(source).ptr(), *pref_key); | |
|
battre
2011/03/10 13:07:28
PREF_CHANGED is only fired when the effective valu
Bernhard Bauer
2011/03/10 14:51:15
Oh, I was assuming it is also fired when the level
battre
2011/03/11 09:28:36
This is not implemented, yet.
| |
| 160 } else { | |
| 161 NOTREACHED(); | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 void ExtensionPreferenceEventRouter::OnPrefChanged( | |
| 166 PrefService* pref_service, | |
| 167 const std::string& browser_pref) { | |
| 168 bool incognito = (pref_service != profile_->GetPrefs()); | |
| 169 | |
| 170 std::string event_name; | |
| 171 std::string permission; | |
| 172 bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref( | |
| 173 browser_pref, &event_name, &permission); | |
| 174 DCHECK(rv); | |
| 175 | |
| 176 ListValue args; | |
| 177 DictionaryValue* dict = new DictionaryValue(); | |
| 178 args.Append(dict); | |
| 179 const PrefService::Preference* pref = | |
| 180 pref_service->FindPreference(browser_pref.c_str()); | |
| 181 CHECK(pref); | |
| 182 ExtensionService* extension_service = profile_->GetExtensionService(); | |
| 183 dict->Set(kValue, pref->GetValue()->DeepCopy()); | |
|
battre
2011/03/10 13:07:28
The proxy settings API needs a hook to modify this
Bernhard Bauer
2011/03/10 14:51:15
Hm, I see. I guess we'll need a separate event rou
battre
2011/03/11 09:28:36
Yes, we could even extract the value transformatio
| |
| 184 if (incognito) { | |
| 185 ExtensionPrefs* ep = extension_service->extension_prefs(); | |
| 186 dict->Set( | |
| 187 kIncognitoSpecific, | |
| 188 Value::CreateBooleanValue(ep->HasIncognitoPrefValue(browser_pref))); | |
| 189 } | |
| 190 | |
| 191 ExtensionEventRouter* router = profile_->GetExtensionEventRouter(); | |
| 192 if (!router || !router->HasEventListener(event_name)) | |
| 193 return; | |
| 194 const ExtensionList* extensions = extension_service->extensions(); | |
| 195 for (ExtensionList::const_iterator it = extensions->begin(); | |
| 196 it != extensions->end(); ++it) { | |
| 197 std::string extension_id = (*it)->id(); | |
| 198 // TODO(bauerb): Only iterate over registered event listeners. | |
| 199 if (router->ExtensionHasEventListener(extension_id, event_name) && | |
| 200 (*it)->HasApiPermission(permission) && | |
| 201 (!incognito || extension_service->CanCrossIncognito(*it))) { | |
| 202 std::string level_of_control = | |
| 203 GetLevelOfControl(profile_, extension_id, browser_pref, incognito); | |
| 204 dict->Set(kLevelOfControl, Value::CreateStringValue(level_of_control)); | |
| 205 | |
| 206 std::string json_args; | |
| 207 base::JSONWriter::Write(&args, false, &json_args); | |
| 208 | |
| 209 DispatchEvent(extension_id, event_name, json_args); | |
| 210 } | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 void ExtensionPreferenceEventRouter::DispatchEvent( | |
| 215 const std::string& extension_id, | |
| 216 const std::string& event_name, | |
| 217 const std::string& json_args) { | |
| 218 profile_->GetExtensionEventRouter()->DispatchEventToExtension( | |
| 219 extension_id, event_name, json_args, NULL, GURL()); | |
| 220 } | |
| 221 | |
| 86 // TODO(battre): Factor out common parts once this is stable. | 222 // TODO(battre): Factor out common parts once this is stable. |
| 87 | 223 |
| 88 GetPreferenceFunction::~GetPreferenceFunction() { } | 224 GetPreferenceFunction::~GetPreferenceFunction() { } |
| 89 | 225 |
| 90 const char* GetPreferenceFunction::GetLevelOfControl( | |
| 91 const std::string& browser_pref, | |
| 92 bool incognito) const { | |
| 93 PrefService* prefs = incognito ? profile_->GetOffTheRecordPrefs() | |
| 94 : profile_->GetPrefs(); | |
| 95 const PrefService::Preference* pref = | |
| 96 prefs->FindPreference(browser_pref.c_str()); | |
| 97 CHECK(pref); | |
| 98 ExtensionPrefs* ep = profile_->GetExtensionService()->extension_prefs(); | |
| 99 | |
| 100 if (!pref->IsExtensionModifiable()) | |
| 101 return kNotControllable; | |
| 102 | |
| 103 if (ep->DoesExtensionControlPref(extension_id(), browser_pref, incognito)) | |
| 104 return kControlledByThisExtension; | |
| 105 | |
| 106 if (ep->CanExtensionControlPref(extension_id(), browser_pref, incognito)) | |
| 107 return kControllableByThisExtension; | |
| 108 | |
| 109 return kControlledByOtherExtensions; | |
| 110 } | |
| 111 | |
| 112 bool GetPreferenceFunction::RunImpl() { | 226 bool GetPreferenceFunction::RunImpl() { |
| 113 std::string pref_key; | 227 std::string pref_key; |
| 114 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key)); | 228 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key)); |
| 115 DictionaryValue* details = NULL; | 229 DictionaryValue* details = NULL; |
| 116 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details)); | 230 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &details)); |
| 117 | 231 |
| 118 bool incognito = false; | 232 bool incognito = false; |
| 119 if (details->HasKey(kIncognito)) | 233 if (details->HasKey(kIncognito)) |
| 120 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(kIncognito, &incognito)); | 234 EXTENSION_FUNCTION_VALIDATE(details->GetBoolean(kIncognito, &incognito)); |
| 121 | 235 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 132 PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref( | 246 PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref( |
| 133 pref_key, &browser_pref, &permission)); | 247 pref_key, &browser_pref, &permission)); |
| 134 if (!GetExtension()->HasApiPermission(permission)) { | 248 if (!GetExtension()->HasApiPermission(permission)) { |
| 135 error_ = base::StringPrintf(kPermissionErrorMessage, pref_key.c_str()); | 249 error_ = base::StringPrintf(kPermissionErrorMessage, pref_key.c_str()); |
| 136 return false; | 250 return false; |
| 137 } | 251 } |
| 138 | 252 |
| 139 const PrefService::Preference* pref = | 253 const PrefService::Preference* pref = |
| 140 prefs->FindPreference(browser_pref.c_str()); | 254 prefs->FindPreference(browser_pref.c_str()); |
| 141 CHECK(pref); | 255 CHECK(pref); |
| 142 std::string level_of_control = GetLevelOfControl(browser_pref, incognito); | 256 std::string level_of_control = |
| 257 GetLevelOfControl(profile_, extension_id(), browser_pref, incognito); | |
| 143 | 258 |
| 144 scoped_ptr<DictionaryValue> result(new DictionaryValue); | 259 scoped_ptr<DictionaryValue> result(new DictionaryValue); |
| 145 result->Set(kValue, pref->GetValue()->DeepCopy()); | 260 result->Set(kValue, pref->GetValue()->DeepCopy()); |
| 146 result->Set(kLevelOfControl, Value::CreateStringValue(level_of_control)); | 261 result->Set(kLevelOfControl, Value::CreateStringValue(level_of_control)); |
| 147 if (incognito) { | 262 if (incognito) { |
| 148 ExtensionPrefs* ep = profile_->GetExtensionService()->extension_prefs(); | 263 ExtensionPrefs* ep = profile_->GetExtensionService()->extension_prefs(); |
| 149 result->Set( | 264 result->Set( |
| 150 kIncognitoSpecific, | 265 kIncognitoSpecific, |
| 151 Value::CreateBooleanValue(ep->HasIncognitoPrefValue(browser_pref))); | 266 Value::CreateBooleanValue(ep->HasIncognitoPrefValue(browser_pref))); |
| 152 } | 267 } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 216 PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref( | 331 PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref( |
| 217 pref_key, &browser_pref, &permission)); | 332 pref_key, &browser_pref, &permission)); |
| 218 if (!GetExtension()->HasApiPermission(permission)) { | 333 if (!GetExtension()->HasApiPermission(permission)) { |
| 219 error_ = base::StringPrintf(kPermissionErrorMessage, pref_key.c_str()); | 334 error_ = base::StringPrintf(kPermissionErrorMessage, pref_key.c_str()); |
| 220 return false; | 335 return false; |
| 221 } | 336 } |
| 222 ExtensionPrefs* prefs = profile_->GetExtensionService()->extension_prefs(); | 337 ExtensionPrefs* prefs = profile_->GetExtensionService()->extension_prefs(); |
| 223 prefs->RemoveExtensionControlledPref(extension_id(), browser_pref, incognito); | 338 prefs->RemoveExtensionControlledPref(extension_id(), browser_pref, incognito); |
| 224 return true; | 339 return true; |
| 225 } | 340 } |
| OLD | NEW |