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