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.h" 6 7 #include <algorithm> 8 #include <set> 9 #include <string> 10 11 #include "base/memory/scoped_ptr.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "base/values.h" 14 #include "chrome/common/extensions/extension_manifest_constants.h" 15 #include "chrome/common/extensions/features/feature.h" 16 #include "chrome/common/extensions/features/simple_feature.h" 17 #include "extensions/common/error_utils.h" 18 #include "extensions/common/install_warning.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 21 namespace errors = extension_manifest_errors; 22 namespace keys = extension_manifest_keys; 23 24 namespace extensions { 25 26 class ManifestTest : public testing::Test { 27 public: 28 ManifestTest() : default_value_("test") {} 29 30 protected: 31 void AssertType(Manifest* manifest, Manifest::Type type) { 32 EXPECT_EQ(type, manifest->type()); 33 EXPECT_EQ(type == Manifest::TYPE_THEME, manifest->is_theme()); 34 EXPECT_EQ(type == Manifest::TYPE_PLATFORM_APP, 35 manifest->is_platform_app()); 36 EXPECT_EQ(type == Manifest::TYPE_LEGACY_PACKAGED_APP, 37 manifest->is_legacy_packaged_app()); 38 EXPECT_EQ(type == Manifest::TYPE_HOSTED_APP, manifest->is_hosted_app()); 39 EXPECT_EQ(type == Manifest::TYPE_SHARED_MODULE, 40 manifest->is_shared_module()); 41 } 42 43 // Helper function that replaces the Manifest held by |manifest| with a copy 44 // with its |key| changed to |value|. If |value| is NULL, then |key| will 45 // instead be deleted. 46 void MutateManifest(scoped_ptr<Manifest>* manifest, 47 const std::string& key, 48 base::Value* value) { 49 scoped_ptr<base::DictionaryValue> manifest_value( 50 manifest->get()->value()->DeepCopy()); 51 if (value) 52 manifest_value->Set(key, value); 53 else 54 manifest_value->Remove(key, NULL); 55 manifest->reset(new Manifest(Manifest::INTERNAL, manifest_value.Pass())); 56 } 57 58 std::string default_value_; 59 }; 60 61 // Verifies that extensions can access the correct keys. 62 TEST_F(ManifestTest, Extension) { 63 scoped_ptr<base::DictionaryValue> manifest_value(new base::DictionaryValue()); 64 manifest_value->SetString(keys::kName, "extension"); 65 manifest_value->SetString(keys::kVersion, "1"); 66 // Only supported in manifest_version=1. 67 manifest_value->SetString(keys::kBackgroundPageLegacy, "bg.html"); 68 manifest_value->SetString("unknown_key", "foo"); 69 70 scoped_ptr<Manifest> manifest( 71 new Manifest(Manifest::INTERNAL, manifest_value.Pass())); 72 std::string error; 73 std::vector<InstallWarning> warnings; 74 EXPECT_TRUE(manifest->ValidateManifest(&error, &warnings)); 75 EXPECT_TRUE(error.empty()); 76 ASSERT_EQ(1u, warnings.size()); 77 AssertType(manifest.get(), Manifest::TYPE_EXTENSION); 78 79 // The known key 'background_page' should be accessible. 80 std::string value; 81 EXPECT_TRUE(manifest->GetString(keys::kBackgroundPageLegacy, &value)); 82 EXPECT_EQ("bg.html", value); 83 84 // The unknown key 'unknown_key' should be accesible. 85 value.clear(); 86 EXPECT_TRUE(manifest->GetString("unknown_key", &value)); 87 EXPECT_EQ("foo", value); 88 89 // Set the manifest_version to 2; background_page should stop working. 90 value.clear(); 91 MutateManifest( 92 &manifest, keys::kManifestVersion, new base::FundamentalValue(2)); 93 EXPECT_FALSE(manifest->GetString("background_page", &value)); 94 EXPECT_EQ("", value); 95 96 // Validate should also give a warning. 97 warnings.clear(); 98 EXPECT_TRUE(manifest->ValidateManifest(&error, &warnings)); 99 EXPECT_TRUE(error.empty()); 100 ASSERT_EQ(2u, warnings.size()); 101 { 102 SimpleFeature feature; 103 feature.set_name("background_page"); 104 feature.set_max_manifest_version(1); 105 EXPECT_EQ( 106 "'background_page' requires manifest version of 1 or lower.", 107 warnings[0].message); 108 } 109 110 // Test DeepCopy and Equals. 111 scoped_ptr<Manifest> manifest2(manifest->DeepCopy()); 112 EXPECT_TRUE(manifest->Equals(manifest2.get())); 113 EXPECT_TRUE(manifest2->Equals(manifest.get())); 114 MutateManifest( 115 &manifest, "foo", new base::StringValue("blah")); 116 EXPECT_FALSE(manifest->Equals(manifest2.get())); 117 } 118 119 // Verifies that key restriction based on type works. 120 TEST_F(ManifestTest, ExtensionTypes) { 121 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); 122 value->SetString(keys::kName, "extension"); 123 value->SetString(keys::kVersion, "1"); 124 125 scoped_ptr<Manifest> manifest( 126 new Manifest(Manifest::INTERNAL, value.Pass())); 127 std::string error; 128 std::vector<InstallWarning> warnings; 129 EXPECT_TRUE(manifest->ValidateManifest(&error, &warnings)); 130 EXPECT_TRUE(error.empty()); 131 EXPECT_TRUE(warnings.empty()); 132 133 // By default, the type is Extension. 134 AssertType(manifest.get(), Manifest::TYPE_EXTENSION); 135 136 // Theme. 137 MutateManifest( 138 &manifest, keys::kTheme, new base::DictionaryValue()); 139 AssertType(manifest.get(), Manifest::TYPE_THEME); 140 MutateManifest( 141 &manifest, keys::kTheme, NULL); 142 143 // Shared module. 144 MutateManifest( 145 &manifest, keys::kExport, new base::DictionaryValue()); 146 AssertType(manifest.get(), Manifest::TYPE_SHARED_MODULE); 147 MutateManifest( 148 &manifest, keys::kExport, NULL); 149 150 // Packaged app. 151 MutateManifest( 152 &manifest, keys::kApp, new base::DictionaryValue()); 153 AssertType(manifest.get(), Manifest::TYPE_LEGACY_PACKAGED_APP); 154 155 // Platform app. 156 MutateManifest( 157 &manifest, keys::kPlatformAppBackground, new base::DictionaryValue()); 158 AssertType(manifest.get(), Manifest::TYPE_PLATFORM_APP); 159 MutateManifest( 160 &manifest, keys::kPlatformAppBackground, NULL); 161 162 // Hosted app. 163 MutateManifest( 164 &manifest, keys::kWebURLs, new base::ListValue()); 165 AssertType(manifest.get(), Manifest::TYPE_HOSTED_APP); 166 MutateManifest( 167 &manifest, keys::kWebURLs, NULL); 168 MutateManifest( 169 &manifest, keys::kLaunchWebURL, new base::StringValue("foo")); 170 AssertType(manifest.get(), Manifest::TYPE_HOSTED_APP); 171 MutateManifest( 172 &manifest, keys::kLaunchWebURL, NULL); 173 }; 174 175 // Verifies that the getters filter restricted keys. 176 TEST_F(ManifestTest, RestrictedKeys) { 177 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); 178 value->SetString(keys::kName, "extension"); 179 value->SetString(keys::kVersion, "1"); 180 181 scoped_ptr<Manifest> manifest( 182 new Manifest(Manifest::INTERNAL, value.Pass())); 183 std::string error; 184 std::vector<InstallWarning> warnings; 185 EXPECT_TRUE(manifest->ValidateManifest(&error, &warnings)); 186 EXPECT_TRUE(error.empty()); 187 EXPECT_TRUE(warnings.empty()); 188 189 // "Commands" requires manifest version 2. 190 const base::Value* output = NULL; 191 MutateManifest( 192 &manifest, keys::kCommands, new base::DictionaryValue()); 193 EXPECT_FALSE(manifest->HasKey(keys::kCommands)); 194 EXPECT_FALSE(manifest->Get(keys::kCommands, &output)); 195 196 MutateManifest( 197 &manifest, keys::kManifestVersion, new base::FundamentalValue(2)); 198 EXPECT_TRUE(manifest->HasKey(keys::kCommands)); 199 EXPECT_TRUE(manifest->Get(keys::kCommands, &output)); 200 201 MutateManifest( 202 &manifest, keys::kPageAction, new base::DictionaryValue()); 203 AssertType(manifest.get(), Manifest::TYPE_EXTENSION); 204 EXPECT_TRUE(manifest->HasKey(keys::kPageAction)); 205 EXPECT_TRUE(manifest->Get(keys::kPageAction, &output)); 206 207 // Platform apps cannot have a "page_action" key. 208 MutateManifest( 209 &manifest, keys::kPlatformAppBackground, new base::DictionaryValue()); 210 AssertType(manifest.get(), Manifest::TYPE_PLATFORM_APP); 211 EXPECT_FALSE(manifest->HasKey(keys::kPageAction)); 212 EXPECT_FALSE(manifest->Get(keys::kPageAction, &output)); 213 MutateManifest( 214 &manifest, keys::kPlatformAppBackground, NULL); 215 216 // Platform apps also can't have a "Commands" key. 217 EXPECT_FALSE(manifest->HasKey(keys::kCommands)); 218 EXPECT_FALSE(manifest->Get(keys::kCommands, &output)); 219 }; 220 221 } // namespace extensions 222