0

I'm writing a JavaScript function that needs to uphold three properties:

  • be very small and lightweight - no external libraries
  • encode a string in such a way as to be able to be passed as a GET parameter
  • this string must be decoded again at its destination

Effectively, it authenticates the user by sending his username and password to a PHP page which then verifies it. This is done via GET because I haven't yet found a way of doing a background cross-domain POST request. The trouble is that if the user has a character such as '#' or similar in his password, it doesn't get sent properly.

Currently to avoid this, I encode() the password string before sending it, which allows it to be received without problems. However, I read that PHP's urldecode() is not a perfect analog for this, as there are corner cases which are treated differently (i.e. ' ', '+', etc). Sadly I cannot find this document anymore, so I cannot quote it, but the gist was that one of them converts spaces into '+' signs, which the other treats as an actual plus sign, or something like that...

As such, I'm looking for a Javascript function that can take a string and make it URL-safe, and which has a perfect reversal function in PHP so that the original string can be recovered.

The arguably awful code I currently use to achieve this:

login.onsubmit = function(){
    loginFailMsg.style.display = 'none';
    var inputs = login.getElementsByTagName('input');
    var formdata = 
        'username='+inputs[0].value+'&password='+encode(inputs[1].value);
    submit.src = formtarget+'/auth/bklt?'+formdata;
    userinfo = undefined;
    setTimeout(getUserinfo,300);
    return false;
};
Arjan
  • 20,227
  • 10
  • 57
  • 70
Mala
  • 12,644
  • 25
  • 79
  • 113
  • Now that you mentioned there's a very good reason for GET, why not remove that sentence and simply share that reason with us? Curious! – Arjan Oct 16 '10 at 23:31
  • And, there's too much noise in your question! If you don't want MD5 (like you commented to Karl's answer), then why mention that, and why not remove the whole hashing from the title as well? – Arjan Oct 16 '10 at 23:37
  • @Arjan: Apologies for the noise, I'm not terribly good at wording myself =P I would love md5 if I could use it, but what I really need is something built into javascript. – Mala Oct 16 '10 at 23:52
  • (Hmmm, JavaScript *is* a programming language, *how* would you use built-in stuff without writing some code yourself ;-) As for background POST: did you look at [JSONP with jQuery](http://www.ibm.com/developerworks/library/wa-aj-jsonp1/)?) – Arjan Oct 17 '10 at 00:00
  • I rewrote the question in what is hopefully a less noisy and clearer way – Mala Oct 17 '10 at 00:00

3 Answers3

2

encodeURIComponent, PHP will decode it automatically when populating $_POST or $_GET

Quentin
  • 800,325
  • 104
  • 1,079
  • 1,205
1

I don't think there's such a thing as a reversible hash function. There are plenty of javascript md5 libraries available, however.

Karl Bielefeldt
  • 42,558
  • 9
  • 56
  • 88
  • apologies, I misspoke - in absence of md5 i'm looking for some kind of translation, i.e. base64 or something... basically something that'll make sure it gets passed to the script correctly – Mala Oct 16 '10 at 22:34
1
'&password='+encode(inputs[1].value)

Where's encode function coming from? Seems to me the quick answer to your question is using encodeURIComponent() instead, available since JavaScript 1.5. See also Comparing escape(), encodeURI(), and encodeURIComponent(); it does not encode everything either, but does encode all the server expects it to.

(As for cross-domain AJAX POST calls, I'd really have a look at "JSON with Padding". See JSONP with jQuery that I mentioned in the comments earlier. This will also prevent issues with the timeout you've randomly chosen, and jQuery will also help you, a lot, to get rid of inputs[0].value and the like. And, as you apparently already have a MD5 hash on the server, I'd really hash the password client side as well --see Karl's answer-- and compare those hashes instead. Respect your user's password and your own time, drop that no external libraries requirement!)

Community
  • 1
  • 1
Arjan
  • 20,227
  • 10
  • 57
  • 70
  • using escape, the # isn't a problem... it's just php's urldecode does not produce the exact input. There are a few corner cases (I wish I could remember where I read this) involving ' ', '+', and a few other characters – Mala Oct 16 '10 at 23:50
  • Oh, as you're not using `
    `, I guess? Modern browsers also support `encodeURI` and the like, but I guess indeed `escape` should give you the same result as a plain `
    `.
    – Arjan Oct 17 '10 at 00:02
  • Oh, sorry. I'm trying to accomplish a cross-domain ajax request, and since this is forbidden the best solution I was able to think of is to try preload an "image" whose url is "http://server.com/remoteauth/?user=username&pass=password" – Mala Oct 17 '10 at 00:03
  • The trouble with jQuery is that it's an external library, and is quite large (compared to nothing, that is). I'm trying to keep the entire script under 25kb. Which makes including jQuery's 72kb minified version out of the question. However, encodeURIComponent() appears (from the doc and from testing) to accomplish my needs. – Mala Oct 17 '10 at 17:50
  • I'm also rewriting it to avoid that hardcoded timeout, because it's obviously a problem. Rather it'll wait for a little while and checking again, with a loop counter so that if that happens too often it sends the request again. Sometimes you just gotta get your hands dirty... – Mala Oct 17 '10 at 17:51
  • @Mala, just as an aside: when [using Google's CDN for jQuery](http://encosia.com/2008/12/10/3-reasons-why-you-should-let-google-host-jquery-for-you/) then many of your users might already have jQuery in their cache anyhow, just by visiting other sites that use the same thing from the same Google URL. And though not on Google's CDN: there's [a MD5 plugin](http://plugins.jquery.com/project/md5) too, making your users happy even though they won't even know it. ;-) – Arjan Oct 17 '10 at 18:15
  • @Arjan thanks for the links. In this particular instance though, since it's a bookmarklet, the prospect of adding a – Mala Oct 20 '10 at 00:53
  • Aha, @Mala, it's a bookmarklet! Just as an aside again: bookmarklets *can* download external libraries. See [How do you use http://toread.cc without a bookmarklet?](http://superuser.com/questions/64475/how-do-you-use-http-toread-cc-without-a-bookmarklet/64494#64494), or see [The Printliminator](http://css-tricks.com/examples/ThePrintliminator/) that even loads jQuery on the fly. – Arjan Oct 20 '10 at 05:36