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 "content/public/common/url_constants.h"
14 #include "extensions/common/error_utils.h"
15 #include "extensions/common/manifest.h"
16 #include "extensions/common/manifest_constants.h"
17 #include "extensions/common/url_pattern.h"
19 namespace keys
= extensions::manifest_keys
;
20 namespace errors
= extensions::manifest_errors
;
24 const char kReadAccessString
[] = "read";
25 const char kReadWriteAccessString
[] = "read-write";
26 const char kCreateAccessString
[] = "create";
28 unsigned int kPermissionsNotDefined
= 0;
29 unsigned int kReadPermission
= 1;
30 unsigned int kWritePermission
= 1 << 1;
31 unsigned int kCreatePermission
= 1 << 2;
32 unsigned int kInvalidPermission
= 1 << 3;
34 unsigned int GetAccessPermissionFlagFromString(const std::string
& access_str
) {
35 if (access_str
== kReadAccessString
)
36 return kReadPermission
;
37 if (access_str
== kReadWriteAccessString
)
38 return kReadPermission
| kWritePermission
;
39 if (access_str
== kCreateAccessString
)
40 return kCreatePermission
;
41 return kInvalidPermission
;
44 // Stored on the Extension.
45 struct FileBrowserHandlerInfo
: public extensions::Extension::ManifestData
{
46 FileBrowserHandler::List file_browser_handlers
;
48 FileBrowserHandlerInfo();
49 virtual ~FileBrowserHandlerInfo();
52 FileBrowserHandlerInfo::FileBrowserHandlerInfo() {
55 FileBrowserHandlerInfo::~FileBrowserHandlerInfo() {
60 FileBrowserHandler::FileBrowserHandler()
61 : file_access_permission_flags_(kPermissionsNotDefined
) {
64 FileBrowserHandler::~FileBrowserHandler() {
67 void FileBrowserHandler::AddPattern(const URLPattern
& pattern
) {
68 url_set_
.AddPattern(pattern
);
71 void FileBrowserHandler::ClearPatterns() {
72 url_set_
.ClearPatterns();
75 bool FileBrowserHandler::MatchesURL(const GURL
& url
) const {
76 return url_set_
.MatchesURL(url
);
79 bool FileBrowserHandler::AddFileAccessPermission(
80 const std::string
& access
) {
81 file_access_permission_flags_
|= GetAccessPermissionFlagFromString(access
);
82 return (file_access_permission_flags_
& kInvalidPermission
) != 0U;
85 bool FileBrowserHandler::ValidateFileAccessPermissions() {
86 bool is_invalid
= (file_access_permission_flags_
& kInvalidPermission
) != 0U;
87 bool can_create
= (file_access_permission_flags_
& kCreatePermission
) != 0U;
88 bool can_read_or_write
= (file_access_permission_flags_
&
89 (kReadPermission
| kWritePermission
)) != 0U;
90 if (is_invalid
|| (can_create
&& can_read_or_write
)) {
91 file_access_permission_flags_
= kInvalidPermission
;
95 if (file_access_permission_flags_
== kPermissionsNotDefined
)
96 file_access_permission_flags_
= kReadPermission
| kWritePermission
;
100 bool FileBrowserHandler::CanRead() const {
101 DCHECK(!(file_access_permission_flags_
& kInvalidPermission
));
102 return (file_access_permission_flags_
& kReadPermission
) != 0;
105 bool FileBrowserHandler::CanWrite() const {
106 DCHECK(!(file_access_permission_flags_
& kInvalidPermission
));
107 return (file_access_permission_flags_
& kWritePermission
) != 0;
110 bool FileBrowserHandler::HasCreateAccessPermission() const {
111 DCHECK(!(file_access_permission_flags_
& kInvalidPermission
));
112 return (file_access_permission_flags_
& kCreatePermission
) != 0;
116 FileBrowserHandler::List
*
117 FileBrowserHandler::GetHandlers(const extensions::Extension
* extension
) {
118 FileBrowserHandlerInfo
* info
= static_cast<FileBrowserHandlerInfo
*>(
119 extension
->GetManifestData(keys::kFileBrowserHandlers
));
121 return &info
->file_browser_handlers
;
125 FileBrowserHandlerParser::FileBrowserHandlerParser() {
128 FileBrowserHandlerParser::~FileBrowserHandlerParser() {
133 FileBrowserHandler
* LoadFileBrowserHandler(
134 const std::string
& extension_id
,
135 const base::DictionaryValue
* file_browser_handler
,
136 base::string16
* error
) {
137 scoped_ptr
<FileBrowserHandler
> result(new FileBrowserHandler());
138 result
->set_extension_id(extension_id
);
140 std::string handler_id
;
141 // Read the file action |id| (mandatory).
142 if (!file_browser_handler
->HasKey(keys::kPageActionId
) ||
143 !file_browser_handler
->GetString(keys::kPageActionId
, &handler_id
)) {
144 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionId
);
147 result
->set_id(handler_id
);
149 // Read the page action title from |default_title| (mandatory).
151 if (!file_browser_handler
->HasKey(keys::kPageActionDefaultTitle
) ||
152 !file_browser_handler
->GetString(keys::kPageActionDefaultTitle
, &title
)) {
153 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle
);
156 result
->set_title(title
);
158 // Initialize access permissions (optional).
159 const base::ListValue
* access_list_value
= NULL
;
160 if (file_browser_handler
->HasKey(keys::kFileAccessList
)) {
161 if (!file_browser_handler
->GetList(keys::kFileAccessList
,
162 &access_list_value
) ||
163 access_list_value
->empty()) {
164 *error
= base::ASCIIToUTF16(errors::kInvalidFileAccessList
);
167 for (size_t i
= 0; i
< access_list_value
->GetSize(); ++i
) {
169 if (!access_list_value
->GetString(i
, &access
) ||
170 result
->AddFileAccessPermission(access
)) {
171 *error
= extensions::ErrorUtils::FormatErrorMessageUTF16(
172 errors::kInvalidFileAccessValue
, base::IntToString(i
));
177 if (!result
->ValidateFileAccessPermissions()) {
178 *error
= base::ASCIIToUTF16(errors::kInvalidFileAccessList
);
182 // Initialize file filters (mandatory, unless "create" access is specified,
183 // in which case is ignored). The list can be empty.
184 if (!result
->HasCreateAccessPermission()) {
185 const base::ListValue
* file_filters
= NULL
;
186 if (!file_browser_handler
->HasKey(keys::kFileFilters
) ||
187 !file_browser_handler
->GetList(keys::kFileFilters
, &file_filters
)) {
188 *error
= base::ASCIIToUTF16(errors::kInvalidFileFiltersList
);
191 for (size_t i
= 0; i
< file_filters
->GetSize(); ++i
) {
193 if (!file_filters
->GetString(i
, &filter
)) {
194 *error
= extensions::ErrorUtils::FormatErrorMessageUTF16(
195 errors::kInvalidFileFilterValue
, base::IntToString(i
));
198 StringToLowerASCII(&filter
);
199 if (!StartsWithASCII(filter
,
200 std::string(content::kFileSystemScheme
) + ':',
202 *error
= extensions::ErrorUtils::FormatErrorMessageUTF16(
203 errors::kInvalidURLPatternError
, filter
);
206 // The user inputs filesystem:*; we don't actually implement scheme
207 // wildcards in URLPattern, so transform to what will match correctly.
208 filter
.replace(0, 11, "chrome-extension://*/");
209 URLPattern
pattern(URLPattern::SCHEME_EXTENSION
);
210 if (pattern
.Parse(filter
) != URLPattern::PARSE_SUCCESS
) {
211 *error
= extensions::ErrorUtils::FormatErrorMessageUTF16(
212 errors::kInvalidURLPatternError
, filter
);
215 std::string path
= pattern
.path();
216 bool allowed
= path
== "/*" || path
== "/*.*" ||
217 (path
.compare(0, 3, "/*.") == 0 &&
218 path
.find_first_of('*', 3) == std::string::npos
);
220 *error
= extensions::ErrorUtils::FormatErrorMessageUTF16(
221 errors::kInvalidURLPatternError
, filter
);
224 result
->AddPattern(pattern
);
228 std::string default_icon
;
229 // Read the file browser action |default_icon| (optional).
230 if (file_browser_handler
->HasKey(keys::kPageActionDefaultIcon
)) {
231 if (!file_browser_handler
->GetString(
232 keys::kPageActionDefaultIcon
, &default_icon
) ||
233 default_icon
.empty()) {
234 *error
= base::ASCIIToUTF16(errors::kInvalidPageActionIconPath
);
237 result
->set_icon_path(default_icon
);
240 return result
.release();
243 // Loads FileBrowserHandlers from |extension_actions| into a list in |result|.
244 bool LoadFileBrowserHandlers(
245 const std::string
& extension_id
,
246 const base::ListValue
* extension_actions
,
247 FileBrowserHandler::List
* result
,
248 base::string16
* error
) {
249 for (base::ListValue::const_iterator iter
= extension_actions
->begin();
250 iter
!= extension_actions
->end();
252 if (!(*iter
)->IsType(base::Value::TYPE_DICTIONARY
)) {
253 *error
= base::ASCIIToUTF16(errors::kInvalidFileBrowserHandler
);
256 scoped_ptr
<FileBrowserHandler
> action(
257 LoadFileBrowserHandler(
259 reinterpret_cast<base::DictionaryValue
*>(*iter
), error
));
261 return false; // Failed to parse file browser action definition.
262 result
->push_back(linked_ptr
<FileBrowserHandler
>(action
.release()));
269 bool FileBrowserHandlerParser::Parse(extensions::Extension
* extension
,
270 base::string16
* error
) {
271 const base::ListValue
* file_browser_handlers_value
= NULL
;
272 if (!extension
->manifest()->GetList(keys::kFileBrowserHandlers
,
273 &file_browser_handlers_value
)) {
274 *error
= base::ASCIIToUTF16(errors::kInvalidFileBrowserHandler
);
277 scoped_ptr
<FileBrowserHandlerInfo
> info(new FileBrowserHandlerInfo
);
278 if (!LoadFileBrowserHandlers(extension
->id(),
279 file_browser_handlers_value
,
280 &info
->file_browser_handlers
,
282 return false; // Failed to parse file browser actions definition.
285 extension
->SetManifestData(keys::kFileBrowserHandlers
, info
.release());
289 const std::vector
<std::string
> FileBrowserHandlerParser::Keys() const {
290 return SingleKey(keys::kFileBrowserHandlers
);