OK, I got a little obsessed with this idea, and I've updated the original password bookmarklet to include added awesomeness(tm).
Now, instead of a Javascript prompt, it creates a floating HTML element in the current window. With this implementation you can finally type in your master password without it being displayed in clear text (it's just like a regular password box).
You can also edit the subdomain it uses if you need to, but this is as unobtrusive and as easy as possible.
Essentially, this script is now as awesome as I'm gonna make it. So use it! Drag it to your bookmarks bar to store it as a bookmarklet, or just click it to see what it does. Go on, you know you want to!
By the way, please leave a comment and tell me weather it works on non-firefox browsers (namely Safari and Opera). I'm aware that it won't wotk in IE due to bookmark length limitations, but that's beyond my control...
Update: Since it doesn't work in IE, I've put up a page that works in IE. It's a good idea to save this page to disk so you'll never be without it if my site goes down...





28 Comments:
Very nice. Now I have seen versions that DO work with IE by simply having the js code posted on a website, since IE cant handle it as a bookmarklet.
Can you make yours work like this too, since I have yet to find one that hides the password like yours.
Then of course people could put it on their own website instead of going out to a site they dont control.
Thanks !
This is an example that would work with IE
javascript:s=document.body.appendChild(document.createElement('script'));s.id='fs';s.language='javascript';void(s.src='http://labs.zarate.org/passwd/passwd.js')
But, question is, how do I edit this to work with yours, and also host the js on my server. How do we convert ascii to the %56%43 blah blah
Here it is so you can read the whole thing.
javascript:s=document.body.
appendChild(document.createElement
('script'));s.id='fs';s.language=
'javascript';void(s.src=
'http://labs.zarate.org/
passwd/passwd.js')
Sadly, IE's general suckiness prevents this code from working. I assume it has some prorietary way of inserting and deleting new HTML elements or something. Personally I can't stand to work with IE anymore, it's just not worth the headaches.
However, I've uploaded the javascript code in a more readable form, so that others can try and get it to work in IE. There's also a function to convert problem characters to %25, %27, etc.
Take a look over here for the code.
(sorry it's not really commented, but at least the parts that you might need to change are all formatted nicely)
Why do some sites appear to have converted so many of the characters of the bookmarklet, when your converter does not convert nearly so many...
for example, your converter when converting this:
javassccript:s=document.body.appendChild(document.createElement('script'));s.id='fs';s.language='javascript';void(s.src='http://labs.zarate.org/passwd/passwd.js')
yields:
javascript:s=document.body.appendChild(document.createElement(%27script%27));s.id=%27fs%27;s.language=%27javascript%27;void(s.src=%27http://labs.zarate.org/passwd/passwd.js%27)
Yet when I view the source of the page where the bookmarklet above came from I see this...
Bookmarklet for Internet Explorer: javascript:%73%3D%64%6F%63%75%6D%65%6E%74%2E%62%6F%64%79%2E%61%70%70%65%6E%64%43%68%69%6C%64%28%64%6F%63%75%6D%65%6E%74%2E%63%72%65%61%74%65%45%6C%65%6D%65%6E%74%28%27%73%63%72%69%70%74%27%29%29%3B%73%2E%69%64%3D%27%66%73%27%3B%73%2E%6C%61%6E%67%75%61%67%65%3D%27%6A%61%76%61%73%63%72%69%70%74%27%3B%76%6F%69%64%28%73%2E%73%72%63%3D%27%68%74%74%70%3A%2F%2F%6C%61%62%73%2E%7A%61%72%61%74%65%2E%6F%72%67%2F%70%61%73%73%77%64%2F%70%61%73%73%77%64%2E%6A%73%27%29
So confused.., Is your converter's conversion sufficient ? I will try it out and see. Thanks
Many people use javascript's escape() function to make bookmarklets url-safe, but this escapes every character (tripling the size of the script in the process). All you really need to do is escape characters that screw up URLS (and it also needs to be able to be pasted into HTML links, which is why I escape the quotes as well).
I think the optimal solution would be to escape all non-base64 characters, but for now my solution has worked well for me...
That's great Tim. Tim is there a chance that you can come up with a plain HTML page that I can save on my blog somewhere so I can access it from anywhere and don't have to rely on my bookmarklets?
Also can that HTML be compatible with IE by any chance?
Do keep up the good work. Well done.
Thanks Tim.
So now that I have converted the javacript, how do I make it a bookmark ?
Thanks again, awesome code.
best regards,
Eric
bookmarks are simply javascript code (must all be one line), with "javascript:" in front of it. For some reason it's a good idea to call void(); after your code is done, otherwise firefox sometimes looks as if it hasn't fully loaded the page.
Tejas - this is pretty simple, I can put one up when I've got a bit more time...
Thanks Tim
I want to use the following pointing to a local JAVASCRIPT.js file, is there a particular syntax for referencing a local source file ? for some reason it wont work, plus here is a link to an excellent Converter I used in addition to yours to fully convert a string, pick your own delimiter, i.e. % and then make sure it is %code % code instead of code %
http://www.vortex.prodigynet.co.uk/misc/ascii_conv.html
This works and points to an external file via URL:
javascript:s=document.body.appendChild
(document.createElement('script'));
s.id='fs';s.language='javascript';
void(s.src='http://labs.zarate.org/passwd/passwd.js')
this does NOT work, and points to a LOCAL javascript Source file. Is my syntax for pointing to a local file not correct ?
javascript:s=document.body.appendChild
(document.createElement('script'));
s.id='fs';s.language='javascript';
void(s.src=’c:\dl\stuff\javascript\passwd.js')
Of course in both cases they are each a single line only. Multiple lines here only to make it more readable.
Thanks !!
The URL method for pointing to local files is actually
file:///c:/dl/script.js
(note there are three slashes after "file:")
There seem to be some security issues though, which are there to prevent any old site from reading your local files. You may be able to get around this, but it might not be very safe ;)
Alright, Link for a page that works with IE is now added in the original post. Save it to your computer, add a bookmark, and you'll never notice that you use a terrible browser ;)
(you might want to get the .txt source version, because it doesn't have auto-inserted ad code...)
You wouldn't happen to have a version that only uses the domain name, would you?
It is actually more secure if site's db gets hacked since it won't provide as many data points to use in hacking out the master password.
Using only the domain name is actually quite hard, because you need to store all known domain suffixes, of which there are hundreds (and there's no central record of them to my knowledge).
However, Chris Zarate has attempted just that. It doesn't work on all domains, but it should be fine for the majority of sites.
Terrific improvement and good implementation, Tim! Glad to see people improving on my idea. I've linked here from my "original" password-generator bookmarklet page.
Hmm - using Safari 2 it puts the password in password fields but seems to put the domain name in all other fields! Maybe I'll take a look at the code when I have some time. Still, good stuff.
Thanks Nic :)
Also, that safari thing is bizarre. There isn't actually any code to insert the host anywhere except the password box it creates, so I have no idea how that's happening...
Amateurs :p
A little more regex magic, and we're parsing just the blogger.com bit just fine.
Without going into how much regexiness is supported from javascript; we reluctantly match everything (.*?), then match any character that's not a slash or a dot, then just the dot, then the no slashes or dots again.
Look ma, no lookups!
javascript:function showInputForm(){var host;try{re = new RegExp(%22https*://.*?([^/.]+[.][^/.]+)/%22);host = document.location.href.match(re)[1];} catch(Exception){host=%22none%22;}var body = document.getElementsByTagName(%27body%27).item(0);var JSPWDiv = document.createElement(%27div%27);JSPWDiv.setAttribute(%27id%27,%27JSMD5PwGenDiv%27);JSPWDiv.setAttribute(%27style%27,%27margin:100px;padding:100;%27);var pwBox = document.createElement(%22input%22);pwBox.setAttribute(%22type%22,%22password%22);pwBox.setAttribute(%22id%22,%22MD5MasterPassword%22);pwBox.setAttribute(%22style%22,%22border:1px solid #b44;%22);var hostBox = document.createElement(%22input%22);hostBox.setAttribute(%22type%22,%22text%22);hostBox.setAttribute(%22id%22,%22MD5MasterHost%22);hostBox.setAttribute(%22value%22,host);hostBox.setAttribute(%22style%22,%22border:1px solid #b44;color:#666;%22);var frm = document.createElement(%27form%27);frm.setAttribute(%27onsubmit%27,%27javascript:%27+doIt.toString()+hex_md5.toString()+binl2hex.toString()+core_md5.toString()+md5_cmn.toString()+md5_ff.toString()+md5_gg.toString()+md5_hh.toString()+md5_ii.toString()+safe_add.toString()+bit_rol.toString()+str2binl.toString()+binl2hex.toString()+%27doIt();return false;%27);var closeBtn = document.createElement(%27a%27);closeBtn.setAttribute(%27onclick%27,%22document.getElementsByTagName(%27body%27).item(0).removeChild(document.getElementById(%27JSMD5PwGenDiv%27))%22);closeBtn.setAttribute(%27style%27,%22color:#b44;text-decoration:none;font-weight:bold;position:absolute;top:0;right:5px;%22);closeBtn.setAttribute(%27href%27,%22javascript:void();%22);closeBtn.appendChild(document.createTextNode(%22[x]%22));var submitBtn = document.createElement(%27input%27);submitBtn.setAttribute(%27type%27,%27submit%27);submitBtn.setAttribute(%27value%27,%27Generate%27);submitBtn.setAttribute(%22style%22,%22margin:10px 0;background:#eee;border:1px solid #988;%22);JSPWDiv.appendChild(closeBtn);JSPWDiv.onkeypress=new Function(%22e%22,%22if (!e) var e = window.event;if(e.keyCode == 27){document.getElementsByTagName(%27body%27).item(0).removeChild(document.getElementById(%27JSMD5PwGenDiv%27));e.cancelBubble = true;if (e.stopPropagation) e.stopPropagation();return false;}e.cancelBubble=false;return true;%22);frm.appendChild(document.createTextNode(%22Master Password: %22));frm.appendChild(pwBox);frm.appendChild(document.createElement(%27br%27));frm.appendChild(document.createTextNode(%22Using Host: %22));frm.appendChild(hostBox);frm.appendChild(document.createElement(%27br%27));frm.appendChild(submitBtn);JSPWDiv.appendChild(frm);JSPWDiv.setAttribute(%22style%22,%22text-align:right;padding:30px 10px 0 10px;position:fixed;z-index:9999;color:#422;font-family:arial,sans-serif;font-size:12pt;background:#fdd;line-height:18pt;border:2px solid #b44;top:10px;right:10px;%22);body.appendChild(JSPWDiv);pwBox.focus();}showInputForm();void(null);function hex_md5(s){return binl2hex(core_md5(str2binl(s), s.length * 8));}function core_md5(x, len){x[len %3E%3E 5] |= 0x80 %3C%3C ((len) %25 32);x[(((len + 64) %3E%3E%3E 9) %3C%3C 4) + 14] = len;var a = 1732584193;var b = -271733879;var c = -1732584194;var d = 271733878;for(var i = 0; i %3C 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 %3E%3E 16) + (y %3E%3E 16) + (lsw %3E%3E 16);return (msw %3C%3C 16) | (lsw & 0xFFFF);}function bit_rol(num, cnt){return (num %3C%3C cnt) | (num %3E%3E%3E (32 - cnt));}function str2binl(str){var bin = Array();var mask = (1 %3C%3C 8) - 1;for(var i = 0; i %3C str.length * 8; i += 8)bin[i%3E%3E5] |= (str.charCodeAt(i / 8) & mask) %3C%3C (i%2532);return bin;}function binl2hex(binarray){var hex_tab = %220123456789abcdef%22;var str = %22%22;for(var i = 0; i %3C binarray.length * 4; i++){str += hex_tab.charAt((binarray[i%3E%3E2] %3E%3E ((i%254)*8+4)) & 0xF) + hex_tab.charAt((binarray[i%3E%3E2] %3E%3E ((i%254)*8)) & 0xF);}return str;}function doIt(){var host = document.getElementById(%27MD5MasterHost%27).value;var master = document.getElementById(%27MD5MasterPassword%27).value;var c = 0;document.getElementsByTagName(%27body%27).item(0).removeChild(document.getElementById(%27JSMD5PwGenDiv%27));if (master != %27%27 && master != null) {var i=0, j=0, p=hex_md5(master+%27:%27+host).substr(0,8), F=document.forms;for(i=0;i%3CF.length;i++){E=F[i].elements;for(j=0;j%3CE.length;j++){D=E[j];if(D.type==%27password%27 && D.id!=%27MD5MasterPassword%27){D.value=p;c++;D.focus();}}}if(c == 0)prompt(%27No password input found, the generated password is:%27,p);}return false;}void(null);
Hmm... guess I didn't really need to post the entire script again, seeing as "%22https*://.*?([^/.]+[.][^/.]+)/%22" neatly fits on a single line.
Sorry William, but that still doesn't work right :/
The problem is when you omit the subdomain (eg using just "http://google.co.uk/"). In this case it would set the domain to "co.uk", which isn't what we want :(
Heh, I saw that the next day when trying to find this site again.
An alternative would be to then grab as many pieces as neccessary to make a domain name at least 'x' characters long.
A better alternative would be to give a combobox type control with the handful of possibilities, defaulting to the above logic.
On another note, pushing the password into every password field detected is broken. There is no easy way to change a password, without at least going to a seperate page, specifying the original domain name, and copying the password into the original page. Otherwise the old and new password fields will end up containing the same password.
I've hacked my version up to only insert the password automatically if the page contains exactly one password field, otherwise displaying the popup. Alternatively, if there was some way to determine which field previously had the focus, you could just insert the password into that.
Good point about the multiple password thing, I tend to get around that by just typing in my old password after I've run the script.
Unfortunately I don't think you can capture the active text box, as you have to unfocus it to run the script.
A greasemonkey script could be a good idea here, where it would insert a little button next to each password field that you click to fill it in (I think this may have already been done actually, I just can't remember where).
Excellent. In case you're not happy with eight-character passwords, the expression below controls the final password length.
p=hex_md5(master+%27:%27+host).substr(0,8)
And about those subdomains....
Why not just break down the url and provide a checkbox for each part? I.e., https://login.ebay.com/someotherstuff would show up as:
-[x]---[x]--[x]
login.ebay.com
Then you could select which parts to exclude by simply unchecking the corresponding boxes.
You are a smart anonymous person. The checkboxes might look a bit ugly (sadly I care about that ;)) but the basic idea is solid. I'd like to work on it when I have time, but that might be a while yet...
Tim, it looks like your script would be the best of the bunch, but unfortuantely due to my testing it seems the passwords generated are different from the version at labs.zarate.org/passwd.
I tested both bookmarklets side by side on the same site. One logged me in, and the other didn't. Both are using the exact same master password and site url, but I think somehow the password is being generated differently.
The version at labs.zarate.org/passwd has been changed since I made my version, it now attempts to strip subdomains, and only uses the domain (ie this site would be "sysprosoft.com" instead of "gfxmonk.sysprosoft.com"). The method Chris used isn't terribly rock-solid, so I chose to leave subdomain information in.
You almost always log in from the same subdomain anyways, and if the sign-up page is on a different subdomain then you can just edit the "host" input that appears when you set your password (to be the same as the log-in subdomain).
If you want my version to generate passwords that are compatible with Chris', you just need to remove the subdomain in the "host" field (gfxmonk.sysprosoft.com becomes sysprosoft.com).
FYI, I have tried this in Opera 8.54 and 9.0, and it works nicely. Thanks!