1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <memory>
#include "base/command_line.h"
#include "base/json/json_file_value_serializer.h"
#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/features/simple_feature.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handlers/csp_info.h"
#include "extensions/common/manifest_handlers/incognito_info.h"
#include "extensions/common/switches.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
namespace {
static constexpr char kBackgroundDisallowedWarning[] =
"'background' is only allowed for extensions, legacy packaged "
"apps, hosted apps, login screen extensions, and chromeos "
"system extensions, but this is a packaged app.";
static constexpr char kBackgroundScriptsDisallowedWarning[] =
"'background.scripts' is only allowed for extensions, legacy packaged "
"apps, hosted apps, login screen extensions, and chromeos system "
"extensions, but this is a packaged app.";
static constexpr char kBackgroundPageDisallowedWarning[] =
"'background.page' is only allowed for extensions, legacy packaged "
"apps, hosted apps, login screen extensions, and chromeos system "
"extensions, but this is a packaged app.";
} // namespace
namespace errors = manifest_errors;
namespace keys = manifest_keys;
using PlatformAppsManifestTest = ChromeManifestTest;
TEST_F(PlatformAppsManifestTest, PlatformApps) {
scoped_refptr<Extension> extension =
LoadAndExpectSuccess("init_valid_platform_app.json");
// Ensure this is treated as platform app, which causes it to have isolated
// storage in the browser process. See also
// ExtensionUtilUnittest.HasIsolatedStorage.
EXPECT_TRUE(extension->is_platform_app());
EXPECT_FALSE(IncognitoInfo::IsSplitMode(extension.get()));
extension =
LoadAndExpectSuccess("init_valid_platform_app_no_manifest_version.json");
EXPECT_EQ(2, extension->manifest_version());
extension = LoadAndExpectSuccess("incognito_valid_platform_app.json");
EXPECT_FALSE(IncognitoInfo::IsSplitMode(extension.get()));
const Testcase error_testcases[] = {
Testcase("init_invalid_platform_app_2.json",
errors::kBackgroundRequiredForPlatformApps),
Testcase("init_invalid_platform_app_3.json",
ErrorUtils::FormatErrorMessage(
errors::kInvalidManifestVersionUnsupported, "either 2 or 3",
"apps")),
};
RunTestcases(error_testcases, EXPECT_TYPE_ERROR);
const Testcase warning_testcases[] = {
Testcase(
"init_invalid_platform_app_1.json",
"'app.launch' is only allowed for legacy packaged apps and hosted "
"apps, but this is a packaged app."),
Testcase("incognito_invalid_platform_app.json",
"'incognito' is only allowed for extensions and legacy packaged "
"apps, "
"but this is a packaged app."),
};
RunTestcases(warning_testcases, EXPECT_TYPE_WARNING);
LoadAndExpectWarnings(
"init_invalid_platform_app_4.json",
{kBackgroundDisallowedWarning, kBackgroundScriptsDisallowedWarning});
LoadAndExpectWarnings(
"init_invalid_platform_app_5.json",
{kBackgroundDisallowedWarning, kBackgroundPageDisallowedWarning});
}
TEST_F(PlatformAppsManifestTest, PlatformAppContentSecurityPolicy) {
// Normal platform apps can't specify a CSP value.
const Testcase warning_testcases[] = {
Testcase(
"init_platform_app_csp_warning_1.json",
"'content_security_policy' is only allowed for extensions, legacy "
"packaged apps, and login screen extensions, but this is a "
"packaged app."),
Testcase("init_platform_app_csp_warning_2.json",
"'app.content_security_policy' is not allowed for specified "
"extension "
"ID.")};
RunTestcases(warning_testcases, EXPECT_TYPE_WARNING);
// Allowlisted ones can (this is the ID corresponding to the base 64 encoded
// key in the init_platform_app_csp.json manifest.)
SimpleFeature::ScopedThreadUnsafeAllowlistForTest allowlist(
"ahplfneplbnjcflhdgkkjeiglkkfeelb");
scoped_refptr<Extension> extension =
LoadAndExpectSuccess("init_platform_app_csp.json");
EXPECT_EQ(0U, extension->install_warnings().size())
<< "Unexpected warning " << extension->install_warnings()[0].message;
EXPECT_TRUE(extension->is_platform_app());
EXPECT_EQ("default-src 'self' https://www.google.com;",
CSPInfo::GetResourceContentSecurityPolicy(extension.get(),
std::string()));
// But even allowlisted ones must specify a secure policy.
LoadAndExpectWarning(
"init_platform_app_csp_insecure.json",
ErrorUtils::FormatErrorMessage(errors::kInvalidCSPInsecureValueIgnored,
keys::kPlatformAppContentSecurityPolicy,
"http://www.google.com", "default-src"));
}
TEST_F(PlatformAppsManifestTest, CertainApisRequirePlatformApps) {
// Put APIs here that should be restricted to platform apps, but that haven't
// yet graduated from experimental.
static constexpr const char* kPlatformAppExperimentalApis[] = {
"dns",
"serial",
};
// TODO(miket): When the first platform-app API leaves experimental, write
// similar code that tests without the experimental flag.
// This manifest is a skeleton used to build more specific manifests for
// testing. The requirements are that (1) it be a valid platform app, and (2)
// it contain no permissions dictionary.
std::string error;
std::optional<base::Value::Dict> platform_app_manifest =
LoadManifest("init_valid_platform_app.json", &error);
ASSERT_TRUE(platform_app_manifest);
std::vector<ManifestData> manifests;
// Create each manifest.
for (const char* api_name : kPlatformAppExperimentalApis) {
base::Value::List permissions;
permissions.Append("experimental");
permissions.Append(api_name);
platform_app_manifest->Set("permissions", std::move(permissions));
manifests.emplace_back(platform_app_manifest->Clone());
}
// First try to load without any flags. This should warn for every API.
for (const auto& manifest : manifests) {
LoadAndExpectWarning(
manifest,
"'experimental' requires the 'experimental-extension-apis' "
"command line switch to be enabled.");
}
// Now try again with the experimental flag set.
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
for (const auto& manifest : manifests) {
LoadAndExpectSuccess(manifest);
}
}
} // namespace extensions
|