12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/api/plugins/plugins_handler.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/grit/generated_resources.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/error_utils.h"
133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest.h"
14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "extensions/common/manifest_constants.h"
1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/manifest_handlers/permissions_parser.h"
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "extensions/common/permissions/api_permission.h"
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "extensions/common/permissions/api_permission_set.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/win/metro.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)namespace keys = manifest_keys;
273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)struct PluginManifestData : Extension::ManifestData {
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Optional list of NPAPI plugins and associated properties for an extension.
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PluginInfo::PluginVector plugins;
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PluginInfo::PluginInfo(const base::FilePath& plugin_path, bool plugin_is_public)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : path(plugin_path), is_public(plugin_is_public) {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PluginInfo::~PluginInfo() {
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const PluginInfo::PluginVector* PluginInfo::GetPlugins(
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Extension* extension) {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PluginManifestData* data = static_cast<PluginManifestData*>(
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension->GetManifestData(keys::kPlugins));
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return data ? &data->plugins : NULL;
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool PluginInfo::HasPlugins(const Extension* extension) {
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  PluginManifestData* data = static_cast<PluginManifestData*>(
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension->GetManifestData(keys::kPlugins));
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return data && !data->plugins.empty() ? true : false;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PluginsHandler::PluginsHandler() {
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)PluginsHandler::~PluginsHandler() {
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::vector<std::string> PluginsHandler::Keys() const {
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return SingleKey(keys::kPlugins);
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool PluginsHandler::Parse(Extension* extension, base::string16* error) {
707d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::ListValue* list_value = NULL;
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!extension->manifest()->GetList(keys::kPlugins, &list_value)) {
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *error = base::ASCIIToUTF16(manifest_errors::kInvalidPlugins);
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<PluginManifestData> plugins_data(new PluginManifestData);
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < list_value->GetSize(); ++i) {
797d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const base::DictionaryValue* plugin_value = NULL;
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!list_value->GetDictionary(i, &plugin_value)) {
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *error = base::ASCIIToUTF16(manifest_errors::kInvalidPlugins);
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Get plugins[i].path.
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string path_str;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) {
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *error = ErrorUtils::FormatErrorMessageUTF16(
88d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)          manifest_errors::kInvalidPluginsPath, base::IntToString(i));
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Get plugins[i].content (optional).
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool is_public = false;
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (plugin_value->HasKey(keys::kPluginsPublic)) {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) {
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *error = ErrorUtils::FormatErrorMessageUTF16(
97d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)            manifest_errors::kInvalidPluginsPublic,
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            base::IntToString(i));
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We don't allow extensions to load NPAPI plugins on Chrome OS, or under
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Windows 8 Metro mode, but still parse the entries to display consistent
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // error messages. If the extension actually requires the plugins then
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // LoadRequirements will prevent it loading.
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_CHROMEOS)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    continue;
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#elif defined(OS_WIN)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (base::win::IsMetroProcess()) {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif  // defined(OS_WIN).
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    plugins_data->plugins.push_back(PluginInfo(
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extension->path().Append(base::FilePath::FromUTF8Unsafe(path_str)),
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        is_public));
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!plugins_data->plugins.empty()) {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extension->SetManifestData(keys::kPlugins, plugins_data.release());
12146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    PermissionsParser::AddAPIPermission(extension, APIPermission::kPlugin);
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool PluginsHandler::Validate(const Extension* extension,
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              std::string* error,
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              std::vector<InstallWarning>* warnings) const {
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Validate claimed plugin paths.
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (extensions::PluginInfo::HasPlugins(extension)) {
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const extensions::PluginInfo::PluginVector* plugins =
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extensions::PluginInfo::GetPlugins(extension);
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK(plugins);
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (std::vector<extensions::PluginInfo>::const_iterator plugin =
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             plugins->begin();
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         plugin != plugins->end(); ++plugin) {
1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      if (!base::PathExists(plugin->path)) {
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        *error = l10n_util::GetStringFUTF8(
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            IDS_EXTENSION_LOAD_PLUGIN_PATH_FAILED,
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            plugin->path.LossyDisplayName());
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
150