Home | History | Annotate | Download | only in messaging
      1 // Copyright (c) 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/browser/extensions/api/messaging/native_messaging_host_manifest.h"
      6 
      7 #include "base/json/json_file_value_serializer.h"
      8 #include "base/logging.h"
      9 #include "base/values.h"
     10 
     11 namespace extensions {
     12 
     13 NativeMessagingHostManifest::~NativeMessagingHostManifest() {}
     14 
     15 // static
     16 bool NativeMessagingHostManifest::IsValidName(const std::string& name) {
     17   if (name.empty()) {
     18     return false;
     19   }
     20 
     21   for (size_t i = 0; i < name.size(); ++i) {
     22     char c = name[i];
     23 
     24     // Verify that only the following characters are used: [a-z0-9._].
     25     if (!((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
     26           c == '.' || c == '_')) {
     27       return false;
     28     }
     29 
     30     // Verify that dots are separated by other characters and that string
     31     // doesn't begin or end with a dot.
     32     if (c == '.' && (i == 0 || name[i - 1] == '.' || i == name.size() - 1)) {
     33       return false;
     34     }
     35   }
     36 
     37   return true;
     38 }
     39 
     40 // static
     41 scoped_ptr<NativeMessagingHostManifest> NativeMessagingHostManifest::Load(
     42     const base::FilePath& file_path,
     43     std::string* error_message) {
     44   DCHECK(error_message);
     45 
     46   JSONFileValueSerializer serializer(file_path);
     47   scoped_ptr<base::Value> parsed(serializer.Deserialize(NULL, error_message));
     48   if (!parsed) {
     49     return scoped_ptr<NativeMessagingHostManifest>();
     50   }
     51 
     52   base::DictionaryValue* dictionary;
     53   if (!parsed->GetAsDictionary(&dictionary)) {
     54     *error_message = "Invalid manifest file.";
     55     return scoped_ptr<NativeMessagingHostManifest>();
     56   }
     57 
     58   scoped_ptr<NativeMessagingHostManifest> result(
     59       new NativeMessagingHostManifest());
     60   if (!result->Parse(dictionary, error_message)) {
     61     return scoped_ptr<NativeMessagingHostManifest>();
     62   }
     63 
     64   return result.Pass();
     65 }
     66 
     67 NativeMessagingHostManifest::NativeMessagingHostManifest() {
     68 }
     69 
     70 bool NativeMessagingHostManifest::Parse(base::DictionaryValue* dictionary,
     71                                         std::string* error_message) {
     72   if (!dictionary->GetString("name", &name_) ||
     73       !IsValidName(name_)) {
     74     *error_message = "Invalid value for name.";
     75     return false;
     76   }
     77 
     78   if (!dictionary->GetString("description", &description_) ||
     79       description_.empty()) {
     80     *error_message = "Invalid value for description.";
     81     return false;
     82   }
     83 
     84   std::string type;
     85   // stdio is the only host type that's currently supported.
     86   if (!dictionary->GetString("type", &type) ||
     87       type != "stdio") {
     88     *error_message = "Invalid value for type.";
     89     return false;
     90   }
     91   interface_ = HOST_INTERFACE_STDIO;
     92 
     93   std::string path;
     94   // JSON parsed checks that all strings are valid UTF8.
     95   if (!dictionary->GetString("path", &path) ||
     96       (path_ = base::FilePath::FromUTF8Unsafe(path)).empty()) {
     97     *error_message = "Invalid value for path.";
     98     return false;
     99   }
    100 
    101   const base::ListValue* allowed_origins_list;
    102   if (!dictionary->GetList("allowed_origins", &allowed_origins_list)) {
    103     *error_message =
    104         "Invalid value for allowed_origins. Expected a list of strings.";
    105     return false;
    106   }
    107   allowed_origins_.ClearPatterns();
    108   for (base::ListValue::const_iterator it = allowed_origins_list->begin();
    109        it != allowed_origins_list->end(); ++it) {
    110     std::string pattern_string;
    111     if (!(*it)->GetAsString(&pattern_string)) {
    112       *error_message = "allowed_origins must be list of strings.";
    113       return false;
    114     }
    115 
    116     URLPattern pattern(URLPattern::SCHEME_EXTENSION);
    117     URLPattern::ParseResult result = pattern.Parse(pattern_string);
    118     if (result != URLPattern::PARSE_SUCCESS) {
    119       *error_message = "Failed to parse pattern \"" + pattern_string +
    120           "\": " + URLPattern::GetParseResultString(result);
    121       return false;
    122     }
    123 
    124     // Disallow patterns that are too broad. Set of allowed origins must be a
    125     // fixed list of extensions.
    126     if (pattern.match_all_urls() || pattern.match_subdomains()) {
    127       *error_message = "Pattern \"" + pattern_string + "\" is not allowed.";
    128       return false;
    129     }
    130 
    131     allowed_origins_.AddPattern(pattern);
    132   }
    133 
    134   return true;
    135 }
    136 
    137 }  // namespace extensions
    138