Home | History | Annotate | Download | only in file_browser_handlers
      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 
     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 
     52 FileBrowserHandlerInfo::FileBrowserHandlerInfo() {
     53 }
     54 
     55 FileBrowserHandlerInfo::~FileBrowserHandlerInfo() {
     56 }
     57 
     58 }  // namespace
     59 
     60 FileBrowserHandler::FileBrowserHandler()
     61     : file_access_permission_flags_(kPermissionsNotDefined) {
     62 }
     63 
     64 FileBrowserHandler::~FileBrowserHandler() {
     65 }
     66 
     67 void FileBrowserHandler::AddPattern(const URLPattern& pattern) {
     68   url_set_.AddPattern(pattern);
     69 }
     70 
     71 void FileBrowserHandler::ClearPatterns() {
     72   url_set_.ClearPatterns();
     73 }
     74 
     75 bool FileBrowserHandler::MatchesURL(const GURL& url) const {
     76   return url_set_.MatchesURL(url);
     77 }
     78 
     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 
     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 
    100 bool FileBrowserHandler::CanRead() const {
    101   DCHECK(!(file_access_permission_flags_ & kInvalidPermission));
    102   return (file_access_permission_flags_ & kReadPermission) != 0;
    103 }
    104 
    105 bool FileBrowserHandler::CanWrite() const {
    106   DCHECK(!(file_access_permission_flags_ & kInvalidPermission));
    107   return (file_access_permission_flags_ & kWritePermission) != 0;
    108 }
    109 
    110 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*
    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 
    125 FileBrowserHandlerParser::FileBrowserHandlerParser() {
    126 }
    127 
    128 FileBrowserHandlerParser::~FileBrowserHandlerParser() {
    129 }
    130 
    131 namespace {
    132 
    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       base::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|.
    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 
    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 
    289 const std::vector<std::string> FileBrowserHandlerParser::Keys() const {
    290   return SingleKey(keys::kFileBrowserHandlers);
    291 }
    292