Hack 37. Keep Track of Secure Site Passwords

 < Day Day Up > 

Generate random passwords for every site based on a master password.

Everyone has too many passwords to remember. Every site from Expedia to Amazon.com to Gmail to individual blogs and mailing lists has its own system. Some services such as Microsoft's Passport, Google's Blogger, and SixApart's TypeKey have tried to stem the tide by providing a cross-site login system. But even these are proliferating at an alarming rate. Most people eventually just give up and use one password everywhere. Some people use a "secure" password for sensitive sites like online banking and e-commerce sites, and an "insecure" password for mailing lists and blogs. All of these systems are doomed to failure.

What we really need is a personalized system of generating passwords locally and retrieving them on demand. Mac OS X has the Keychain application, but it works only on Mac OS X. Firefox has its Password Manager, but it doesn't store the passwords securely, and it works only on sites that allow the browser to remember passwords in the first place. (But see "Allow Password Remembering" [Hack #32] for a way around that.)

This hack defines a local master password that you can enter to generate a random password for each web site you visit. It never stores the master password on disk; you simply enter it whenever you need to log into a web site. So even if someone steals your laptop, she won't be able to access any of your stored passwords, because you haven't stored them anywhere.

4.10.1. The Code

This user script runs on all pages. The first half of the code is taken up with the MD5 hash algorithm, which the script uses to generate each password. The long mpwd_getHostname function is devoted to determining the portion of the current domain, minus the country-specific top-level domain name. This means that you can reuse the same site-specific password on http://www.amazon.com and http://www.amazon.co.uk.

The rest of the script checks for password fields on the current page and adds a Master password field to each form to allow you to enter your master password. If you enter it correctly, the script fills the original password field with your random site-specific password, or generates a new one and stores it locally.

Save the following user script as pwdcomposer.user.js:

    // ==UserScript==    // @name    Password Composer    // @namespace   http://joe.lapoutre.com/BoT/Javascript/    // @description  Generate site specific passwords based on a master password    // @include    *    // @version    1.08    // ==/UserScript==    // based on code by Johannes le Poutré and others    // and included here with their gracious permission    var clearText = false; // show generated passwds in cleartext    var topDomain = false; // use top domain instead of full host    function errLog(msg) {    if (typeof(GM_log == "function")) {    GM_log(msg);    } else {    window.status = msg;    }    }        function hex_md5(s) {    return binl2hex(core_md5(str2binl(s), s.length * 8));    }    function core_md5(x, len) {    x[len >> 5] |= 0x80 << ((len) % 32);    x[(((len + 64) >>>9) << 4) + 14] = len;    var a = 1732584193;    var b = -271733879;    var c = -1732584194;    var d = 271733878;    for (var i = 0; i < x.length; i += 16) {    var olda = a;    var oldb = b;    var oldc = c;    var oldd = d;    a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);    d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);    c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);    b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);    a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);    d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);    c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);    b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);    a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);    d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);    c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);    b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);    a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);    d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);    c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);    b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);    a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);    d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);    c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);    b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);    a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);    d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);    c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);    b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);    a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);    d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);    c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);    b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);    a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);    d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);    c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);    b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);    a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);    d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);    c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);    b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);    a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);    d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);    c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);    b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);    a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);    d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);    c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);    b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);    a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);    d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);    c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);    b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);    a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);    d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);    c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);    b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);    a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);    d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);    c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);    b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);    a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);    d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);    c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);    b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);    a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);    d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);    c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);    b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);    a = safe_add(a, olda);    b = safe_add(b, oldb);    c = safe_add(c, oldc);    d = safe_add(d, oldd); } return Array(a, b, c, d); }  function md5_cmn(q, a, b, x, s, t) { return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); } function md5_ff(a, b, c, d, x, s, t) { return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); } function md5_gg(a, b, c, d, x, s, t) { return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); } function md5_hh(a, b, c, d, x, s, t) { return md5_cmn(b ^ c ^ d, a, b, x, s, t); } function md5_ii(a, b, c, d, x, s, t) { return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); } function safe_add(x, y) { var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); } function bit_rol(num, cnt) { return (num << cnt) | (num >>>(32 - cnt)); } function str2binl(str) { var bin = Array(); var mask = (1 << 8) - 1; for (var i = 0; i < str.length * 8; i += 8) { bin[i >> 5] |= (str.charCodeAt(i / 8) & mask) << (i % 32); } return bin; } function binl2hex(binarray) { var hex_tab = '0123456789abcdef'; var str = ''; for (var i = 0; i < binarray.length * 4; i++) { str+=hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF)+ hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF); } return str; } function mpwd_getHostname() { var re = new RegExp('https*://([^/]+)'); var url = document.location.href.toLowerCase(); var host = url.match(re)[1]; // look at minimum domain instead of host // see http://labs.zarate.org/passwd/ if (topDomain) { host = host.split('.'); if (host[2] != null) { s = host[host.length-2] + '.' + host[host.length-1]; domains='ab.ca|ac.ac|ac.at|ac.be|ac.cn|ac.il|ac.in|ac.jp|'+ 'ac.kr|ac.nz|ac.th|ac.uk|ac.za|adm.br|adv.br|agro.pl|ah.cn|aid.pl|alt'+ '.za|am.br|arq.br|art.br|arts.ro|asn.au|asso.fr|asso.mc|atm.pl|auto.p'+ 'l|bbs.tr|bc.ca|bio.br|biz.pl|bj.cn|br.com|cn.com|cng.br|cnt.br|co.ac'+ '|co.at|co.il|co.in|co.jp|co.kr|co.nz|co.th|co.uk|co.za|com.au|com.br'+ '|com.cn|com.ec|com.fr|com.hk|com.mm|com.mx|com.pl|com.ro|com.ru|com.'+ 'sg|com.tr|com.tw|cq.cn|cri.nz|de.com|ecn.br|edu.au|edu.cn|edu.hk|edu'+ '.mm|edu.mx|edu.pl|edu.tr|edu.za|eng.br|ernet.in|esp.br|etc.br|eti.br'+ '|eu.com|eu.lv|fin.ec|firm.ro|fm.br|fot.br|fst.br|g12.br|gb.com|gb.ne'+ 't|gd.cn|gen.nz|gmina.pl|go.jp|go.kr|go.th|gob.mx|gov.br|gov.cn|gov.e'+ 'c|gov.il|gov.in|gov.mm|gov.mx|gov.sg|gov.tr|gov.za|govt.nz|gs.cn|gsm'+ '.pl|gv.ac|gv.at|gx.cn|gz.cn|hb.cn|he.cn|hi.cn|hk.cn|hl.cn|hn.cn|hu.c'+ 'om|idv.tw|ind.br|inf.br|info.pl|info.ro|iwi.nz|jl.cn|jor.br|jpn.com|'+ 'js.cn|k12.il|k12.tr|lel.br|ln.cn|ltd.uk|mail.pl|maori.nz|mb.ca|me.uk'+ '|med.br|med.ec|media.pl|mi.th|miasta.pl|mil.br|mil.ec|mil.nz|mil.pl|'+ 'mil.tr|mil.za|mo.cn|muni.il|nb.ca|ne.jp|ne.kr|net.au|net.br|net.cn|n'+ 'et.ec|net.hk|net.il|net.in|net.mm|net.mx|net.nz|net.pl|net.ru|net.sg'+ '|net.th|net.tr|net.tw|net.za|nf.ca|ngo.za|nm.cn|nm.kr|no.com|nom.br|'+ 'nom.pl|nom.ro|nom.za|ns.ca|nt.ca|nt.ro|ntr.br|nx.cn|odo.br|on.ca|or.'+ 'ac|or.at|or.jp|or.kr|or.th|org.au|org.br|org.cn|org.ec|org.hk|org.il'+ '|org.mm|org.mx|org.nz|org.pl|org.ro|org.ru|org.sg|org.tr|org.tw|org.'+ 'uk|org.za|pc.pl|pe.ca|plc.uk|ppg.br|presse.fr|priv.pl|pro.br|psc.br|'+ 'psi.br|qc.ca|qc.com|qh.cn|re.kr|realestate.pl|rec.br|rec.ro|rel.pl|r'+ 'es.in|ru.com|sa.com|sc.cn|school.nz|school.za|se.com|se.net|sh.cn|sh'+ 'op.pl|sk.ca|sklep.pl|slg.br|sn.cn|sos.pl|store.ro|targi.pl|tj.cn|tm.'+ 'fr|tm.mc|tm.pl|tm.ro|tm.za|tmp.br|tourism.pl|travel.pl|tur.br|turyst'+ 'yka.pl|tv.br|tw.cn|uk.co|uk.com|uk.net|us.com|uy.com|vet.br|web.za|w'+ 'eb.com|www.ro|xj.cn|xz.cn|yk.ca|yn.cn|za.com'; domains=domains.split('|'); for(var i=0; i<domains.length; i++) { if (s==domains[i]) { s=host[host.length-3]+'.'+s; break; } } } else { s = host.join('.'); } return s; } else { // no manipulation (full host name) return host; } } // generate the password and populate original form function mpwd_doIt() { if (!mpwd_check_password()) { return; } var master = document.getElementById('masterpwd').value; var domain = document.getElementById('mpwddomain').value.toLowerCase(); // remove panel before messing with passwd fields mpwd_remove(); if (master != '' && master != null) { var i=0, j=0, p=hex_md5(master+':'+domain).substr(0,8); var inputs = document.getElementsByTagName('input'); for(i=0;i<inputs.length;i++) { var inp = inputs[i]; if(inp.getAttribute('type') == 'password') { inp.value=p; if (clearText) { inp.type = 'text'; var cl = inp.getAttribute("class") || ""; // hack to mark passwd fields by setting class name // intentde to find them on a second pass, if // type is modified to text if (cl.indexOf("mpwdpasswd") == -1) { inp.setAttribute("class", cl + " mpwdpasswd"); } } // inp.focus(); } else if(inp.getAttribute('type') == 'text') { var nm = inp.getAttribute('name').toLowerCase(); var cl = inp.getAttribute("class") || ""; // field named something like passwd or class mpwdpasswd if (nm.indexOf('password')!=-1 || nm.indexOf('passwd')!=-1 || cl.indexOf("mpwdpasswd") != -1) { inp.value=p; if (! clearText) inp.type = 'password'; // inp.focus(); } } } // give focus to first password field getPwdFld().focus(); } }; // check for multiple passwd fields per form (e.g. 'verify passwd') function hasMultiplePwdFields() { // find any form that has 2+ password fields as children // note literal '>' char in xpath expression! var xpres = document.evaluate( "count(//form[count(//input[@type='password']) > 1])", document, null, XPathResult.ANY_TYPE, null); return(xpres.numberValue > 0); } // find first password field function getPwdFld() { var L = document.getElementsByTagName('input'); for (var i = 0; i < L.length; i++) { var nm, tp, cl; try { nm = L[i].getAttribute("name") || ""; } catch(e) { }; try { tp = L[i].getAttribute("type") || ""; } catch(e) { }; try { cl = L[i].getAttribute("class") || ""; } catch(e) { }; if ((tp == "password") || (tp == "text" && nm.toLowerCase().substring(0,5) == "passw") || (cl.indexOf("mpwdpasswd") > -1)) { return L[i]; } } return null; } function mpwd_remove() { var body = document.getElementsByTagName('body')[0]; body.removeChild(document.getElementById('mpwd_bgd')); body.removeChild(document.getElementById('mpwd_panel')); } function mpwd_keyup(e) { mpwd_check_password(); if (e.keyCode == 13 || e.keyCode == 10) { mpwd_doIt(); } else if (e.keyCode == 27) { mpwd_remove(); } } function mpwd_check_password() { var pwd = document.getElementById('masterpwd'); var pwd2 = document.getElementById('secondpwd'); if (!pwd2) return 1; if (pwd.value != pwd2.value && pwd2.value != '') { pwd2.style.background='#f77'; pwd2.style.borderColor='red'; return 0; } else { pwd2.style.background = 'white'; pwd2.style.borderColor='#777'; return 1; } } function mpwd_panel(event) { var pwdTop = 0; var pwdLeft = 0; if (document.getElementById('mpwd_panel')) { mpwd_remove(); return; } try { var obj = getPwdFld(); if (obj.offsetParent) { while (obj.offsetParent) { pwdTop += obj.offsetTop; pwdLeft += obj.offsetLeft; obj = obj.offsetParent; } } } catch (e) {   pwdTop = 10;   pwdLeft = 10; } // full document width and height as rendered in browser: var html = document.getElementsByTagName('html')[0]; var pag_w = parseInt(document.defaultView.getComputedStyle(html, '').getPropertyValue('width')); var pag_h = parseInt(document.defaultView.getComputedStyle(html, '').getPropertyValue('height')); var div = document.createElement('div'); div.style.color='#777'; div.style.padding='5px'; div.style.backgroundColor='white'; div.style.border='1px solid black'; div.style.borderBottom='3px solid black'; div.style.borderRight='2px solid black'; div.style.MozBorderRadius='10px'; div.style.fontSize='9pt'; div.style.fontFamily='sans-serif'; div.style.lineHeight='1.8em'; div.style.position='absolute'; div.style.width='230px'; // keep panel at least 10 px away from right page edge div.style.left = ((250 + pwdLeft > pag_w)? pag_w - 250 : pwdLeft) + 'px'; div.style.top = pwdTop + 'px'; div.style.zIndex = 9999; // make sure we're visible/on top div.setAttribute('id', 'mpwd_panel'); div.appendChild(document.createTextNode('Master password: ')); var icnShow = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAA'+ 'AAMCAIAAADZF8uwAAAAkUlEQVR4nGL4TwRgwCWxc%2BfOU6dOQRUZowKI6N%2B%2Ff93c'+ '3Ly8vBCKMI3Ztm1bZ2dnenr65cuXcSoKCwt7%2BPDh4cOHs7KysCt6%2Ffo1Pz%2B%2Fs'+ '7Ozk5MTkPH582csiiZMmDBlyhQIu6amZubMmVgUGRkZvXr1CsK%2Bffu2oaEhdjdBAFyK'+ 'aEV4AFQRLmOQAQAAAP%2F%2FAwB27VC%2BrCyA0QAAAABJRU5ErkJggg%3D%3D'; var icnHide = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAA'+ 'AAMAgMAAAArG7R0AAAADFBMVEX%2F%2F%2F%2FMzMxmZmYzMzM7z8wMAAAAJ0lEQVQImW'+ 'NgAIMEhv%2FH0hgOMEYwHGAD0kD%2BAaAoBBuA8f%2F%2FH0AKARI5DD%2FY1kZdAAAAA'+ 'ElFTkSuQmCC'; var show = document.createElement('img'); show.setAttribute('src', (clearText) ? icnShow : icnHide); show.setAttribute('id', "icnShow"); show.setAttribute('title', 'Show or hide generated password'); show.style.paddingRight = '4px'; show.style.display='inline'; // some stupid sites set this to block show.style.cursor = 'pointer'; show.addEventListener('click', function(event) { clearText = !clearText; document.getElementById("icnShow").setAttribute('src', (clearText) ? icnShow : icnHide); document.getElementById('masterpwd').focus(); }, true); div.appendChild(show); var pwd = document.createElement('input'); pwd.style.border='1px solid #777'; pwd.setAttribute('type','password'); pwd.setAttribute('id','masterpwd'); pwd.style.width = '100px'; pwd.style.fontSize='9pt'; pwd.style.color='#777'; // fire action if RETURN key is typed div.appendChild(pwd); div.appendChild(document.createElement('br')); if (hasMultiplePwdFields()) { // only of a 'verify field' is on original page div.appendChild(document.createTextNode('Check password: ')); var pwd2 = document.createElement('input'); pwd2.setAttribute('type','password'); pwd2.setAttribute('id','secondpwd'); pwd2.style.width = '100px'; pwd2.style.color='#777'; pwd2.style.border='1px solid #777'; pwd2.style.fontSize='9pt'; div.appendChild(pwd2); div.appendChild(document.createElement('br')); } div.appendChild(document.createTextNode('Domain: ')); var subicn = document.createElement('img'); subicn.setAttribute('src', 'data:image/png;base64,iVBORw0KGgoAAAAN'+   'SUhEUgAAAAkAAAAJCAAAAADF%2BlnMAAAAGUlEQVR42mNogQGGlv8QgIvFAAL%2FCaqDA'+   'QCbtDxVGHcjrgAAAABJRU5ErkJggg%3D%3D'); subicn.setAttribute('id', "icnSubdom"); subicn.setAttribute('title', 'Toggle use sub domain'); subicn.style.display='inline'; subicn.style.paddingRight = '4px'; subicn.style.cursor = 'pointer'; subicn.addEventListener('click', function(event) { toggleSubdomain(); document.getElementById('masterpwd').focus(); }, true); div.appendChild(subicn); var domn = document.createElement('input'); domn.setAttribute('type','text'); domn.setAttribute('value', mpwd_getHostname()); domn.setAttribute('id','mpwddomain'); domn.setAttribute('title','Edit domain name for different password'); domn.style.width = '150px'; domn.style.border = 'none'; domn.style.fontSize='9pt'; domn.style.color='#777'; div.appendChild(domn); div.addEventListener('keyup', mpwd_keyup, true); var bgd = document.createElement('div'); bgd.setAttribute('id','mpwd_bgd'); bgd.style.position='absolute'; bgd.style.top='0px'; bgd.style.left='0px'; bgd.style.backgroundColor='black'; bgd.style.opacity='0.35'; bgd.style.height = pag_h + 'px'; bgd.style.width = pag_w + 'px'; bgd.style.zIndex='9998'; bgd.addEventListener('click', mpwd_remove, true); var body = document.getElementsByTagName('body')[0]; body.appendChild(bgd); body.appendChild(div); setTimeout("document.getElementById('masterpwd').focus();", 333); initSubdomainSetting(); }; // Setting: use sub domain function initSubdomainSetting() { if (typeof(GM_getValue) == 'function') { topDomain = GM_getValue('topDomain', false); } updateSubDomainSetting(); } function toggleSubdomain() { topDomain = !topDomain; if (typeof(GM_setValue) == 'function') { GM_setValue('topDomain', topDomain); } updateSubDomainSetting(); } function updateSubDomainSetting() { var icnPlus = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAA'+ 'AAJCAAAAADF%2BlnMAAAAHUlEQVR42mNogQGGlv8QAGExYLAYQACnLFwvDAAA6Fk4WdfT'+ '%2FgAAAAAASUVORK5CYII%3D'; var icnMin = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAA'+ 'AJCAAAAADF%2BlnMAAAAGUlEQVR42mNogQGGlv8QgIvFAAL%2FCaqDAQCbtDxVGHcjrgA'+ 'AAABJRU5ErkJggg%3D%3D';  document.getElementById("icnSubdom").setAttribute('src', (topDomain) ? icnMin : icnPlus); document.getElementById("mpwddomain").setAttribute('value',  mpwd_getHostname()); } function mpwd_launcher() { // image 12px var bullet = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAA'+ 'AMCAYAAABWdVznAAAAX0lEQVR4nGL4%2F%2F8%2FAykYwkhL%2B08IR0VFIWkAUn%2F%2'+ 'B%2FMGJoRqysGoASRKtAWw9SOjMGRTN%2BG0AKgYLQzUT1AC3iVgNcGdBMVE2EOVpQhhV'+ 'AxCDBAhhFA3EYgAAAAD%2F%2FwMAKhyYBtU1wpoAAAAASUVORK5CYII%3D'; var pwdTop = 0; var pwdLft = 0; var obj; try { obj = getPwdFld(); if (obj.offsetParent) { while (obj.offsetParent) { pwdTop += obj.offsetTop; pwdLft += obj.offsetLeft; obj = obj.offsetParent; } } } catch (e) {     pwdTop = 10; pwdLft = 10; } // return if no passwd field is found if (! obj) return; var bull = document.createElement('img'); bull.style.position='absolute'; bull.style.top = pwdTop + 'px'; bull.style.left = (pwdLft - 12) + 'px'; bull.setAttribute('src', bullet); bull.setAttribute('title', 'Open Password Composer'); bull.style.cursor = 'pointer'; bull.addEventListener('click', mpwd_panel, true); bull.style.zIndex = 9999; document.getElementsByTagName('body')[0].appendChild(bull); } mpwd_launcher(); // add menu command to manually launch passwd composer if (typeof(GM_registerMenuCommand == 'function')) { GM_registerMenuCommand("Show Password Composer", mpwd_panel); } 

4.10.2. Running the Hack

After installing the user script (Tools Install This User Script), go to http://www.flickr.com and click "Sign up to register a new account. In the registration form, you will see a small icon next to the password field titled "Open Password Composer," as shown in Figure 4-11.

Figure 4-11. Password Composer active


Click the icon to open the Password Composer, and you have a chance to enter your master password, as shown in Figure 4-12.

Figure 4-12. Entering a master password


Enter a password in the box, press Enter, and you will go back to the original page with the password field filled with a generated password.

You have the option of using this password for this entire site or just for a specific subdomain. This is especially useful on blogging sites such as Blogspot or TypePad, where each subdomain is really a different site owned by a different person. You can choose a different random password for each subdomain, or you can choose to share a single password across all subdomains.

The script is also smart enough to handle web forms that contain multiple password fields, such as sites that tell you to enter a password and then immediately enter it again in a separate field to make sure you didn't mistype it. The script autofills both password fields once you type your master password.

     < Day Day Up > 


    Greasemonkey Hacks
    Greasemonkey Hacks: Tips & Tools for Remixing the Web with Firefox
    ISBN: 0596101651
    EAN: 2147483647
    Year: 2005
    Pages: 168
    Authors: Mark Pilgrim

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net