externally_connectable.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/extensions/manifest_handlers/externally_connectable.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <algorithm> 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/stl_util.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/extensions/api/manifest_types.h" 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/extensions/extension_manifest_constants.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/extensions/permissions/api_permission_set.h" 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/extensions/permissions/permissions_data.h" 15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/common/error_utils.h" 16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/common/url_pattern.h" 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "googleurl/src/gurl.h" 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/base/registry_controlled_domains/registry_controlled_domain.h" 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace rcd = net::registry_controlled_domains; 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace extensions { 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace externally_connectable_errors { 25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kErrorInvalid[] = "Invalid value for 'externally_connectable'"; 26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kErrorInvalidMatchPattern[] = "Invalid match pattern '*'"; 27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kErrorInvalidId[] = "Invalid ID '*'"; 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kErrorTopLevelDomainsNotAllowed[] = 29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "\"*\" is an effective top level domain for which wildcard subdomains such " 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "as \"*\" are not allowed"; 31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const char kErrorWildcardHostsNotAllowed[] = 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) "Wildcard domain patterns such as \"*\" are not allowed"; 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace keys = extension_manifest_keys; 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace errors = externally_connectable_errors; 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using api::manifest_types::ExternallyConnectable; 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace { 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kAllIds[] = "*"; 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)template <typename T> 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)std::vector<T> Sorted(const std::vector<T>& in) { 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::vector<T> out = in; 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::sort(out.begin(), out.end()); 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return out; 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} // namespace 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ExternallyConnectableHandler::ExternallyConnectableHandler() {} 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ExternallyConnectableHandler::~ExternallyConnectableHandler() {} 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool ExternallyConnectableHandler::Parse(Extension* extension, 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) string16* error) { 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::Value* externally_connectable = NULL; 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) CHECK(extension->manifest()->Get(keys::kExternallyConnectable, 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &externally_connectable)); 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<ExternallyConnectableInfo> info = 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ExternallyConnectableInfo::FromValue(*externally_connectable, error); 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!info) 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return false; 65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!info->matches.is_empty()) { 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) PermissionsData::GetInitialAPIPermissions(extension)->insert( 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) APIPermission::kWebConnectable); 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) extension->SetManifestData(keys::kExternallyConnectable, info.release()); 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return true; 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const std::vector<std::string> ExternallyConnectableHandler::Keys() const { 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return SingleKey(keys::kExternallyConnectable); 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ExternallyConnectableInfo* ExternallyConnectableInfo::Get( 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const Extension* extension) { 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return static_cast<ExternallyConnectableInfo*>( 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) extension->GetManifestData(keys::kExternallyConnectable)); 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)scoped_ptr<ExternallyConnectableInfo> ExternallyConnectableInfo::FromValue( 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::Value& value, 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) string16* error) { 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<ExternallyConnectable> externally_connectable = 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ExternallyConnectable::FromValue(value); 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (!externally_connectable) { 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *error = UTF8ToUTF16(errors::kErrorInvalid); 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return scoped_ptr<ExternallyConnectableInfo>(); 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) URLPatternSet matches; 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (externally_connectable->matches) { 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (std::vector<std::string>::iterator it = 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) externally_connectable->matches->begin(); 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) it != externally_connectable->matches->end(); ++it) { 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Safe to use SCHEME_ALL here; externally_connectable gives a page -> 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // extension communication path, not the other way. 103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) URLPattern pattern(URLPattern::SCHEME_ALL); 104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (pattern.Parse(*it) != URLPattern::PARSE_SUCCESS) { 105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) errors::kErrorInvalidMatchPattern, *it); 107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return scoped_ptr<ExternallyConnectableInfo>(); 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Wildcard hosts are not allowed. 111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (pattern.host().empty()) { 112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) errors::kErrorWildcardHostsNotAllowed, *it); 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return scoped_ptr<ExternallyConnectableInfo>(); 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Wildcards on subdomains of a TLD are not allowed. 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) size_t registry_length = rcd::GetRegistryLength( 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pattern.host(), 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // This means that things that look like TLDs - the foobar in 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // http://google.foobar - count as TLDs. 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rcd::INCLUDE_UNKNOWN_REGISTRIES, 123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // This means that effective TLDs like appspot.com count as TLDs; 124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // codereview.appspot.com and evil.appspot.com are different. 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) rcd::INCLUDE_PRIVATE_REGISTRIES); 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (registry_length == std::string::npos) { 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // The URL parsing combined with host().empty() should have caught this. 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NOTREACHED() << *it; 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) errors::kErrorInvalidMatchPattern, *it); 132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return scoped_ptr<ExternallyConnectableInfo>(); 133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Broad match patterns like "*.com", "*.co.uk", and even "*.appspot.com" 136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // are not allowed. However just "appspot.com" is ok. 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (registry_length == 0 && pattern.match_subdomains()) { 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) errors::kErrorTopLevelDomainsNotAllowed, 140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pattern.host().c_str(), 141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) *it); 142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return scoped_ptr<ExternallyConnectableInfo>(); 143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) matches.AddPattern(pattern); 146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::vector<std::string> ids; 150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool all_ids = false; 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (externally_connectable->ids) { 153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) for (std::vector<std::string>::iterator it = 154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) externally_connectable->ids->begin(); 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) it != externally_connectable->ids->end(); ++it) { 156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (*it == kAllIds) { 157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) all_ids = true; 158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else if (Extension::IdIsValid(*it)) { 159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ids.push_back(*it); 160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *error = ErrorUtils::FormatErrorMessageUTF16( 162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) errors::kErrorInvalidId, *it); 163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return scoped_ptr<ExternallyConnectableInfo>(); 164c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return make_scoped_ptr( 169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) new ExternallyConnectableInfo(matches, ids, all_ids)); 170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 172c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ExternallyConnectableInfo::~ExternallyConnectableInfo() {} 173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ExternallyConnectableInfo::ExternallyConnectableInfo( 175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const URLPatternSet& matches, 176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::vector<std::string>& ids, 177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool all_ids) 178868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : matches(matches), ids(Sorted(ids)), all_ids(all_ids) {} 179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool ExternallyConnectableInfo::IdCanConnect(const std::string& id) { 181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (all_ids) 182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return true; 183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(base::STLIsSorted(ids)); 184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return std::binary_search(ids.begin(), ids.end(), id); 185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 186c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace extensions 188