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/files/file_path.h" 6 #include "base/json/json_file_value_serializer.h" 7 #include "base/memory/ref_counted.h" 8 #include "base/path_service.h" 9 #include "base/run_loop.h" 10 #include "base/values.h" 11 #include "chrome/browser/chrome_notification_types.h" 12 #include "chrome/browser/extensions/extension_service.h" 13 #include "chrome/browser/extensions/extension_service_unittest.h" 14 #include "chrome/browser/extensions/permissions_updater.h" 15 #include "chrome/common/chrome_paths.h" 16 #include "chrome/common/extensions/extension_test_util.h" 17 #include "chrome/test/base/testing_profile.h" 18 #include "content/public/browser/notification_observer.h" 19 #include "content/public/browser/notification_registrar.h" 20 #include "content/public/browser/notification_service.h" 21 #include "extensions/common/extension.h" 22 #include "extensions/common/permissions/permission_set.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 25 using extension_test_util::LoadManifest; 26 27 namespace extensions { 28 29 namespace { 30 31 // A helper class that listens for NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED. 32 class PermissionsUpdaterListener : public content::NotificationObserver { 33 public: 34 PermissionsUpdaterListener() 35 : received_notification_(false), waiting_(false) { 36 registrar_.Add(this, 37 chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED, 38 content::NotificationService::AllSources()); 39 } 40 41 void Reset() { 42 received_notification_ = false; 43 waiting_ = false; 44 extension_ = NULL; 45 permissions_ = NULL; 46 } 47 48 void Wait() { 49 if (received_notification_) 50 return; 51 52 waiting_ = true; 53 base::RunLoop run_loop; 54 run_loop.Run(); 55 } 56 57 bool received_notification() const { return received_notification_; } 58 const Extension* extension() const { return extension_.get(); } 59 const PermissionSet* permissions() const { return permissions_.get(); } 60 UpdatedExtensionPermissionsInfo::Reason reason() const { return reason_; } 61 62 private: 63 virtual void Observe(int type, 64 const content::NotificationSource& source, 65 const content::NotificationDetails& details) OVERRIDE { 66 received_notification_ = true; 67 UpdatedExtensionPermissionsInfo* info = 68 content::Details<UpdatedExtensionPermissionsInfo>(details).ptr(); 69 70 extension_ = info->extension; 71 permissions_ = info->permissions; 72 reason_ = info->reason; 73 74 if (waiting_) { 75 waiting_ = false; 76 base::MessageLoopForUI::current()->Quit(); 77 } 78 } 79 80 bool received_notification_; 81 bool waiting_; 82 content::NotificationRegistrar registrar_; 83 scoped_refptr<const Extension> extension_; 84 scoped_refptr<const PermissionSet> permissions_; 85 UpdatedExtensionPermissionsInfo::Reason reason_; 86 }; 87 88 class PermissionsUpdaterTest : public ExtensionServiceTestBase { 89 }; 90 91 scoped_refptr<Extension> LoadOurManifest() { 92 base::FilePath path; 93 path = path.AppendASCII("api_test") 94 .AppendASCII("permissions") 95 .AppendASCII("optional"); 96 return LoadManifest(path.AsUTF8Unsafe(), 97 "manifest.json", 98 Manifest::INTERNAL, 99 Extension::NO_FLAGS); 100 } 101 102 void AddPattern(URLPatternSet* extent, const std::string& pattern) { 103 int schemes = URLPattern::SCHEME_ALL; 104 extent->AddPattern(URLPattern(schemes, pattern)); 105 } 106 107 } // namespace 108 109 // Test that the PermissionUpdater can correctly add and remove active 110 // permissions. This tests all of PermissionsUpdater's public methods because 111 // GrantActivePermissions and UpdateActivePermissions are used by 112 // AddPermissions. 113 TEST_F(PermissionsUpdaterTest, AddAndRemovePermissions) { 114 InitializeEmptyExtensionService(); 115 116 // Load the test extension. 117 scoped_refptr<Extension> extension = LoadOurManifest(); 118 ASSERT_TRUE(extension.get()); 119 120 APIPermissionSet default_apis; 121 default_apis.insert(APIPermission::kManagement); 122 ManifestPermissionSet empty_manifest_permissions; 123 124 URLPatternSet default_hosts; 125 AddPattern(&default_hosts, "http://a.com/*"); 126 scoped_refptr<PermissionSet> default_permissions = 127 new PermissionSet(default_apis, empty_manifest_permissions, 128 default_hosts, URLPatternSet()); 129 130 // Make sure it loaded properly. 131 scoped_refptr<const PermissionSet> permissions = 132 extension->GetActivePermissions(); 133 ASSERT_EQ(*default_permissions.get(), 134 *extension->GetActivePermissions().get()); 135 136 // Add a few permissions. 137 APIPermissionSet apis; 138 apis.insert(APIPermission::kTab); 139 apis.insert(APIPermission::kNotification); 140 URLPatternSet hosts; 141 AddPattern(&hosts, "http://*.c.com/*"); 142 143 scoped_refptr<PermissionSet> delta = 144 new PermissionSet(apis, empty_manifest_permissions, 145 hosts, URLPatternSet()); 146 147 PermissionsUpdaterListener listener; 148 PermissionsUpdater updater(profile_.get()); 149 updater.AddPermissions(extension.get(), delta.get()); 150 151 listener.Wait(); 152 153 // Verify that the permission notification was sent correctly. 154 ASSERT_TRUE(listener.received_notification()); 155 ASSERT_EQ(extension, listener.extension()); 156 ASSERT_EQ(UpdatedExtensionPermissionsInfo::ADDED, listener.reason()); 157 ASSERT_EQ(*delta.get(), *listener.permissions()); 158 159 // Make sure the extension's active permissions reflect the change. 160 scoped_refptr<PermissionSet> active_permissions = 161 PermissionSet::CreateUnion(default_permissions.get(), delta.get()); 162 ASSERT_EQ(*active_permissions.get(), 163 *extension->GetActivePermissions().get()); 164 165 // Verify that the new granted and active permissions were also stored 166 // in the extension preferences. In this case, the granted permissions should 167 // be equal to the active permissions. 168 ExtensionPrefs* prefs = service_->extension_prefs(); 169 scoped_refptr<PermissionSet> granted_permissions = 170 active_permissions; 171 172 scoped_refptr<PermissionSet> from_prefs = 173 prefs->GetActivePermissions(extension->id()); 174 ASSERT_EQ(*active_permissions.get(), *from_prefs.get()); 175 176 from_prefs = prefs->GetGrantedPermissions(extension->id()); 177 ASSERT_EQ(*active_permissions.get(), *from_prefs.get()); 178 179 // In the second part of the test, we'll remove the permissions that we 180 // just added except for 'notification'. 181 apis.erase(APIPermission::kNotification); 182 delta = new PermissionSet(apis, empty_manifest_permissions, 183 hosts, URLPatternSet()); 184 185 listener.Reset(); 186 updater.RemovePermissions(extension.get(), delta.get()); 187 listener.Wait(); 188 189 // Verify that the notification was correct. 190 ASSERT_TRUE(listener.received_notification()); 191 ASSERT_EQ(extension, listener.extension()); 192 ASSERT_EQ(UpdatedExtensionPermissionsInfo::REMOVED, listener.reason()); 193 ASSERT_EQ(*delta.get(), *listener.permissions()); 194 195 // Make sure the extension's active permissions reflect the change. 196 active_permissions = 197 PermissionSet::CreateDifference(active_permissions.get(), delta.get()); 198 ASSERT_EQ(*active_permissions.get(), 199 *extension->GetActivePermissions().get()); 200 201 // Verify that the extension prefs hold the new active permissions and the 202 // same granted permissions. 203 from_prefs = prefs->GetActivePermissions(extension->id()); 204 ASSERT_EQ(*active_permissions.get(), *from_prefs.get()); 205 206 from_prefs = prefs->GetGrantedPermissions(extension->id()); 207 ASSERT_EQ(*granted_permissions.get(), *from_prefs.get()); 208 } 209 210 } // namespace extensions 211