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