O'Reilly Hacks
oreilly.comO'Reilly NetworkSafari BookshelfConferences Sign In/My Account | View Cart   
Book List Learning Lab PDFs O'Reilly Gear Newsletters Press Room Jobs  


 
Buy the book!
Greasemonkey Hacks
By Mark Pilgrim
November 2005
More Info

HACK
#37
Keep Track of Secure Site Passwords
Generate random passwords for every site based on a master password
The Code
[Discuss (0) | Link to this hack]

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" 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.

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);
			}


O'Reilly Home | Privacy Policy

© 2007 O'Reilly Media, Inc.
Website: | Customer Service: | Book issues:

All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.