Home | History | Annotate | Download | only in manifest_tests
      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/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"
     16 
     17 namespace extensions {
     18 
     19 namespace errors = manifest_errors;
     20 
     21 class PlatformAppsManifestTest : public ExtensionManifestTest {
     22 };
     23 
     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()));
     29 
     30   extension =
     31       LoadAndExpectSuccess("init_valid_platform_app_no_manifest_version.json");
     32   EXPECT_EQ(2, extension->manifest_version());
     33 
     34   extension = LoadAndExpectSuccess("incognito_valid_platform_app.json");
     35   EXPECT_FALSE(IncognitoInfo::IsSplitMode(extension.get()));
     36 
     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")),
     43   };
     44   RunTestcases(error_testcases, arraysize(error_testcases), EXPECT_TYPE_ERROR);
     45 
     46   Testcase warning_testcases[] = {
     47     Testcase(
     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."),
     51     Testcase(
     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."),
     55     Testcase(
     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."),
     62   };
     63   RunTestcases(
     64       warning_testcases, arraysize(warning_testcases), EXPECT_TYPE_WARNING);
     65 }
     66 
     67 TEST_F(PlatformAppsManifestTest, PlatformAppContentSecurityPolicy) {
     68   // Normal platform apps can't specify a CSP value.
     69   Testcase warning_testcases[] = {
     70     Testcase(
     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."),
     74     Testcase(
     75         "init_platform_app_csp_warning_2.json",
     76         "'app.content_security_policy' is not allowed for specified extension "
     77             "ID.")
     78   };
     79   RunTestcases(
     80       warning_testcases, arraysize(warning_testcases), EXPECT_TYPE_WARNING);
     81 
     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(),
     94                                                       std::string()));
     95 
     96   // But even whitelisted ones must specify a secure policy.
     97   LoadAndExpectError(
     98       "init_platform_app_csp_insecure.json",
     99       errors::kInsecureContentSecurityPolicy);
    100 }
    101 
    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[] = {
    106     "dns",
    107     "serial",
    108   };
    109   // TODO(miket): When the first platform-app API leaves experimental, write
    110   // similar code that tests without the experimental flag.
    111 
    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.
    115   std::string error;
    116   scoped_ptr<base::DictionaryValue> manifest(
    117       LoadManifest("init_valid_platform_app.json", &error));
    118 
    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];
    123 
    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()));
    130   }
    131 
    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);
    136   }
    137 
    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(), ""));
    143   }
    144 }
    145 
    146 }  // namespace extensions
    147