1// Copyright (c) 2013 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/common/extensions/api/plugins/plugins_handler.h"
6
7#include "base/files/file_util.h"
8#include "base/strings/string_number_conversions.h"
9#include "base/strings/utf_string_conversions.h"
10#include "base/values.h"
11#include "chrome/grit/generated_resources.h"
12#include "extensions/common/error_utils.h"
13#include "extensions/common/manifest.h"
14#include "extensions/common/manifest_constants.h"
15#include "extensions/common/manifest_handlers/permissions_parser.h"
16#include "extensions/common/permissions/api_permission.h"
17#include "extensions/common/permissions/api_permission_set.h"
18#include "ui/base/l10n/l10n_util.h"
19
20#if defined(OS_WIN)
21#include "base/win/metro.h"
22#endif
23
24namespace extensions {
25
26namespace keys = manifest_keys;
27
28namespace {
29
30struct PluginManifestData : Extension::ManifestData {
31  // Optional list of NPAPI plugins and associated properties for an extension.
32  PluginInfo::PluginVector plugins;
33};
34
35}  // namespace
36
37PluginInfo::PluginInfo(const base::FilePath& plugin_path, bool plugin_is_public)
38    : path(plugin_path), is_public(plugin_is_public) {
39}
40
41PluginInfo::~PluginInfo() {
42}
43
44// static
45const PluginInfo::PluginVector* PluginInfo::GetPlugins(
46    const Extension* extension) {
47  PluginManifestData* data = static_cast<PluginManifestData*>(
48      extension->GetManifestData(keys::kPlugins));
49  return data ? &data->plugins : NULL;
50}
51
52// static
53bool PluginInfo::HasPlugins(const Extension* extension) {
54  PluginManifestData* data = static_cast<PluginManifestData*>(
55      extension->GetManifestData(keys::kPlugins));
56  return data && !data->plugins.empty() ? true : false;
57}
58
59PluginsHandler::PluginsHandler() {
60}
61
62PluginsHandler::~PluginsHandler() {
63}
64
65const std::vector<std::string> PluginsHandler::Keys() const {
66  return SingleKey(keys::kPlugins);
67}
68
69bool PluginsHandler::Parse(Extension* extension, base::string16* error) {
70  const base::ListValue* list_value = NULL;
71  if (!extension->manifest()->GetList(keys::kPlugins, &list_value)) {
72    *error = base::ASCIIToUTF16(manifest_errors::kInvalidPlugins);
73    return false;
74  }
75
76  scoped_ptr<PluginManifestData> plugins_data(new PluginManifestData);
77
78  for (size_t i = 0; i < list_value->GetSize(); ++i) {
79    const base::DictionaryValue* plugin_value = NULL;
80    if (!list_value->GetDictionary(i, &plugin_value)) {
81      *error = base::ASCIIToUTF16(manifest_errors::kInvalidPlugins);
82      return false;
83    }
84    // Get plugins[i].path.
85    std::string path_str;
86    if (!plugin_value->GetString(keys::kPluginsPath, &path_str)) {
87      *error = ErrorUtils::FormatErrorMessageUTF16(
88          manifest_errors::kInvalidPluginsPath, base::IntToString(i));
89      return false;
90    }
91
92    // Get plugins[i].content (optional).
93    bool is_public = false;
94    if (plugin_value->HasKey(keys::kPluginsPublic)) {
95      if (!plugin_value->GetBoolean(keys::kPluginsPublic, &is_public)) {
96        *error = ErrorUtils::FormatErrorMessageUTF16(
97            manifest_errors::kInvalidPluginsPublic,
98            base::IntToString(i));
99        return false;
100      }
101    }
102
103    // We don't allow extensions to load NPAPI plugins on Chrome OS, or under
104    // Windows 8 Metro mode, but still parse the entries to display consistent
105    // error messages. If the extension actually requires the plugins then
106    // LoadRequirements will prevent it loading.
107#if defined(OS_CHROMEOS)
108    continue;
109#elif defined(OS_WIN)
110    if (base::win::IsMetroProcess()) {
111      continue;
112    }
113#endif  // defined(OS_WIN).
114    plugins_data->plugins.push_back(PluginInfo(
115        extension->path().Append(base::FilePath::FromUTF8Unsafe(path_str)),
116        is_public));
117  }
118
119  if (!plugins_data->plugins.empty()) {
120    extension->SetManifestData(keys::kPlugins, plugins_data.release());
121    PermissionsParser::AddAPIPermission(extension, APIPermission::kPlugin);
122  }
123
124  return true;
125}
126
127bool PluginsHandler::Validate(const Extension* extension,
128                              std::string* error,
129                              std::vector<InstallWarning>* warnings) const {
130  // Validate claimed plugin paths.
131  if (extensions::PluginInfo::HasPlugins(extension)) {
132    const extensions::PluginInfo::PluginVector* plugins =
133        extensions::PluginInfo::GetPlugins(extension);
134    CHECK(plugins);
135    for (std::vector<extensions::PluginInfo>::const_iterator plugin =
136             plugins->begin();
137         plugin != plugins->end(); ++plugin) {
138      if (!base::PathExists(plugin->path)) {
139        *error = l10n_util::GetStringFUTF8(
140            IDS_EXTENSION_LOAD_PLUGIN_PATH_FAILED,
141            plugin->path.LossyDisplayName());
142      return false;
143      }
144    }
145  }
146  return true;
147}
148
149}  // namespace extensions
150