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