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