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