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 5if (!chrome.cookies) { 6 chrome.cookies = chrome.experimental.cookies; 7} 8 9// A simple Timer class. 10function Timer() { 11 this.start_ = new Date(); 12 13 this.elapsed = function() { 14 return (new Date()) - this.start_; 15 } 16 17 this.reset = function() { 18 this.start_ = new Date(); 19 } 20} 21 22// Compares cookies for "key" (name, domain, etc.) equality, but not "value" 23// equality. 24function cookieMatch(c1, c2) { 25 return (c1.name == c2.name) && (c1.domain == c2.domain) && 26 (c1.hostOnly == c2.hostOnly) && (c1.path == c2.path) && 27 (c1.secure == c2.secure) && (c1.httpOnly == c2.httpOnly) && 28 (c1.session == c2.session) && (c1.storeId == c2.storeId); 29} 30 31// Returns an array of sorted keys from an associative array. 32function sortedKeys(array) { 33 var keys = []; 34 for (var i in array) { 35 keys.push(i); 36 } 37 keys.sort(); 38 return keys; 39} 40 41// Shorthand for document.querySelector. 42function select(selector) { 43 return document.querySelector(selector); 44} 45 46// An object used for caching data about the browser's cookies, which we update 47// as notifications come in. 48function CookieCache() { 49 this.cookies_ = {}; 50 51 this.reset = function() { 52 this.cookies_ = {}; 53 } 54 55 this.add = function(cookie) { 56 var domain = cookie.domain; 57 if (!this.cookies_[domain]) { 58 this.cookies_[domain] = []; 59 } 60 this.cookies_[domain].push(cookie); 61 }; 62 63 this.remove = function(cookie) { 64 var domain = cookie.domain; 65 if (this.cookies_[domain]) { 66 var i = 0; 67 while (i < this.cookies_[domain].length) { 68 if (cookieMatch(this.cookies_[domain][i], cookie)) { 69 this.cookies_[domain].splice(i, 1); 70 } else { 71 i++; 72 } 73 } 74 if (this.cookies_[domain].length == 0) { 75 delete this.cookies_[domain]; 76 } 77 } 78 }; 79 80 // Returns a sorted list of cookie domains that match |filter|. If |filter| is 81 // null, returns all domains. 82 this.getDomains = function(filter) { 83 var result = []; 84 sortedKeys(this.cookies_).forEach(function(domain) { 85 if (!filter || domain.indexOf(filter) != -1) { 86 result.push(domain); 87 } 88 }); 89 return result; 90 } 91 92 this.getCookies = function(domain) { 93 return this.cookies_[domain]; 94 }; 95} 96 97 98var cache = new CookieCache(); 99 100 101function removeAllForFilter() { 102 var filter = select("#filter").value; 103 var timer = new Timer(); 104 cache.getDomains(filter).forEach(function(domain) { 105 removeCookiesForDomain(domain); 106 }); 107} 108 109function removeAll() { 110 var all_cookies = []; 111 cache.getDomains().forEach(function(domain) { 112 cache.getCookies(domain).forEach(function(cookie) { 113 all_cookies.push(cookie); 114 }); 115 }); 116 cache.reset(); 117 var count = all_cookies.length; 118 var timer = new Timer(); 119 for (var i = 0; i < count; i++) { 120 removeCookie(all_cookies[i]); 121 } 122 timer.reset(); 123 chrome.cookies.getAll({}, function(cookies) { 124 for (var i in cookies) { 125 cache.add(cookies[i]); 126 removeCookie(cookies[i]); 127 } 128 }); 129} 130 131function removeCookie(cookie) { 132 var url = "http" + (cookie.secure ? "s" : "") + "://" + cookie.domain + 133 cookie.path; 134 chrome.cookies.remove({"url": url, "name": cookie.name}); 135} 136 137function removeCookiesForDomain(domain) { 138 var timer = new Timer(); 139 cache.getCookies(domain).forEach(function(cookie) { 140 removeCookie(cookie); 141 }); 142} 143 144function resetTable() { 145 var table = select("#cookies"); 146 while (table.rows.length > 1) { 147 table.deleteRow(table.rows.length - 1); 148 } 149} 150 151var reload_scheduled = false; 152 153function scheduleReloadCookieTable() { 154 if (!reload_scheduled) { 155 reload_scheduled = true; 156 setTimeout(reloadCookieTable, 250); 157 } 158} 159 160function reloadCookieTable() { 161 reload_scheduled = false; 162 163 var filter = select("#filter").value; 164 165 var domains = cache.getDomains(filter); 166 167 select("#filter_count").innerText = domains.length; 168 select("#total_count").innerText = cache.getDomains().length; 169 170 select("#delete_all_button").innerHTML = ""; 171 if (domains.length) { 172 var button = document.createElement("button"); 173 button.onclick = removeAllForFilter; 174 button.innerText = "delete all " + domains.length; 175 select("#delete_all_button").appendChild(button); 176 } 177 178 resetTable(); 179 var table = select("#cookies"); 180 181 domains.forEach(function(domain) { 182 var cookies = cache.getCookies(domain); 183 var row = table.insertRow(-1); 184 row.insertCell(-1).innerText = domain; 185 var cell = row.insertCell(-1); 186 cell.innerText = cookies.length; 187 cell.setAttribute("class", "cookie_count"); 188 189 var button = document.createElement("button"); 190 button.innerText = "delete"; 191 button.onclick = (function(dom){ 192 return function() { 193 removeCookiesForDomain(dom); 194 }; 195 }(domain)); 196 var cell = row.insertCell(-1); 197 cell.appendChild(button); 198 cell.setAttribute("class", "button"); 199 }); 200} 201 202function focusFilter() { 203 select("#filter").focus(); 204} 205 206function resetFilter() { 207 var filter = select("#filter"); 208 filter.focus(); 209 if (filter.value.length > 0) { 210 filter.value = ""; 211 reloadCookieTable(); 212 } 213} 214 215var ESCAPE_KEY = 27; 216window.onkeydown = function(event) { 217 if (event.keyCode == ESCAPE_KEY) { 218 resetFilter(); 219 } 220} 221 222function listener(info) { 223 cache.remove(info.cookie); 224 if (!info.removed) { 225 cache.add(info.cookie); 226 } 227 scheduleReloadCookieTable(); 228} 229 230function startListening() { 231 chrome.cookies.onChanged.addListener(listener); 232} 233 234function stopListening() { 235 chrome.cookies.onChanged.removeListener(listener); 236} 237 238function onload() { 239 focusFilter(); 240 var timer = new Timer(); 241 chrome.cookies.getAll({}, function(cookies) { 242 startListening(); 243 start = new Date(); 244 for (var i in cookies) { 245 cache.add(cookies[i]); 246 } 247 timer.reset(); 248 reloadCookieTable(); 249 }); 250} 251 252document.addEventListener('DOMContentLoaded', function() { 253 onload(); 254 document.body.addEventListener('click', focusFilter); 255 document.querySelector('#remove_button').addEventListener('click', removeAll); 256 document.querySelector('#filter_div input').addEventListener( 257 'input', reloadCookieTable); 258 document.querySelector('#filter_div button').addEventListener( 259 'click', resetFilter); 260}); 261