Fix broken path in extensions/common/PRESUBMIT.py
[chromium-blink-merge.git] / chrome / common / extensions / api / file_browser_handlers / file_browser_handler.cc
blobac957e4eca7af20a0a5b1944b37635087ffccdbb
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 base::StringToLowerASCII(&filter);
203 if (!StartsWithASCII(filter,
204 std::string(url::kFileSystemScheme) + ':',
205 true)) {
206 *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
207 errors::kInvalidURLPatternError, filter);
208 return NULL;
210 // The user inputs filesystem:*; we don't actually implement scheme
211 // wildcards in URLPattern, so transform to what will match correctly.
212 filter.replace(0, 11, "chrome-extension://*/");
213 URLPattern pattern(URLPattern::SCHEME_EXTENSION);
214 if (pattern.Parse(filter) != URLPattern::PARSE_SUCCESS) {
215 *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
216 errors::kInvalidURLPatternError, filter);
217 return NULL;
219 std::string path = pattern.path();
220 bool allowed = path == "/*" || path == "/*.*" ||
221 (path.compare(0, 3, "/*.") == 0 &&
222 path.find_first_of('*', 3) == std::string::npos);
223 if (!allowed) {
224 *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
225 errors::kInvalidURLPatternError, filter);
226 return NULL;
228 result->AddPattern(pattern);
232 std::string default_icon;
233 // Read the file browser action |default_icon| (optional).
234 if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) {
235 if (!file_browser_handler->GetString(
236 keys::kPageActionDefaultIcon, &default_icon) ||
237 default_icon.empty()) {
238 *error = base::ASCIIToUTF16(errors::kInvalidPageActionIconPath);
239 return NULL;
241 result->set_icon_path(default_icon);
244 return result.release();
247 // Loads FileBrowserHandlers from |extension_actions| into a list in |result|.
248 bool LoadFileBrowserHandlers(
249 const std::string& extension_id,
250 const base::ListValue* extension_actions,
251 FileBrowserHandler::List* result,
252 base::string16* error) {
253 for (base::ListValue::const_iterator iter = extension_actions->begin();
254 iter != extension_actions->end();
255 ++iter) {
256 if (!(*iter)->IsType(base::Value::TYPE_DICTIONARY)) {
257 *error = base::ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
258 return false;
260 scoped_ptr<FileBrowserHandler> action(
261 LoadFileBrowserHandler(
262 extension_id,
263 reinterpret_cast<base::DictionaryValue*>(*iter), error));
264 if (!action.get())
265 return false; // Failed to parse file browser action definition.
266 result->push_back(linked_ptr<FileBrowserHandler>(action.release()));
268 return true;
271 } // namespace
273 bool FileBrowserHandlerParser::Parse(extensions::Extension* extension,
274 base::string16* error) {
275 const base::Value* file_browser_handlers_value = nullptr;
276 if (!extension->manifest()->Get(keys::kFileBrowserHandlers,
277 &file_browser_handlers_value)) {
278 return true;
281 if (!extensions::PermissionsParser::HasAPIPermission(
282 extension, extensions::APIPermission::ID::kFileBrowserHandler)) {
283 extension->AddInstallWarning(extensions::InstallWarning(
284 errors::kInvalidFileBrowserHandlerMissingPermission));
285 return true;
288 const base::ListValue* file_browser_handlers_list_value = nullptr;
289 if (!file_browser_handlers_value->GetAsList(
290 &file_browser_handlers_list_value)) {
291 *error = base::ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
292 return false;
295 scoped_ptr<FileBrowserHandlerInfo> info(new FileBrowserHandlerInfo);
296 if (!LoadFileBrowserHandlers(extension->id(),
297 file_browser_handlers_list_value,
298 &info->file_browser_handlers, error)) {
299 return false; // Failed to parse file browser actions definition.
302 extension->SetManifestData(keys::kFileBrowserHandlers, info.release());
303 return true;
306 const std::vector<std::string> FileBrowserHandlerParser::Keys() const {
307 return SingleKey(keys::kFileBrowserHandlers);