/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- * vim: sw=2 ts=2 sts=2 * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** * Test added with bug 460086 to test the behavior of the new API that was added * to remove all traces of visiting a site. */ // Globals Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/PlacesUtils.jsm"); Cu.import("resource://gre/modules/ForgetAboutSite.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils", "resource://testing-common/PlacesTestUtils.jsm"); const COOKIE_EXPIRY = Math.round(Date.now() / 1000) + 60; const COOKIE_NAME = "testcookie"; const COOKIE_PATH = "/"; const LOGIN_USERNAME = "username"; const LOGIN_PASSWORD = "password"; const LOGIN_USERNAME_FIELD = "username_field"; const LOGIN_PASSWORD_FIELD = "password_field"; const PERMISSION_TYPE = "test-perm"; const PERMISSION_VALUE = Ci.nsIPermissionManager.ALLOW_ACTION; const PREFERENCE_NAME = "test-pref"; // Utility Functions /** * Creates an nsIURI object for the given string representation of a URI. * * @param aURIString * The spec of the URI to create. * @returns an nsIURI representing aURIString. */ function uri(aURIString) { return Cc["@mozilla.org/network/io-service;1"]. getService(Ci.nsIIOService). newURI(aURIString, null, null); } /** * Asynchronously check a url is visited. * * @param aURI * The URI. * * @return {Promise} * @resolves When the check has been added successfully. * @rejects JavaScript exception. */ function promiseIsURIVisited(aURI) { let deferred = Promise.defer(); PlacesUtils.asyncHistory.isURIVisited(aURI, function(unused, aIsVisited) { deferred.resolve(aIsVisited); }); return deferred.promise; } /** * Add a cookie to the cookie service. * * @param aDomain */ function add_cookie(aDomain) { check_cookie_exists(aDomain, false); let cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2); cm.add(aDomain, COOKIE_PATH, COOKIE_NAME, "", false, false, false, COOKIE_EXPIRY, {}); check_cookie_exists(aDomain, true); } /** * Checks to ensure that a cookie exists or not for a domain. * * @param aDomain * The domain to check for the cookie. * @param aExists * True if the cookie should exist, false otherwise. */ function check_cookie_exists(aDomain, aExists) { let cm = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2); let cookie = { host: aDomain, name: COOKIE_NAME, path: COOKIE_PATH } let checker = aExists ? do_check_true : do_check_false; checker(cm.cookieExists(cookie)); } /** * Adds a disabled host to the login manager. * * @param aHost * The host to add to the list of disabled hosts. */ function add_disabled_host(aHost) { check_disabled_host(aHost, false); let lm = Cc["@mozilla.org/login-manager;1"]. getService(Ci.nsILoginManager); lm.setLoginSavingEnabled(aHost, false); check_disabled_host(aHost, true); } /** * Checks to see if a host is disabled for storing logins or not. * * @param aHost * The host to check if it is disabled. * @param aIsDisabled * True if the host should be disabled, false otherwise. */ function check_disabled_host(aHost, aIsDisabled) { let lm = Cc["@mozilla.org/login-manager;1"]. getService(Ci.nsILoginManager); let checker = aIsDisabled ? do_check_false : do_check_true; checker(lm.getLoginSavingEnabled(aHost)); } /** * Adds a login for the specified host to the login manager. * * @param aHost * The host to add the login for. */ function add_login(aHost) { check_login_exists(aHost, false); let login = Cc["@mozilla.org/login-manager/loginInfo;1"]. createInstance(Ci.nsILoginInfo); login.init(aHost, "", null, LOGIN_USERNAME, LOGIN_PASSWORD, LOGIN_USERNAME_FIELD, LOGIN_PASSWORD_FIELD); let lm = Cc["@mozilla.org/login-manager;1"]. getService(Ci.nsILoginManager); lm.addLogin(login); check_login_exists(aHost, true); } /** * Checks to see if a login exists for a host. * * @param aHost * The host to check for the test login. * @param aExists * True if the login should exist, false otherwise. */ function check_login_exists(aHost, aExists) { let lm = Cc["@mozilla.org/login-manager;1"]. getService(Ci.nsILoginManager); let count = { value: 0 }; lm.findLogins(count, aHost, "", null); do_check_eq(count.value, aExists ? 1 : 0); } /** * Adds a permission for the specified URI to the permission manager. * * @param aURI * The URI to add the test permission for. */ function add_permission(aURI) { check_permission_exists(aURI, false); let pm = Cc["@mozilla.org/permissionmanager;1"]. getService(Ci.nsIPermissionManager); let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] .getService(Ci.nsIScriptSecurityManager); let principal = ssm.createCodebasePrincipal(aURI, {}); pm.addFromPrincipal(principal, PERMISSION_TYPE, PERMISSION_VALUE); check_permission_exists(aURI, true); } /** * Checks to see if a permission exists for the given URI. * * @param aURI * The URI to check if a permission exists. * @param aExists * True if the permission should exist, false otherwise. */ function check_permission_exists(aURI, aExists) { let pm = Cc["@mozilla.org/permissionmanager;1"]. getService(Ci.nsIPermissionManager); let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] .getService(Ci.nsIScriptSecurityManager); let principal = ssm.createCodebasePrincipal(aURI, {}); let perm = pm.testExactPermissionFromPrincipal(principal, PERMISSION_TYPE); let checker = aExists ? do_check_eq : do_check_neq; checker(perm, PERMISSION_VALUE); } /** * Adds a content preference for the specified URI. * * @param aURI * The URI to add a preference for. */ function add_preference(aURI) { let deferred = Promise.defer(); let cp = Cc["@mozilla.org/content-pref/service;1"]. getService(Ci.nsIContentPrefService2); cp.set(aURI.spec, PREFERENCE_NAME, "foo", null, { handleCompletion: () => deferred.resolve() }); return deferred.promise; } /** * Checks to see if a content preference exists for the given URI. * * @param aURI * The URI to check if a preference exists. */ function preference_exists(aURI) { let deferred = Promise.defer(); let cp = Cc["@mozilla.org/content-pref/service;1"]. getService(Ci.nsIContentPrefService2); let exists = false; cp.getByDomainAndName(aURI.spec, PREFERENCE_NAME, null, { handleResult: () => exists = true, handleCompletion: () => deferred.resolve(exists) }); return deferred.promise; } // Test Functions // History function* test_history_cleared_with_direct_match() { const TEST_URI = uri("http://mozilla.org/foo"); do_check_false(yield promiseIsURIVisited(TEST_URI)); yield PlacesTestUtils.addVisits(TEST_URI); do_check_true(yield promiseIsURIVisited(TEST_URI)); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); do_check_false(yield promiseIsURIVisited(TEST_URI)); } function* test_history_cleared_with_subdomain() { const TEST_URI = uri("http://www.mozilla.org/foo"); do_check_false(yield promiseIsURIVisited(TEST_URI)); yield PlacesTestUtils.addVisits(TEST_URI); do_check_true(yield promiseIsURIVisited(TEST_URI)); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); do_check_false(yield promiseIsURIVisited(TEST_URI)); } function* test_history_not_cleared_with_uri_contains_domain() { const TEST_URI = uri("http://ilovemozilla.org/foo"); do_check_false(yield promiseIsURIVisited(TEST_URI)); yield PlacesTestUtils.addVisits(TEST_URI); do_check_true(yield promiseIsURIVisited(TEST_URI)); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); do_check_true(yield promiseIsURIVisited(TEST_URI)); // Clear history since we left something there from this test. yield PlacesTestUtils.clearHistory(); } // Cookie Service function* test_cookie_cleared_with_direct_match() { const TEST_DOMAIN = "mozilla.org"; add_cookie(TEST_DOMAIN); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_cookie_exists(TEST_DOMAIN, false); } function* test_cookie_cleared_with_subdomain() { const TEST_DOMAIN = "www.mozilla.org"; add_cookie(TEST_DOMAIN); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_cookie_exists(TEST_DOMAIN, false); } function* test_cookie_not_cleared_with_uri_contains_domain() { const TEST_DOMAIN = "ilovemozilla.org"; add_cookie(TEST_DOMAIN); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_cookie_exists(TEST_DOMAIN, true); } // Login Manager function* test_login_manager_disabled_hosts_cleared_with_direct_match() { const TEST_HOST = "http://mozilla.org"; add_disabled_host(TEST_HOST); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_disabled_host(TEST_HOST, false); } function* test_login_manager_disabled_hosts_cleared_with_subdomain() { const TEST_HOST = "http://www.mozilla.org"; add_disabled_host(TEST_HOST); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_disabled_host(TEST_HOST, false); } function* test_login_manager_disabled_hosts_not_cleared_with_uri_contains_domain() { const TEST_HOST = "http://ilovemozilla.org"; add_disabled_host(TEST_HOST); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_disabled_host(TEST_HOST, true); // Reset state let lm = Cc["@mozilla.org/login-manager;1"]. getService(Ci.nsILoginManager); lm.setLoginSavingEnabled(TEST_HOST, true); check_disabled_host(TEST_HOST, false); } function* test_login_manager_logins_cleared_with_direct_match() { const TEST_HOST = "http://mozilla.org"; add_login(TEST_HOST); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_login_exists(TEST_HOST, false); } function* test_login_manager_logins_cleared_with_subdomain() { const TEST_HOST = "http://www.mozilla.org"; add_login(TEST_HOST); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_login_exists(TEST_HOST, false); } function* test_login_manager_logins_not_cleared_with_uri_contains_domain() { const TEST_HOST = "http://ilovemozilla.org"; add_login(TEST_HOST); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_login_exists(TEST_HOST, true); let lm = Cc["@mozilla.org/login-manager;1"]. getService(Ci.nsILoginManager); lm.removeAllLogins(); check_login_exists(TEST_HOST, false); } // Permission Manager function* test_permission_manager_cleared_with_direct_match() { const TEST_URI = uri("http://mozilla.org"); add_permission(TEST_URI); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_permission_exists(TEST_URI, false); } function* test_permission_manager_cleared_with_subdomain() { const TEST_URI = uri("http://www.mozilla.org"); add_permission(TEST_URI); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_permission_exists(TEST_URI, false); } function* test_permission_manager_not_cleared_with_uri_contains_domain() { const TEST_URI = uri("http://ilovemozilla.org"); add_permission(TEST_URI); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); check_permission_exists(TEST_URI, true); // Reset state let pm = Cc["@mozilla.org/permissionmanager;1"]. getService(Ci.nsIPermissionManager); pm.removeAll(); check_permission_exists(TEST_URI, false); } function waitForPurgeNotification() { let deferred = Promise.defer(); let observer = { observe: function(aSubject, aTopic, aData) { Services.obs.removeObserver(observer, "browser:purge-domain-data"); // test_storage_cleared needs this extra executeSoon because // the DOMStorage clean-up is also listening to this same observer // which is run synchronously. Services.tm.mainThread.dispatch(function() { deferred.resolve(); }, Components.interfaces.nsIThread.DISPATCH_NORMAL); } }; Services.obs.addObserver(observer, "browser:purge-domain-data", false); return deferred.promise; } // Content Preferences function* test_content_preferences_cleared_with_direct_match() { const TEST_URI = uri("http://mozilla.org"); do_check_false(yield preference_exists(TEST_URI)); yield add_preference(TEST_URI); do_check_true(yield preference_exists(TEST_URI)); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); yield waitForPurgeNotification(); do_check_false(yield preference_exists(TEST_URI)); } function* test_content_preferences_cleared_with_subdomain() { const TEST_URI = uri("http://www.mozilla.org"); do_check_false(yield preference_exists(TEST_URI)); yield add_preference(TEST_URI); do_check_true(yield preference_exists(TEST_URI)); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); yield waitForPurgeNotification(); do_check_false(yield preference_exists(TEST_URI)); } function* test_content_preferences_not_cleared_with_uri_contains_domain() { const TEST_URI = uri("http://ilovemozilla.org"); do_check_false(yield preference_exists(TEST_URI)); yield add_preference(TEST_URI); do_check_true(yield preference_exists(TEST_URI)); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); yield waitForPurgeNotification(); do_check_true(yield preference_exists(TEST_URI)); // Reset state yield ForgetAboutSite.removeDataFromDomain("ilovemozilla.org"); yield waitForPurgeNotification(); do_check_false(yield preference_exists(TEST_URI)); } function push_registration_exists(aURL, ps) { return new Promise(resolve => { let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] .getService(Ci.nsIScriptSecurityManager); let principal = ssm.createCodebasePrincipalFromOrigin(aURL); return ps.getSubscription(aURL, principal, (status, record) => { if (!Components.isSuccessCode(status)) { resolve(false); } else { resolve(!!record); } }); }); } // Push function* test_push_cleared() { let ps; try { ps = Cc["@mozilla.org/push/Service;1"]. getService(Ci.nsIPushService); } catch (e) { // No push service, skip test. return; } do_get_profile(); setPrefs(); const {PushDB, PushService, PushServiceWebSocket} = serviceExports; const userAgentID = 'bd744428-f125-436a-b6d0-dd0c9845837f'; const channelID = '0ef2ad4a-6c49-41ad-af6e-95d2425276bf'; let db = PushServiceWebSocket.newPushDB(); try { PushService.init({ serverURI: "wss://push.example.org/", db, makeWebSocket(uriObj) { return new MockWebSocket(uriObj, { onHello(request) { this.serverSendMsg(JSON.stringify({ messageType: 'hello', status: 200, uaid: userAgentID, })); }, }); } }); const TEST_URL = "https://www.mozilla.org/scope/"; do_check_false(yield push_registration_exists(TEST_URL, ps)); yield db.put({ channelID, pushEndpoint: 'https://example.org/update/clear-success', scope: TEST_URL, version: 1, originAttributes: '', quota: Infinity, }); do_check_true(yield push_registration_exists(TEST_URL, ps)); let promisePurgeNotification = waitForPurgeNotification(); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); yield promisePurgeNotification; do_check_false(yield push_registration_exists(TEST_URL, ps)); } finally { yield PushService._shutdownService(); } } // Cache function* test_cache_cleared() { // Because this test is asynchronous, it should be the last test do_check_true(tests[tests.length - 1] == arguments.callee); // NOTE: We could be more extensive with this test and actually add an entry // to the cache, and then make sure it is gone. However, we trust that // the API is well tested, and that when we get the observer // notification, we have actually cleared the cache. // This seems to happen asynchronously... let os = Cc["@mozilla.org/observer-service;1"]. getService(Ci.nsIObserverService); let observer = { observe: function(aSubject, aTopic, aData) { os.removeObserver(observer, "cacheservice:empty-cache"); // Shutdown the download manager. Services.obs.notifyObservers(null, "quit-application", null); do_test_finished(); } }; os.addObserver(observer, "cacheservice:empty-cache", false); yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); do_test_pending(); } function* test_storage_cleared() { function getStorageForURI(aURI) { let ssm = Cc["@mozilla.org/scriptsecuritymanager;1"] .getService(Ci.nsIScriptSecurityManager); let principal = ssm.createCodebasePrincipal(aURI, {}); let dsm = Cc["@mozilla.org/dom/localStorage-manager;1"]. getService(Ci.nsIDOMStorageManager); return dsm.createStorage(null, principal, ""); } let s = [ getStorageForURI(uri("http://mozilla.org")), getStorageForURI(uri("http://my.mozilla.org")), getStorageForURI(uri("http://ilovemozilla.org")), ]; for (let i = 0; i < s.length; ++i) { let storage = s[i]; storage.setItem("test", "value" + i); do_check_eq(storage.length, 1); do_check_eq(storage.key(0), "test"); do_check_eq(storage.getItem("test"), "value" + i); } yield ForgetAboutSite.removeDataFromDomain("mozilla.org"); yield waitForPurgeNotification(); do_check_eq(s[0].getItem("test"), null); do_check_eq(s[0].length, 0); do_check_eq(s[1].getItem("test"), null); do_check_eq(s[1].length, 0); do_check_eq(s[2].getItem("test"), "value2"); do_check_eq(s[2].length, 1); } var tests = [ // History test_history_cleared_with_direct_match, test_history_cleared_with_subdomain, test_history_not_cleared_with_uri_contains_domain, // Cookie Service test_cookie_cleared_with_direct_match, test_cookie_cleared_with_subdomain, test_cookie_not_cleared_with_uri_contains_domain, // Login Manager test_login_manager_disabled_hosts_cleared_with_direct_match, test_login_manager_disabled_hosts_cleared_with_subdomain, test_login_manager_disabled_hosts_not_cleared_with_uri_contains_domain, test_login_manager_logins_cleared_with_direct_match, test_login_manager_logins_cleared_with_subdomain, test_login_manager_logins_not_cleared_with_uri_contains_domain, // Permission Manager test_permission_manager_cleared_with_direct_match, test_permission_manager_cleared_with_subdomain, test_permission_manager_not_cleared_with_uri_contains_domain, // Content Preferences test_content_preferences_cleared_with_direct_match, test_content_preferences_cleared_with_subdomain, test_content_preferences_not_cleared_with_uri_contains_domain, // Push test_push_cleared, // Storage test_storage_cleared, // Cache test_cache_cleared, ]; function run_test() { for (let i = 0; i < tests.length; i++) add_task(tests[i]); run_next_test(); }