• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h"
6 
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/manifest.h"
15 #include "extensions/common/manifest_constants.h"
16 #include "extensions/common/url_pattern.h"
17 #include "url/url_constants.h"
18 
19 namespace keys = extensions::manifest_keys;
20 namespace errors = extensions::manifest_errors;
21 
22 namespace {
23 
24 const char kReadAccessString[] = "read";
25 const char kReadWriteAccessString[] = "read-write";
26 const char kCreateAccessString[] = "create";
27 
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;
33 
GetAccessPermissionFlagFromString(const std::string & access_str)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;
42 }
43 
44 // Stored on the Extension.
45 struct FileBrowserHandlerInfo : public extensions::Extension::ManifestData {
46   FileBrowserHandler::List file_browser_handlers;
47 
48   FileBrowserHandlerInfo();
49   virtual ~FileBrowserHandlerInfo();
50 };
51 
FileBrowserHandlerInfo()52 FileBrowserHandlerInfo::FileBrowserHandlerInfo() {
53 }
54 
~FileBrowserHandlerInfo()55 FileBrowserHandlerInfo::~FileBrowserHandlerInfo() {
56 }
57 
58 }  // namespace
59 
FileBrowserHandler()60 FileBrowserHandler::FileBrowserHandler()
61     : file_access_permission_flags_(kPermissionsNotDefined) {
62 }
63 
~FileBrowserHandler()64 FileBrowserHandler::~FileBrowserHandler() {
65 }
66 
AddPattern(const URLPattern & pattern)67 void FileBrowserHandler::AddPattern(const URLPattern& pattern) {
68   url_set_.AddPattern(pattern);
69 }
70 
ClearPatterns()71 void FileBrowserHandler::ClearPatterns() {
72   url_set_.ClearPatterns();
73 }
74 
MatchesURL(const GURL & url) const75 bool FileBrowserHandler::MatchesURL(const GURL& url) const {
76   return url_set_.MatchesURL(url);
77 }
78 
AddFileAccessPermission(const std::string & access)79 bool FileBrowserHandler::AddFileAccessPermission(
80     const std::string& access) {
81   file_access_permission_flags_ |= GetAccessPermissionFlagFromString(access);
82   return (file_access_permission_flags_ & kInvalidPermission) != 0U;
83 }
84 
ValidateFileAccessPermissions()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;
92     return false;
93   }
94 
95   if (file_access_permission_flags_ == kPermissionsNotDefined)
96     file_access_permission_flags_ = kReadPermission | kWritePermission;
97   return true;
98 }
99 
CanRead() const100 bool FileBrowserHandler::CanRead() const {
101   DCHECK(!(file_access_permission_flags_ & kInvalidPermission));
102   return (file_access_permission_flags_ & kReadPermission) != 0;
103 }
104 
CanWrite() const105 bool FileBrowserHandler::CanWrite() const {
106   DCHECK(!(file_access_permission_flags_ & kInvalidPermission));
107   return (file_access_permission_flags_ & kWritePermission) != 0;
108 }
109 
HasCreateAccessPermission() const110 bool FileBrowserHandler::HasCreateAccessPermission() const {
111   DCHECK(!(file_access_permission_flags_ & kInvalidPermission));
112   return (file_access_permission_flags_ & kCreatePermission) != 0;
113 }
114 
115 // static
116 FileBrowserHandler::List*
GetHandlers(const extensions::Extension * extension)117 FileBrowserHandler::GetHandlers(const extensions::Extension* extension) {
118   FileBrowserHandlerInfo* info = static_cast<FileBrowserHandlerInfo*>(
119       extension->GetManifestData(keys::kFileBrowserHandlers));
120   if (info)
121     return &info->file_browser_handlers;
122   return NULL;
123 }
124 
FileBrowserHandlerParser()125 FileBrowserHandlerParser::FileBrowserHandlerParser() {
126 }
127 
~FileBrowserHandlerParser()128 FileBrowserHandlerParser::~FileBrowserHandlerParser() {
129 }
130 
131 namespace {
132 
LoadFileBrowserHandler(const std::string & extension_id,const base::DictionaryValue * file_browser_handler,base::string16 * error)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);
139 
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);
145     return NULL;
146   }
147   result->set_id(handler_id);
148 
149   // Read the page action title from |default_title| (mandatory).
150   std::string title;
151   if (!file_browser_handler->HasKey(keys::kPageActionDefaultTitle) ||
152       !file_browser_handler->GetString(keys::kPageActionDefaultTitle, &title)) {
153     *error = base::ASCIIToUTF16(errors::kInvalidPageActionDefaultTitle);
154     return NULL;
155   }
156   result->set_title(title);
157 
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);
165       return NULL;
166     }
167     for (size_t i = 0; i < access_list_value->GetSize(); ++i) {
168       std::string access;
169       if (!access_list_value->GetString(i, &access) ||
170           result->AddFileAccessPermission(access)) {
171         *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
172             errors::kInvalidFileAccessValue, base::IntToString(i));
173         return NULL;
174       }
175     }
176   }
177   if (!result->ValidateFileAccessPermissions()) {
178     *error = base::ASCIIToUTF16(errors::kInvalidFileAccessList);
179     return NULL;
180   }
181 
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);
189       return NULL;
190     }
191     for (size_t i = 0; i < file_filters->GetSize(); ++i) {
192       std::string filter;
193       if (!file_filters->GetString(i, &filter)) {
194         *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
195             errors::kInvalidFileFilterValue, base::IntToString(i));
196         return NULL;
197       }
198       StringToLowerASCII(&filter);
199       if (!StartsWithASCII(filter,
200                            std::string(url::kFileSystemScheme) + ':',
201                            true)) {
202         *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
203             errors::kInvalidURLPatternError, filter);
204         return NULL;
205       }
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);
213         return NULL;
214       }
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);
219       if (!allowed) {
220         *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
221             errors::kInvalidURLPatternError, filter);
222         return NULL;
223       }
224       result->AddPattern(pattern);
225     }
226   }
227 
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);
235       return NULL;
236     }
237     result->set_icon_path(default_icon);
238   }
239 
240   return result.release();
241 }
242 
243 // Loads FileBrowserHandlers from |extension_actions| into a list in |result|.
LoadFileBrowserHandlers(const std::string & extension_id,const base::ListValue * extension_actions,FileBrowserHandler::List * result,base::string16 * error)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();
251        ++iter) {
252     if (!(*iter)->IsType(base::Value::TYPE_DICTIONARY)) {
253       *error = base::ASCIIToUTF16(errors::kInvalidFileBrowserHandler);
254       return false;
255     }
256     scoped_ptr<FileBrowserHandler> action(
257         LoadFileBrowserHandler(
258             extension_id,
259             reinterpret_cast<base::DictionaryValue*>(*iter), error));
260     if (!action.get())
261       return false;  // Failed to parse file browser action definition.
262     result->push_back(linked_ptr<FileBrowserHandler>(action.release()));
263   }
264   return true;
265 }
266 
267 }  // namespace
268 
Parse(extensions::Extension * extension,base::string16 * error)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);
275     return false;
276   }
277   scoped_ptr<FileBrowserHandlerInfo> info(new FileBrowserHandlerInfo);
278   if (!LoadFileBrowserHandlers(extension->id(),
279                                file_browser_handlers_value,
280                                &info->file_browser_handlers,
281                                error)) {
282     return false;  // Failed to parse file browser actions definition.
283   }
284 
285   extension->SetManifestData(keys::kFileBrowserHandlers, info.release());
286   return true;
287 }
288 
Keys() const289 const std::vector<std::string> FileBrowserHandlerParser::Keys() const {
290   return SingleKey(keys::kFileBrowserHandlers);
291 }
292