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.
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/extension_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"
17 namespace extensions
{
19 namespace errors
= manifest_errors
;
21 class PlatformAppsManifestTest
: public ExtensionManifestTest
{
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()));
31 LoadAndExpectSuccess("init_valid_platform_app_no_manifest_version.json");
32 EXPECT_EQ(2, extension
->manifest_version());
34 extension
= LoadAndExpectSuccess("incognito_valid_platform_app.json");
35 EXPECT_FALSE(IncognitoInfo::IsSplitMode(extension
.get()));
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")),
44 RunTestcases(error_testcases
, arraysize(error_testcases
), EXPECT_TYPE_ERROR
);
46 Testcase warning_testcases
[] = {
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."),
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."),
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."),
64 warning_testcases
, arraysize(warning_testcases
), EXPECT_TYPE_WARNING
);
67 TEST_F(PlatformAppsManifestTest
, PlatformAppContentSecurityPolicy
) {
68 // Normal platform apps can't specify a CSP value.
69 Testcase warning_testcases
[] = {
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."),
75 "init_platform_app_csp_warning_2.json",
76 "'app.content_security_policy' is not allowed for specified extension "
80 warning_testcases
, arraysize(warning_testcases
), EXPECT_TYPE_WARNING
);
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(),
96 // But even whitelisted ones must specify a secure policy.
98 "init_platform_app_csp_insecure.json",
99 errors::kInsecureContentSecurityPolicy
);
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
[] = {
109 // TODO(miket): When the first platform-app API leaves experimental, write
110 // similar code that tests without the experimental flag.
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.
116 scoped_ptr
<base::DictionaryValue
> manifest(
117 LoadManifest("init_valid_platform_app.json", &error
));
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
];
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()));
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(Manifest(manifests
[i
].get(), ""),
135 errors::kExperimentalFlagRequired
);
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(Manifest(manifests
[i
].get(), ""));
146 } // namespace extensions