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 <algorithm>
6
7#include "chrome/common/extensions/extension_manifest_constants.h"
8#include "chrome/common/extensions/features/feature_channel.h"
9#include "chrome/common/extensions/manifest_handlers/externally_connectable.h"
10#include "chrome/common/extensions/manifest_tests/extension_manifest_test.h"
11#include "extensions/common/error_utils.h"
12#include "testing/gmock/include/gmock/gmock.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15using testing::ElementsAre;
16
17namespace extensions {
18
19namespace errors = externally_connectable_errors;
20
21class ExternallyConnectableTest : public ExtensionManifestTest {
22 public:
23  ExternallyConnectableTest() : channel_(chrome::VersionInfo::CHANNEL_DEV) {}
24
25 protected:
26  ExternallyConnectableInfo* GetExternallyConnectableInfo(
27      scoped_refptr<Extension> extension) {
28    return static_cast<ExternallyConnectableInfo*>(extension->GetManifestData(
29        extension_manifest_keys::kExternallyConnectable));
30  }
31
32 private:
33  ScopedCurrentChannel channel_;
34};
35
36TEST_F(ExternallyConnectableTest, IDsAndMatches) {
37  scoped_refptr<Extension> extension =
38      LoadAndExpectSuccess("externally_connectable_ids_and_matches.json");
39  ASSERT_TRUE(extension.get());
40
41  EXPECT_TRUE(extension->HasAPIPermission(APIPermission::kWebConnectable));
42
43  ExternallyConnectableInfo* info =
44      ExternallyConnectableInfo::Get(extension.get());
45  ASSERT_TRUE(info);
46
47  EXPECT_THAT(info->ids, ElementsAre("abcdefghijklmnopabcdefghijklmnop",
48                                     "ponmlkjihgfedcbaponmlkjihgfedcba"));
49
50  EXPECT_FALSE(info->all_ids);
51
52  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://example.com")));
53  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://example.com/")));
54  EXPECT_FALSE(info->matches.MatchesURL(GURL("http://example.com/index.html")));
55
56  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://google.com")));
57  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://google.com/")));
58  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://google.com/index.html")));
59  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://www.google.com")));
60  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://www.google.com/")));
61  EXPECT_TRUE(info->matches.MatchesURL(GURL("https://google.com")));
62  EXPECT_TRUE(info->matches.MatchesURL(GURL("https://google.com/")));
63
64  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://build.chromium.org")));
65  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://build.chromium.org/")));
66  EXPECT_TRUE(
67      info->matches.MatchesURL(GURL("http://build.chromium.org/index.html")));
68  EXPECT_FALSE(info->matches.MatchesURL(GURL("https://build.chromium.org")));
69  EXPECT_FALSE(info->matches.MatchesURL(GURL("https://build.chromium.org/")));
70  EXPECT_FALSE(
71      info->matches.MatchesURL(GURL("http://foo.chromium.org/index.html")));
72
73  EXPECT_FALSE(info->matches.MatchesURL(GURL("http://yahoo.com")));
74  EXPECT_FALSE(info->matches.MatchesURL(GURL("http://yahoo.com/")));
75
76  // TLD-style patterns should match just the TLD.
77  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://appspot.com/foo.html")));
78  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://com")));
79  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://go/here")));
80
81  // TLD-style patterns should *not* match any subdomains of the TLD.
82  EXPECT_FALSE(
83      info->matches.MatchesURL(GURL("http://codereview.appspot.com/foo.html")));
84  EXPECT_FALSE(
85      info->matches.MatchesURL(GURL("http://chromium.com/index.html")));
86  EXPECT_FALSE(info->matches.MatchesURL(GURL("http://here.go/somewhere")));
87
88  // Paths that don't have any wildcards should match the exact domain, but
89  // ignore the trailing slash. This is kind of a corner case, so let's test it.
90  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://no.wildcard.path")));
91  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://no.wildcard.path/")));
92  EXPECT_FALSE(info->matches.MatchesURL(
93        GURL("http://no.wildcard.path/index.html")));
94}
95
96TEST_F(ExternallyConnectableTest, IDs) {
97  scoped_refptr<Extension> extension =
98      LoadAndExpectSuccess("externally_connectable_ids.json");
99  ASSERT_TRUE(extension.get());
100
101  EXPECT_FALSE(extension->HasAPIPermission(APIPermission::kWebConnectable));
102
103  ExternallyConnectableInfo* info =
104      ExternallyConnectableInfo::Get(extension.get());
105  ASSERT_TRUE(info);
106
107  EXPECT_THAT(info->ids, ElementsAre("abcdefghijklmnopabcdefghijklmnop",
108                                     "ponmlkjihgfedcbaponmlkjihgfedcba"));
109
110  EXPECT_FALSE(info->all_ids);
111
112  EXPECT_FALSE(info->matches.MatchesURL(GURL("http://google.com/index.html")));
113}
114
115TEST_F(ExternallyConnectableTest, Matches) {
116  scoped_refptr<Extension> extension =
117      LoadAndExpectSuccess("externally_connectable_matches.json");
118  ASSERT_TRUE(extension.get());
119
120  EXPECT_TRUE(extension->HasAPIPermission(APIPermission::kWebConnectable));
121
122  ExternallyConnectableInfo* info =
123      ExternallyConnectableInfo::Get(extension.get());
124  ASSERT_TRUE(info);
125
126  EXPECT_THAT(info->ids, ElementsAre());
127
128  EXPECT_FALSE(info->all_ids);
129
130  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://example.com")));
131  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://example.com/")));
132  EXPECT_FALSE(info->matches.MatchesURL(GURL("http://example.com/index.html")));
133
134  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://google.com")));
135  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://google.com/")));
136  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://google.com/index.html")));
137  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://www.google.com")));
138  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://www.google.com/")));
139  EXPECT_TRUE(info->matches.MatchesURL(GURL("https://google.com")));
140  EXPECT_TRUE(info->matches.MatchesURL(GURL("https://google.com/")));
141
142  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://build.chromium.org")));
143  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://build.chromium.org/")));
144  EXPECT_TRUE(
145      info->matches.MatchesURL(GURL("http://build.chromium.org/index.html")));
146  EXPECT_FALSE(info->matches.MatchesURL(GURL("https://build.chromium.org")));
147  EXPECT_FALSE(info->matches.MatchesURL(GURL("https://build.chromium.org/")));
148  EXPECT_FALSE(
149      info->matches.MatchesURL(GURL("http://foo.chromium.org/index.html")));
150
151  EXPECT_FALSE(info->matches.MatchesURL(GURL("http://yahoo.com")));
152  EXPECT_FALSE(info->matches.MatchesURL(GURL("http://yahoo.com/")));
153}
154
155TEST_F(ExternallyConnectableTest, AllIDs) {
156  scoped_refptr<Extension> extension =
157      LoadAndExpectSuccess("externally_connectable_all_ids.json");
158  ASSERT_TRUE(extension.get());
159
160  EXPECT_FALSE(extension->HasAPIPermission(APIPermission::kWebConnectable));
161
162  ExternallyConnectableInfo* info =
163      ExternallyConnectableInfo::Get(extension.get());
164  ASSERT_TRUE(info);
165
166  EXPECT_THAT(info->ids, ElementsAre("abcdefghijklmnopabcdefghijklmnop",
167                                     "ponmlkjihgfedcbaponmlkjihgfedcba"));
168
169  EXPECT_TRUE(info->all_ids);
170
171  EXPECT_FALSE(info->matches.MatchesURL(GURL("http://google.com/index.html")));
172}
173
174TEST_F(ExternallyConnectableTest, IdCanConnect) {
175  // Not in order to test that ExternallyConnectableInfo sorts it.
176  std::string matches_ids_array[] = { "g", "h", "c", "i", "a", "z", "b" };
177  std::vector<std::string> matches_ids(
178      matches_ids_array, matches_ids_array + arraysize(matches_ids_array));
179
180  std::string nomatches_ids_array[] = { "2", "3", "1" };
181
182  // all_ids = false.
183  {
184    ExternallyConnectableInfo info(URLPatternSet(), matches_ids, false);
185    for (size_t i = 0; i < matches_ids.size(); ++i)
186      EXPECT_TRUE(info.IdCanConnect(matches_ids[i]));
187    for (size_t i = 0; i < arraysize(nomatches_ids_array); ++i)
188      EXPECT_FALSE(info.IdCanConnect(nomatches_ids_array[i]));
189  }
190
191  // all_ids = true.
192  {
193    ExternallyConnectableInfo info(URLPatternSet(), matches_ids, true);
194    for (size_t i = 0; i < matches_ids.size(); ++i)
195      EXPECT_TRUE(info.IdCanConnect(matches_ids[i]));
196    for (size_t i = 0; i < arraysize(nomatches_ids_array); ++i)
197      EXPECT_TRUE(info.IdCanConnect(nomatches_ids_array[i]));
198  }
199}
200
201TEST_F(ExternallyConnectableTest, ErrorWrongFormat) {
202  LoadAndExpectError("externally_connectable_error_wrong_format.json",
203                     errors::kErrorInvalid);
204}
205
206TEST_F(ExternallyConnectableTest, ErrorBadID) {
207  LoadAndExpectError(
208      "externally_connectable_bad_id.json",
209      ErrorUtils::FormatErrorMessage(errors::kErrorInvalidId, "badid"));
210}
211
212TEST_F(ExternallyConnectableTest, ErrorBadMatches) {
213  LoadAndExpectError(
214      "externally_connectable_error_bad_matches.json",
215      ErrorUtils::FormatErrorMessage(errors::kErrorInvalidMatchPattern,
216                                     "www.yahoo.com"));
217}
218
219TEST_F(ExternallyConnectableTest, WarningNoAllURLs) {
220  scoped_refptr<Extension> extension = LoadAndExpectWarning(
221      "externally_connectable_error_all_urls.json",
222      ErrorUtils::FormatErrorMessage(errors::kErrorWildcardHostsNotAllowed,
223                                     "<all_urls>"));
224  ExternallyConnectableInfo* info = GetExternallyConnectableInfo(extension);
225  EXPECT_FALSE(info->matches.ContainsPattern(
226      URLPattern(URLPattern::SCHEME_ALL, "<all_urls>")));
227  EXPECT_TRUE(info->matches.MatchesURL(GURL("https://example.com")));
228  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://build.chromium.org")));
229}
230
231TEST_F(ExternallyConnectableTest, WarningWildcardHost) {
232  scoped_refptr<Extension> extension = LoadAndExpectWarning(
233      "externally_connectable_error_wildcard_host.json",
234      ErrorUtils::FormatErrorMessage(errors::kErrorWildcardHostsNotAllowed,
235                                     "http://*/*"));
236  ExternallyConnectableInfo* info = GetExternallyConnectableInfo(extension);
237  EXPECT_FALSE(info->matches.ContainsPattern(
238      URLPattern(URLPattern::SCHEME_ALL, "http://*/*")));
239  EXPECT_TRUE(info->matches.MatchesURL(GURL("https://example.com")));
240  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://build.chromium.org")));
241}
242
243TEST_F(ExternallyConnectableTest, WarningNoTLD) {
244  scoped_refptr<Extension> extension = LoadAndExpectWarning(
245      "externally_connectable_error_tld.json",
246      ErrorUtils::FormatErrorMessage(
247          errors::kErrorTopLevelDomainsNotAllowed,
248          "co.uk",
249          "http://*.co.uk/*"));
250  ExternallyConnectableInfo* info = GetExternallyConnectableInfo(extension);
251  EXPECT_FALSE(info->matches.ContainsPattern(
252      URLPattern(URLPattern::SCHEME_ALL, "http://*.co.uk/*")));
253  EXPECT_TRUE(info->matches.MatchesURL(GURL("https://example.com")));
254  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://build.chromium.org")));
255}
256
257TEST_F(ExternallyConnectableTest, WarningNoEffectiveTLD) {
258  scoped_refptr<Extension> extension = LoadAndExpectWarning(
259      "externally_connectable_error_effective_tld.json",
260      ErrorUtils::FormatErrorMessage(
261          errors::kErrorTopLevelDomainsNotAllowed,
262          "appspot.com",
263          "http://*.appspot.com/*"));
264  ExternallyConnectableInfo* info = GetExternallyConnectableInfo(extension);
265  EXPECT_FALSE(info->matches.ContainsPattern(
266      URLPattern(URLPattern::SCHEME_ALL, "http://*.appspot.com/*")));
267  EXPECT_TRUE(info->matches.MatchesURL(GURL("https://example.com")));
268  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://build.chromium.org")));
269}
270
271TEST_F(ExternallyConnectableTest, WarningUnknownTLD) {
272  scoped_refptr<Extension> extension = LoadAndExpectWarning(
273      "externally_connectable_error_unknown_tld.json",
274      ErrorUtils::FormatErrorMessage(
275          errors::kErrorTopLevelDomainsNotAllowed,
276          "notatld",
277          "http://*.notatld/*"));
278  ExternallyConnectableInfo* info = GetExternallyConnectableInfo(extension);
279  EXPECT_FALSE(info->matches.ContainsPattern(
280      URLPattern(URLPattern::SCHEME_ALL, "http://*.notatld/*")));
281  EXPECT_TRUE(info->matches.MatchesURL(GURL("https://example.com")));
282  EXPECT_TRUE(info->matches.MatchesURL(GURL("http://build.chromium.org")));
283}
284
285TEST_F(ExternallyConnectableTest, WarningNothingSpecified) {
286  LoadAndExpectWarning("externally_connectable_nothing_specified.json",
287                       errors::kErrorNothingSpecified);
288}
289
290}  // namespace extensions
291