1 // Copyright 2014 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/manifest_handlers/extension_action_handler.h"
6
7 #include <memory>
8
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "chrome/common/extensions/api/extension_action/action_info.h"
12 #include "chrome/common/extensions/extension_constants.h"
13 #include "extensions/common/extension.h"
14 #include "extensions/common/file_util.h"
15 #include "extensions/common/image_util.h"
16 #include "extensions/common/manifest_constants.h"
17
18 namespace extensions {
19
ExtensionActionHandler()20 ExtensionActionHandler::ExtensionActionHandler() {
21 }
22
~ExtensionActionHandler()23 ExtensionActionHandler::~ExtensionActionHandler() {
24 }
25
Parse(Extension * extension,base::string16 * error)26 bool ExtensionActionHandler::Parse(Extension* extension,
27 base::string16* error) {
28 const char* key = nullptr;
29 const char* error_key = nullptr;
30 ActionInfo::Type type = ActionInfo::TYPE_ACTION;
31 if (extension->manifest()->HasKey(manifest_keys::kAction)) {
32 key = manifest_keys::kAction;
33 error_key = manifest_errors::kInvalidAction;
34 // type ACTION is correct.
35 }
36
37 if (extension->manifest()->HasKey(manifest_keys::kPageAction)) {
38 if (key != nullptr) {
39 // An extension can only have one action.
40 *error = base::ASCIIToUTF16(manifest_errors::kOneUISurfaceOnly);
41 return false;
42 }
43 key = manifest_keys::kPageAction;
44 error_key = manifest_errors::kInvalidPageAction;
45 type = ActionInfo::TYPE_PAGE;
46 }
47
48 if (extension->manifest()->HasKey(manifest_keys::kBrowserAction)) {
49 if (key != nullptr) {
50 // An extension can only have one action.
51 *error = base::ASCIIToUTF16(manifest_errors::kOneUISurfaceOnly);
52 return false;
53 }
54 key = manifest_keys::kBrowserAction;
55 error_key = manifest_errors::kInvalidBrowserAction;
56 type = ActionInfo::TYPE_BROWSER;
57 }
58
59 if (key) {
60 const base::DictionaryValue* dict = nullptr;
61 if (!extension->manifest()->GetDictionary(key, &dict)) {
62 *error = base::ASCIIToUTF16(error_key);
63 return false;
64 }
65
66 std::unique_ptr<ActionInfo> action_info =
67 ActionInfo::Load(extension, type, dict, error);
68 if (!action_info)
69 return false; // Failed to parse extension action definition.
70
71 switch (type) {
72 case ActionInfo::TYPE_ACTION:
73 ActionInfo::SetExtensionActionInfo(extension, std::move(action_info));
74 break;
75 case ActionInfo::TYPE_PAGE:
76 ActionInfo::SetPageActionInfo(extension, std::move(action_info));
77 break;
78 case ActionInfo::TYPE_BROWSER:
79 ActionInfo::SetBrowserActionInfo(extension, std::move(action_info));
80 break;
81 }
82 } else { // No key, used for synthesizing an action for extensions with none.
83 if (Manifest::IsComponentLocation(extension->location()))
84 return true; // Don't synthesize actions for component extensions.
85 if (extension->was_installed_by_default())
86 return true; // Don't synthesize actions for default extensions.
87
88 // Set an empty page action. We use a page action (instead of a browser
89 // action) because the action should not be seen as enabled on every page.
90 auto action_info = std::make_unique<ActionInfo>(ActionInfo::TYPE_PAGE);
91 action_info->synthesized = true;
92 ActionInfo::SetPageActionInfo(extension, std::move(action_info));
93 }
94
95 return true;
96 }
97
Validate(const Extension * extension,std::string * error,std::vector<InstallWarning> * warnings) const98 bool ExtensionActionHandler::Validate(
99 const Extension* extension,
100 std::string* error,
101 std::vector<InstallWarning>* warnings) const {
102 const ActionInfo* action = ActionInfo::GetAnyActionInfo(extension);
103 if (!action || action->default_icon.empty())
104 return true;
105
106 const char* manifest_key = nullptr;
107 switch (action->type) {
108 case ActionInfo::TYPE_ACTION:
109 manifest_key = manifest_keys::kAction;
110 break;
111 case ActionInfo::TYPE_BROWSER:
112 manifest_key = manifest_keys::kBrowserAction;
113 break;
114 case ActionInfo::TYPE_PAGE:
115 manifest_key = manifest_keys::kPageAction;
116 break;
117 }
118 DCHECK(manifest_key);
119
120 // Analyze the icons for visibility using the default toolbar color, since
121 // the majority of Chrome users don't modify their theme.
122 return file_util::ValidateExtensionIconSet(
123 action->default_icon, extension, manifest_key,
124 image_util::kDefaultToolbarColor, error);
125 }
126
AlwaysParseForType(Manifest::Type type) const127 bool ExtensionActionHandler::AlwaysParseForType(Manifest::Type type) const {
128 return type == Manifest::TYPE_EXTENSION || type == Manifest::TYPE_USER_SCRIPT;
129 }
130
Keys() const131 base::span<const char* const> ExtensionActionHandler::Keys() const {
132 static constexpr const char* kKeys[] = {
133 manifest_keys::kPageAction,
134 manifest_keys::kBrowserAction,
135 };
136 return kKeys;
137 }
138
139 } // namespace extensions
140