Home | History | Annotate | Download | only in cookies
      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 if (!chrome.cookies) {
      6   chrome.cookies = chrome.experimental.cookies;
      7 }
      8 
      9 // A simple Timer class.
     10 function 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.
     24 function 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.
     32 function 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.
     42 function 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.
     48 function 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 
     98 var cache = new CookieCache();
     99 
    100 
    101 function 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 
    109 function 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 
    131 function 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 
    137 function removeCookiesForDomain(domain) {
    138   var timer = new Timer();
    139   cache.getCookies(domain).forEach(function(cookie) {
    140     removeCookie(cookie);
    141   });
    142 }
    143 
    144 function resetTable() {
    145   var table = select("#cookies");
    146   while (table.rows.length > 1) {
    147     table.deleteRow(table.rows.length - 1);
    148   }
    149 }
    150 
    151 var reload_scheduled = false;
    152 
    153 function scheduleReloadCookieTable() {
    154   if (!reload_scheduled) {
    155     reload_scheduled = true;
    156     setTimeout(reloadCookieTable, 250);
    157   }
    158 }
    159 
    160 function 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 
    202 function focusFilter() {
    203   select("#filter").focus();
    204 }
    205 
    206 function resetFilter() {
    207   var filter = select("#filter");
    208   filter.focus();
    209   if (filter.value.length > 0) {
    210     filter.value = "";
    211     reloadCookieTable();
    212   }
    213 }
    214 
    215 var ESCAPE_KEY = 27;
    216 window.onkeydown = function(event) {
    217   if (event.keyCode == ESCAPE_KEY) {
    218     resetFilter();
    219   }
    220 }
    221 
    222 function listener(info) {
    223   cache.remove(info.cookie);
    224   if (!info.removed) {
    225     cache.add(info.cookie);
    226   }
    227   scheduleReloadCookieTable();
    228 }
    229 
    230 function startListening() {
    231   chrome.cookies.onChanged.addListener(listener);
    232 }
    233 
    234 function stopListening() {
    235   chrome.cookies.onChanged.removeListener(listener);
    236 }
    237 
    238 function 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 
    252 document.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