172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Use of this source code is governed by a BSD-style license that can be 372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// found in the LICENSE file. 472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/extensions/external_policy_extension_loader.h" 672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/logging.h" 872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/values.h" 972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/prefs/pref_service.h" 1072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/profiles/profile.h" 11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/extensions/extension.h" 12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/pref_names.h" 13dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h" 14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h" 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h" 1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "googleurl/src/gurl.h" 1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsennamespace { 1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Check an extension ID and an URL to be syntactically correct. 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool CheckExtension(const std::string& id, const std::string& update_url) { 2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen GURL url(update_url); 2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!url.is_valid()) { 2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen LOG(WARNING) << "Policy specifies invalid update URL for external " 2572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen << "extension: " << update_url; 2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!Extension::IdIsValid(id)) { 2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen LOG(WARNING) << "Policy specifies invalid ID for external " 3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen << "extension: " << id; 3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return false; 3272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return true; 3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} // namespace 3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 3872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenExternalPolicyExtensionLoader::ExternalPolicyExtensionLoader( 3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Profile* profile) 4072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen : profile_(profile) { 4172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen pref_change_registrar_.Init(profile_->GetPrefs()); 4272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen pref_change_registrar_.Add(prefs::kExtensionInstallForceList, this); 4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen notification_registrar_.Add(this, 4472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NotificationType::PROFILE_DESTROYED, 4572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Source<Profile>(profile_)); 4672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 4772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 4872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExternalPolicyExtensionLoader::StartLoading() { 4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const ListValue* forcelist = 5072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen profile_->GetPrefs()->GetList(prefs::kExtensionInstallForceList); 5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen DictionaryValue* result = new DictionaryValue(); 5272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (forcelist != NULL) { 5372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::string extension_desc; 5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen for (ListValue::const_iterator it = forcelist->begin(); 5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen it != forcelist->end(); ++it) { 5672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (!(*it)->GetAsString(&extension_desc)) { 5772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen LOG(WARNING) << "Failed to read forcelist string."; 5872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else { 5972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // Each string item of the list has the following form: 6072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // extension_id_code;extension_update_url 6172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // The update URL might also contain semicolons. 6272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen size_t pos = extension_desc.find(';'); 6372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::string id = extension_desc.substr(0, pos); 6472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::string update_url = extension_desc.substr(pos+1); 6572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (CheckExtension(id, update_url)) { 6672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen result->SetString(id + ".external_update_url", update_url); 6772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 6872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 6972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 7072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 7172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen prefs_.reset(result); 7272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen LoadFinished(); 7372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 7472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 7572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid ExternalPolicyExtensionLoader::Observe( 7672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NotificationType type, 7772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const NotificationSource& source, 7872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen const NotificationDetails& details) { 7972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (profile_ == NULL) return; 8072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen switch (type.value) { 8172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case NotificationType::PREF_CHANGED: { 8272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (Source<PrefService>(source).ptr() == profile_->GetPrefs()) { 8372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::string* pref_name = Details<std::string>(details).ptr(); 8472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (*pref_name == prefs::kExtensionInstallForceList) { 8572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen StartLoading(); 8672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } else { 8772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NOTREACHED() << "Unexpected preference name."; 8872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 8972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 9072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen break; 9172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 9272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen case NotificationType::PROFILE_DESTROYED: { 9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (Source<Profile>(source).ptr() == profile_) { 9472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen notification_registrar_.RemoveAll(); 9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen pref_change_registrar_.RemoveAll(); 9672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen profile_ = NULL; 9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 9872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen break; 9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen default: 10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen NOTREACHED() << "Unexpected notification type."; 10272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 104