Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / common / extensions / api / file_browser_handlers / file_browser_handler.cc
blobf0508a9c723f42e7a4167edd35a6fde6eb525786
1 // Copyright 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.
5 #include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h"
7 #include "base/logging.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "chrome/common/extensions/extension_constants.h"
13 #include "extensions/common/error_utils.h"
14 #include "extensions/common/install_warning.h"
15 #include "extensions/common/manifest.h"
16 #include "extensions/common/manifest_constants.h"
17 #include "extensions/common/manifest_handlers/permissions_parser.h"
18 #include "extensions/common/permissions/api_permission.h"
19 #include "extensions/common/url_pattern.h"
20 #include "url/url_constants.h"
22 namespace keys = extensions::manifest_keys;
23 namespace errors = extensions::manifest_errors;
25 namespace {
27 const char kReadAccessString[] = "read";
28 const char kReadWriteAccessString[] = "read-write";
29 const char kCreateAccessString[] = "create";
31 unsigned int kPermissionsNotDefined = 0;
32 unsigned int kReadPermission = 1;
33 unsigned int kWritePermission = 1 << 1;
34 unsigned int kCreatePermission = 1 << 2;
35 unsigned int kInvalidPermission = 1 << 3;
37 unsigned int GetAccessPermissionFlagFromString(const std::string& access_str) {
38 if (access_str == kReadAccessString)
39 return kReadPermission;
40 if (access_str == kReadWriteAccessString)
41 return kReadPermission | kWritePermission;
42 if (access_str == kCreateAccessString)
43 return kCreatePermission;
44 return kInvalidPermission;
47 // Stored on the Extension.
48 struct FileBrowserHandlerInfo : public extensions::Extension::ManifestData {
49 FileBrowserHandler::List file_browser_handlers;
51 FileBrowserHandlerInfo();
52 ~FileBrowserHandlerInfo() override;
55 FileBrowserHandlerInfo::FileBrowserHandlerInfo() {
58 FileBrowserHandlerInfo::~FileBrowserHandlerInfo() {
61 } // namespace
63 FileBrowserHandler::FileBrowserHandler()
64 : file_access_permission_flags_(kPermissionsNotDefined) {
67 FileBrowserHandler::~FileBrowserHandler() {
70 void FileBrowserHandler::AddPattern(const URLPattern& pattern) {
71 url_set_.AddPattern(pattern);
74 void FileBrowserHandler::ClearPatterns() {
75 url_set_.ClearPatterns();
78 bool FileBrowserHandler::MatchesURL(const GURL& url) const {
79 return url_set_.MatchesURL(url);
82 bool FileBrowserHandler::AddFileAccessPermission(
83 const std::string& access) {
84 file_access_permission_flags_ |= GetAccessPermissionFlagFromString(access);
85 return (file_access_permission_flags_ & kInvalidPermission) != 0U;
88 bool FileBrowserHandler::ValidateFileAccessPermissions() {
89 bool is_invalid = (file_access_permission_flags_ & kInvalidPermission) != 0U;
90 bool can_create = (file_access_permission_flags_ & kCreatePermission) != 0U;
91 bool can_read_or_write = (file_access_permission_flags_ &
92 (kReadPermission | kWritePermission)) != 0U;
93 if (is_invalid || (can_create && can_read_or_write)) {
94 file_access_permission_flags_ = kInvalidPermission;
95 return false;
98 if (file_access_permission_flags_ == kPermissionsNotDefined)
99 file_access_permission_flags_ = kReadPermission | kWritePermission;
100 return true;
103 bool FileBrowserHandler::CanRead() const {
104 DCHECK(!(file_access_permission_flags_ & kInvalidPermission));
105 return (file_access_permission_flags_ & kReadPermission) != 0;
108 bool FileBrowserHandler::CanWrite() const {
109 DCHECK(!(file_access_permission_flags_ & kInvalidPermission));
110 return (file_access_permission_flags_ & kWritePermission) != 0;
113 bool FileBrowserHandler::HasCreateAccessPermission() const {
114 DCHECK(!(file_access_permission_flags_ & kInvalidPermission));
115 return (file_access_permission_flags_ & kCreatePermission) != 0;
118 // static
119 FileBrowserHandler::List*
120 FileBrowserHandler::GetHandlers(const extensions::Extension* extension) {
121 FileBrowserHandlerInfo* const info = static_cast<FileBrowserHandlerInfo*>(
122 extension->GetManifestData(keys::kFileBrowserHandlers));
123 if (!info)
124 return nullptr;
126 return &info->file_browser_handlers;
129 FileBrowserHandlerParser::FileBrowserHandlerParser() {
132 FileBrowserHandlerParser::~FileBrowserHandlerParser() {
135 namespace {
137 FileBrowserHandler* LoadFileBrowserHandler(
138 const std::string& extension_id,
139 const base::DictionaryValue* file_browser_handler,
140 base::string16* error) {
141 scoped_ptr<FileBrowserHandler> result(new FileBrowserHandler());
142 result->set_extension_id(extension_id);
144 std::string handler_id;
145 // Read the file action |id| (mandatory).
146 if (!file_browser_handler->HasKey(keys::kPageActionId) ||
147 !file_browser_handler->GetString(keys::kPageActionId, &handler_id)) {
148 *error = base::ASCIIToUTF16(errors::kInvalidPageActionId);
149 return NULL;
151 result->set_id(handler_id);
153 // Read the page action title from |default_title| (mandatory).
154 std::string title;
155 if (!file_browser_handler->HasKey(keys::kPageActionDefaultTitle) ||
156 !file_browser_handler->GetString(keys::kPageActionDefaultTitle, &title)) {
157 *error = base::ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle);
158 return NULL;
160 result->set_title(title);
162 // Initialize access permissions (optional).
163 const base::ListValue* access_list_value = NULL;
164 if (file_browser_handler->HasKey(keys::kFileAccessList)) {
165 if (!file_browser_handler->GetList(keys::kFileAccessList,
166 &access_list_value) ||
167 access_list_value->empty()) {
168 *error = base::ASCIIToUTF16(errors::kInvalidFileAccessList);
169 return NULL;
171 for (size_t i = 0; i < access_list_value->GetSize(); ++i) {
172 std::string access;
173 if (!access_list_value->GetString(i, &access) ||
174 result->AddFileAccessPermission(access)) {
175 *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
176 errors::kInvalidFileAccessValue, base::IntToString(i));
177 return NULL;
181 if (!result->ValidateFileAccessPermissions()) {
182 *error = base::ASCIIToUTF16(errors::kInvalidFileAccessList);
183 return NULL;
186 // Initialize file filters (mandatory, unless "create" access is specified,
187 // in which case is ignored). The list can be empty.
188 if (!result->HasCreateAccessPermission()) {
189 const base::ListValue* file_filters = NULL;
190 if (!file_browser_handler->HasKey(keys::kFileFilters) ||
191 !file_browser_handler->GetList(keys::kFileFilters, &file_filters)) {
192 *error = base::ASCIIToUTF16(errors::kInvalidFileFiltersList);
193 return NULL;
195 for (size_t i = 0; i < file_filters->GetSize(); ++i) {
196 std::string filter;
197 if (!file_filters->GetString(i, &filter)) {
198 *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
199 errors::kInvalidFileFilterValue, base::IntToString(i));
200 return NULL;
202 filter = base::ToLowerASCII(filter);
203 if (!base::StartsWith(filter, std::string(url::kFileSystemScheme) + ':',
204 base::CompareCase::SENSITIVE)) {
205 *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
206 errors::kInvalidURLPatternError, filter);
207 return NULL;
209 // The user inputs filesystem:*; we don't actually implement scheme
210 // wildcards in URLPattern, so transform to what will match correctly.
211 filter.replace(0, 11, "chrome-extension://*/");
212 URLPattern pattern(URLPattern::SCHEME_EXTENSION);
213 if (pattern.Parse(filter) != URLPattern::PARSE_SUCCESS) {
214 *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
215 errors::kInvalidURLPatternError, filter);
216 return NULL;
218 std::string path = pattern.path();
219 bool allowed = path == "/*" || path == "/*.*" ||
220 (path.compare(0, 3, "/*.") == 0 &&
221 path.find_first_of('*', 3) == std::string::npos);
222 if (!allowed) {
223 *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
224 errors::kInvalidURLPatternError, filter);
225 return NULL;
227 result->AddPattern(pattern);
231 std::string default_icon;
232 // Read the file browser action |default_icon| (optional).
233 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) {
234 if (!file_browser_handler->GetString(
235 keys::kPageActionDefaultIcon, &default_icon) ||
236 default_icon.empty()) {
237 *error = base::ASCIIToUTF16(errors::kInvalidPageActionIconPath);
238 return NULL;
240 result->set_icon_path(default_icon);
243 return result.release();
246 // Loads FileBrowserHandlers from |extension_actions| into a list in |result|.
247 bool LoadFileBrowserHandlers(
248 const std::string& extension_id,
249 const base::ListValue* extension_actions,
250 FileBrowserHandler::List* result,
251 base::string16* error) {
252 for (base::ListValue::const_iterator iter = extension_actions->begin();
253 iter != extension_actions->end();
254 ++iter) {
255 if (!(*iter)->IsType(base::Value::TYPE_DICTIONARY)) {
256 *error = base::ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
257 return false;
259 scoped_ptr<FileBrowserHandler> action(
260 LoadFileBrowserHandler(
261 extension_id,
262 reinterpret_cast<base::DictionaryValue*>(*iter), error));
263 if (!action.get())
264 return false; // Failed to parse file browser action definition.
265 result->push_back(linked_ptr<FileBrowserHandler>(action.release()));
267 return true;
270 } // namespace
272 bool FileBrowserHandlerParser::Parse(extensions::Extension* extension,
273 base::string16* error) {
274 const base::Value* file_browser_handlers_value = nullptr;
275 if (!extension->manifest()->Get(keys::kFileBrowserHandlers,
276 &file_browser_handlers_value)) {
277 return true;
280 if (!extensions::PermissionsParser::HasAPIPermission(
281 extension, extensions::APIPermission::ID::kFileBrowserHandler)) {
282 extension->AddInstallWarning(extensions::InstallWarning(
283 errors::kInvalidFileBrowserHandlerMissingPermission));
284 return true;
287 const base::ListValue* file_browser_handlers_list_value = nullptr;
288 if (!file_browser_handlers_value->GetAsList(
289 &file_browser_handlers_list_value)) {
290 *error = base::ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
291 return false;
294 scoped_ptr<FileBrowserHandlerInfo> info(new FileBrowserHandlerInfo);
295 if (!LoadFileBrowserHandlers(extension->id(),
296 file_browser_handlers_list_value,
297 &info->file_browser_handlers, error)) {
298 return false; // Failed to parse file browser actions definition.
301 extension->SetManifestData(keys::kFileBrowserHandlers, info.release());
302 return true;
305 const std::vector<std::string> FileBrowserHandlerParser::Keys() const {
306 return SingleKey(keys::kFileBrowserHandlers);