File: extension_manifests_platformapp_unittest.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (168 lines) | stat: -rw-r--r-- 6,956 bytes parent folder | download | duplicates (6)
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