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