1 // Copyright (c) 2012 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 "base/command_line.h" 6 #include "base/json/json_file_value_serializer.h" 7 #include "base/memory/linked_ptr.h" 8 #include "chrome/common/extensions/manifest_handlers/app_isolation_info.h" 9 #include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h" 10 #include "extensions/common/error_utils.h" 11 #include "extensions/common/manifest_constants.h" 12 #include "extensions/common/manifest_handlers/csp_info.h" 13 #include "extensions/common/manifest_handlers/incognito_info.h" 14 #include "extensions/common/switches.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 17 namespace extensions { 18 19 namespace errors = manifest_errors; 20 21 class PlatformAppsManifestTest : public ChromeManifestTest { 22 }; 23 24 TEST_F(PlatformAppsManifestTest, PlatformApps) { 25 scoped_refptr<Extension> extension = 26 LoadAndExpectSuccess("init_valid_platform_app.json"); 27 EXPECT_TRUE(AppIsolationInfo::HasIsolatedStorage(extension.get())); 28 EXPECT_FALSE(IncognitoInfo::IsSplitMode(extension.get())); 29 30 extension = 31 LoadAndExpectSuccess("init_valid_platform_app_no_manifest_version.json"); 32 EXPECT_EQ(2, extension->manifest_version()); 33 34 extension = LoadAndExpectSuccess("incognito_valid_platform_app.json"); 35 EXPECT_FALSE(IncognitoInfo::IsSplitMode(extension.get())); 36 37 Testcase error_testcases[] = { 38 Testcase("init_invalid_platform_app_2.json", 39 errors::kBackgroundRequiredForPlatformApps), 40 Testcase("init_invalid_platform_app_3.json", 41 ErrorUtils::FormatErrorMessage( 42 errors::kInvalidManifestVersionOld, "2", "apps")), 43 }; 44 RunTestcases(error_testcases, arraysize(error_testcases), EXPECT_TYPE_ERROR); 45 46 Testcase warning_testcases[] = { 47 Testcase( 48 "init_invalid_platform_app_1.json", 49 "'app.launch' is only allowed for hosted apps and legacy packaged " 50 "apps, but this is a packaged app."), 51 Testcase( 52 "init_invalid_platform_app_4.json", 53 "'background' is only allowed for extensions, hosted apps, and legacy " 54 "packaged apps, but this is a packaged app."), 55 Testcase( 56 "init_invalid_platform_app_5.json", 57 "'background' is only allowed for extensions, hosted apps, and legacy " 58 "packaged apps, but this is a packaged app."), 59 Testcase("incognito_invalid_platform_app.json", 60 "'incognito' is only allowed for extensions and legacy packaged apps, " 61 "but this is a packaged app."), 62 }; 63 RunTestcases( 64 warning_testcases, arraysize(warning_testcases), EXPECT_TYPE_WARNING); 65 } 66 67 TEST_F(PlatformAppsManifestTest, PlatformAppContentSecurityPolicy) { 68 // Normal platform apps can't specify a CSP value. 69 Testcase warning_testcases[] = { 70 Testcase( 71 "init_platform_app_csp_warning_1.json", 72 "'content_security_policy' is only allowed for extensions and legacy " 73 "packaged apps, but this is a packaged app."), 74 Testcase( 75 "init_platform_app_csp_warning_2.json", 76 "'app.content_security_policy' is not allowed for specified extension " 77 "ID.") 78 }; 79 RunTestcases( 80 warning_testcases, arraysize(warning_testcases), EXPECT_TYPE_WARNING); 81 82 // Whitelisted ones can (this is the ID corresponding to the base 64 encoded 83 // key in the init_platform_app_csp.json manifest.) 84 std::string test_id = "ahplfneplbnjcflhdgkkjeiglkkfeelb"; 85 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 86 switches::kWhitelistedExtensionID, test_id); 87 scoped_refptr<Extension> extension = 88 LoadAndExpectSuccess("init_platform_app_csp.json"); 89 EXPECT_EQ(0U, extension->install_warnings().size()) 90 << "Unexpected warning " << extension->install_warnings()[0].message; 91 EXPECT_TRUE(extension->is_platform_app()); 92 EXPECT_EQ("default-src 'self' https://www.google.com", 93 CSPInfo::GetResourceContentSecurityPolicy(extension.get(), 94 std::string())); 95 96 // But even whitelisted ones must specify a secure policy. 97 LoadAndExpectError( 98 "init_platform_app_csp_insecure.json", 99 errors::kInsecureContentSecurityPolicy); 100 } 101 102 TEST_F(PlatformAppsManifestTest, CertainApisRequirePlatformApps) { 103 // Put APIs here that should be restricted to platform apps, but that haven't 104 // yet graduated from experimental. 105 const char* kPlatformAppExperimentalApis[] = { 106 "dns", 107 "serial", 108 }; 109 // TODO(miket): When the first platform-app API leaves experimental, write 110 // similar code that tests without the experimental flag. 111 112 // This manifest is a skeleton used to build more specific manifests for 113 // testing. The requirements are that (1) it be a valid platform app, and (2) 114 // it contain no permissions dictionary. 115 std::string error; 116 scoped_ptr<base::DictionaryValue> manifest( 117 LoadManifest("init_valid_platform_app.json", &error)); 118 119 std::vector<linked_ptr<base::DictionaryValue> > manifests; 120 // Create each manifest. 121 for (size_t i = 0; i < arraysize(kPlatformAppExperimentalApis); ++i) { 122 const char* api_name = kPlatformAppExperimentalApis[i]; 123 124 // DictionaryValue will take ownership of this ListValue. 125 base::ListValue *permissions = new base::ListValue(); 126 permissions->Append(new base::StringValue("experimental")); 127 permissions->Append(new base::StringValue(api_name)); 128 manifest->Set("permissions", permissions); 129 manifests.push_back(make_linked_ptr(manifest->DeepCopy())); 130 } 131 132 // First try to load without any flags. This should fail for every API. 133 for (size_t i = 0; i < arraysize(kPlatformAppExperimentalApis); ++i) { 134 LoadAndExpectError(ManifestData(manifests[i].get(), ""), 135 errors::kExperimentalFlagRequired); 136 } 137 138 // Now try again with the experimental flag set. 139 CommandLine::ForCurrentProcess()->AppendSwitch( 140 switches::kEnableExperimentalExtensionApis); 141 for (size_t i = 0; i < arraysize(kPlatformAppExperimentalApis); ++i) { 142 LoadAndExpectSuccess(ManifestData(manifests[i].get(), "")); 143 } 144 } 145 146 } // namespace extensions 147