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 "extensions/common/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 "extensions/common/error_utils.h" 15#include "extensions/common/features/feature.h" 16#include "extensions/common/features/simple_feature.h" 17#include "extensions/common/install_warning.h" 18#include "extensions/common/manifest_constants.h" 19#include "testing/gtest/include/gtest/gtest.h" 20 21namespace extensions { 22 23namespace errors = manifest_errors; 24namespace keys = manifest_keys; 25 26class 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. 62TEST_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. 120TEST_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 with event page. 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 // Platform app with service worker. 163 MutateManifest( 164 &manifest, keys::kPlatformAppServiceWorker, new base::DictionaryValue()); 165 AssertType(manifest.get(), Manifest::TYPE_PLATFORM_APP); 166 MutateManifest(&manifest, keys::kPlatformAppServiceWorker, NULL); 167 168 // Hosted app. 169 MutateManifest( 170 &manifest, keys::kWebURLs, new base::ListValue()); 171 AssertType(manifest.get(), Manifest::TYPE_HOSTED_APP); 172 MutateManifest( 173 &manifest, keys::kWebURLs, NULL); 174 MutateManifest( 175 &manifest, keys::kLaunchWebURL, new base::StringValue("foo")); 176 AssertType(manifest.get(), Manifest::TYPE_HOSTED_APP); 177 MutateManifest( 178 &manifest, keys::kLaunchWebURL, NULL); 179}; 180 181// Verifies that the getters filter restricted keys. 182TEST_F(ManifestTest, RestrictedKeys) { 183 scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); 184 value->SetString(keys::kName, "extension"); 185 value->SetString(keys::kVersion, "1"); 186 187 scoped_ptr<Manifest> manifest( 188 new Manifest(Manifest::INTERNAL, value.Pass())); 189 std::string error; 190 std::vector<InstallWarning> warnings; 191 EXPECT_TRUE(manifest->ValidateManifest(&error, &warnings)); 192 EXPECT_TRUE(error.empty()); 193 EXPECT_TRUE(warnings.empty()); 194 195 // "Commands" requires manifest version 2. 196 const base::Value* output = NULL; 197 MutateManifest( 198 &manifest, keys::kCommands, new base::DictionaryValue()); 199 EXPECT_FALSE(manifest->HasKey(keys::kCommands)); 200 EXPECT_FALSE(manifest->Get(keys::kCommands, &output)); 201 202 MutateManifest( 203 &manifest, keys::kManifestVersion, new base::FundamentalValue(2)); 204 EXPECT_TRUE(manifest->HasKey(keys::kCommands)); 205 EXPECT_TRUE(manifest->Get(keys::kCommands, &output)); 206 207 MutateManifest( 208 &manifest, keys::kPageAction, new base::DictionaryValue()); 209 AssertType(manifest.get(), Manifest::TYPE_EXTENSION); 210 EXPECT_TRUE(manifest->HasKey(keys::kPageAction)); 211 EXPECT_TRUE(manifest->Get(keys::kPageAction, &output)); 212 213 // Platform apps cannot have a "page_action" key. 214 MutateManifest( 215 &manifest, keys::kPlatformAppBackground, new base::DictionaryValue()); 216 AssertType(manifest.get(), Manifest::TYPE_PLATFORM_APP); 217 EXPECT_FALSE(manifest->HasKey(keys::kPageAction)); 218 EXPECT_FALSE(manifest->Get(keys::kPageAction, &output)); 219 MutateManifest( 220 &manifest, keys::kPlatformAppBackground, NULL); 221 222 // Platform apps also can't have a "Commands" key. 223 EXPECT_FALSE(manifest->HasKey(keys::kCommands)); 224 EXPECT_FALSE(manifest->Get(keys::kCommands, &output)); 225}; 226 227} // namespace extensions 228