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/extensions/external_policy_extension_loader.h"
6
7 #include "base/logging.h"
8 #include "base/values.h"
9 #include "chrome/browser/prefs/pref_service.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/common/extensions/extension.h"
12 #include "chrome/common/pref_names.h"
13 #include "content/browser/browser_thread.h"
14 #include "content/common/notification_service.h"
15 #include "content/common/notification_type.h"
16 #include "googleurl/src/gurl.h"
17
18 namespace {
19
20 // Check an extension ID and an URL to be syntactically correct.
CheckExtension(const std::string & id,const std::string & update_url)21 bool CheckExtension(const std::string& id, const std::string& update_url) {
22 GURL url(update_url);
23 if (!url.is_valid()) {
24 LOG(WARNING) << "Policy specifies invalid update URL for external "
25 << "extension: " << update_url;
26 return false;
27 }
28 if (!Extension::IdIsValid(id)) {
29 LOG(WARNING) << "Policy specifies invalid ID for external "
30 << "extension: " << id;
31 return false;
32 }
33 return true;
34 }
35
36 } // namespace
37
ExternalPolicyExtensionLoader(Profile * profile)38 ExternalPolicyExtensionLoader::ExternalPolicyExtensionLoader(
39 Profile* profile)
40 : profile_(profile) {
41 pref_change_registrar_.Init(profile_->GetPrefs());
42 pref_change_registrar_.Add(prefs::kExtensionInstallForceList, this);
43 notification_registrar_.Add(this,
44 NotificationType::PROFILE_DESTROYED,
45 Source<Profile>(profile_));
46 }
47
StartLoading()48 void ExternalPolicyExtensionLoader::StartLoading() {
49 const ListValue* forcelist =
50 profile_->GetPrefs()->GetList(prefs::kExtensionInstallForceList);
51 DictionaryValue* result = new DictionaryValue();
52 if (forcelist != NULL) {
53 std::string extension_desc;
54 for (ListValue::const_iterator it = forcelist->begin();
55 it != forcelist->end(); ++it) {
56 if (!(*it)->GetAsString(&extension_desc)) {
57 LOG(WARNING) << "Failed to read forcelist string.";
58 } else {
59 // Each string item of the list has the following form:
60 // extension_id_code;extension_update_url
61 // The update URL might also contain semicolons.
62 size_t pos = extension_desc.find(';');
63 std::string id = extension_desc.substr(0, pos);
64 std::string update_url = extension_desc.substr(pos+1);
65 if (CheckExtension(id, update_url)) {
66 result->SetString(id + ".external_update_url", update_url);
67 }
68 }
69 }
70 }
71 prefs_.reset(result);
72 LoadFinished();
73 }
74
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)75 void ExternalPolicyExtensionLoader::Observe(
76 NotificationType type,
77 const NotificationSource& source,
78 const NotificationDetails& details) {
79 if (profile_ == NULL) return;
80 switch (type.value) {
81 case NotificationType::PREF_CHANGED: {
82 if (Source<PrefService>(source).ptr() == profile_->GetPrefs()) {
83 std::string* pref_name = Details<std::string>(details).ptr();
84 if (*pref_name == prefs::kExtensionInstallForceList) {
85 StartLoading();
86 } else {
87 NOTREACHED() << "Unexpected preference name.";
88 }
89 }
90 break;
91 }
92 case NotificationType::PROFILE_DESTROYED: {
93 if (Source<Profile>(source).ptr() == profile_) {
94 notification_registrar_.RemoveAll();
95 pref_change_registrar_.RemoveAll();
96 profile_ = NULL;
97 }
98 break;
99 }
100 default:
101 NOTREACHED() << "Unexpected notification type.";
102 }
103 }
104