diff --git a/js/zerobin.js b/js/zerobin.js index fb603f4..ff89772 100644 --- a/js/zerobin.js +++ b/js/zerobin.js @@ -18,14 +18,26 @@ sjcl.random.startCollectors(); * @param int seconds * @return string */ -function secondsToHuman(seconds) -{ - if (seconds<60) { var v=Math.floor(seconds); return v+' second'+((v>1)?'s':''); } - if (seconds<60*60) { var v=Math.floor(seconds/60); return v+' minute'+((v>1)?'s':''); } - if (seconds<60*60*24) { var v=Math.floor(seconds/(60*60)); return v+' hour'+((v>1)?'s':''); } +function secondsToHuman(seconds) { + if (seconds < 60) { + var v = Math.floor(seconds); + return v + ' second' + ((v > 1) ? 's' : ''); + } + if (seconds < 60 * 60) { + var v = Math.floor(seconds / 60); + return v + ' minute' + ((v > 1) ? 's' : ''); + } + if (seconds < 60 * 60 * 24) { + var v = Math.floor(seconds / (60 * 60)); + return v + ' hour' + ((v > 1) ? 's' : ''); + } // If less than 2 months, display in days: - if (seconds<60*60*24*60) { var v=Math.floor(seconds/(60*60*24)); return v+' day'+((v>1)?'s':''); } - var v=Math.floor(seconds/(60*60*24*30)); return v+' month'+((v>1)?'s':''); + if (seconds < 60 * 60 * 24 * 60) { + var v = Math.floor(seconds / (60 * 60 * 24)); + return v + ' day' + ((v > 1) ? 's' : ''); + } + var v = Math.floor(seconds / (60 * 60 * 24 * 30)); + return v + ' month' + ((v > 1) ? 's' : ''); } /** @@ -35,24 +47,21 @@ function secondsToHuman(seconds) * @param object associative_array Object to be serialized * @return string */ -function hashToParameterString(associativeArray) -{ - var parameterString = "" - for (key in associativeArray) - { - if( parameterString === "" ) - { - parameterString = encodeURIComponent(key); - parameterString += "=" + encodeURIComponent(associativeArray[key]); - } else { - parameterString += "&" + encodeURIComponent(key); - parameterString += "=" + encodeURIComponent(associativeArray[key]); +function hashToParameterString(associativeArray) { + var parameterString = "" + for (key in associativeArray) { + if (parameterString === "") { + parameterString = encodeURIComponent(key); + parameterString += "=" + encodeURIComponent(associativeArray[key]); + } else { + parameterString += "&" + encodeURIComponent(key); + parameterString += "=" + encodeURIComponent(associativeArray[key]); + } } - } - //padding for URL shorteners - parameterString += "&p=p"; - - return parameterString; + //padding for URL shorteners + parameterString += "&p=p"; + + return parameterString; } /** @@ -61,19 +70,18 @@ function hashToParameterString(associativeArray) * @param string parameter_string String containing parameters * @return object */ -function parameterStringToHash(parameterString) -{ - var parameterHash = {}; - var parameterArray = parameterString.split("&"); - for (var i = 0; i < parameterArray.length; i++) { - //var currentParamterString = decodeURIComponent(parameterArray[i]); - var pair = parameterArray[i].split("="); - var key = decodeURIComponent(pair[0]); - var value = decodeURIComponent(pair[1]); - parameterHash[key] = value; - } - - return parameterHash; +function parameterStringToHash(parameterString) { + var parameterHash = {}; + var parameterArray = parameterString.split("&"); + for (var i = 0; i < parameterArray.length; i++) { + //var currentParamterString = decodeURIComponent(parameterArray[i]); + var pair = parameterArray[i].split("="); + var key = decodeURIComponent(pair[0]); + var value = decodeURIComponent(pair[1]); + parameterHash[key] = value; + } + + return parameterHash; } /** @@ -81,14 +89,13 @@ function parameterStringToHash(parameterString) * * @return object **/ -function getParameterHash() -{ - var hashIndex = window.location.href.indexOf("#"); - if (hashIndex >= 0) { - return parameterStringToHash(window.location.href.substring(hashIndex + 1)); - } else { - return {}; - } +function getParameterHash() { + var hashIndex = window.location.href.indexOf("#"); + if (hashIndex >= 0) { + return parameterStringToHash(window.location.href.substring(hashIndex + 1)); + } else { + return {}; + } } /** @@ -98,14 +105,14 @@ function getParameterHash() * @return base64 string data */ function compress(message) { - return Base64.toBase64( RawDeflate.deflate( Base64.utob(message) ) ); + return Base64.toBase64(RawDeflate.deflate(Base64.utob(message))); } /** * Decompress a message compressed with compress(). */ function decompress(data) { - return Base64.btou( RawDeflate.inflate( Base64.fromBase64(data) ) ); + return Base64.btou(RawDeflate.inflate(Base64.fromBase64(data))); } /** @@ -116,7 +123,10 @@ function decompress(data) { * @return encrypted string data */ function zeroCipher(key, message) { - return sjcl.encrypt(key,compress(message)); + if ($('input#password').val().length == 0) { + return sjcl.encrypt(key, compress(message)); + } + return sjcl.encrypt(key + sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash($("input#password").val())), compress(message)); } /** @@ -127,7 +137,14 @@ function zeroCipher(key, message) { * @return string readable message */ function zeroDecipher(key, data) { - return decompress(sjcl.decrypt(key,data)); + if (data != undefined) { + try { + return decompress(sjcl.decrypt(key, data)); + } catch (err) { + var password = prompt("Please enter the password for this paste.", ""); + return decompress(sjcl.decrypt(key + sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(password)), data)); + } + } } /** @@ -135,13 +152,13 @@ function zeroDecipher(key, data) { * eg. http://server.com/zero/?aaaa#bbbb --> http://server.com/zero/ */ function scriptLocation() { - var scriptLocation = window.location.href.substring(0,window.location.href.length - - window.location.search.length - window.location.hash.length); - var hashIndex = scriptLocation.indexOf("#"); - if (hashIndex !== -1) { - scriptLocation = scriptLocation.substring(0, hashIndex) - } - return scriptLocation + var scriptLocation = window.location.href.substring(0, window.location.href.length + - window.location.search.length - window.location.hash.length); + var hashIndex = scriptLocation.indexOf("#"); + if (hashIndex !== -1) { + scriptLocation = scriptLocation.substring(0, hashIndex) + } + return scriptLocation } /** @@ -165,8 +182,8 @@ function setElementText(element, text) { // For IE<10. if ($('div#oldienotice').is(":visible")) { // IE<10 does not support white-space:pre-wrap; so we have to do this BIG UGLY STINKING THING. - var html = htmlEntities(text).replace(/\n/ig,"\r\n
"); - element.html('
'+html+'
'); + var html = htmlEntities(text).replace(/\n/ig, "\r\n
"); + element.html('
' + html + '
'); } // for other (sane) browsers: else { @@ -183,7 +200,7 @@ function setElementText(element, text) { function displayMessages(key, comments) { try { // Try to decrypt the paste. var cleartext = zeroDecipher(key, comments[0].data); - } catch(err) { + } catch (err) { $('div#cleartext').addClass('hidden'); $('div#prettymessage').addClass('hidden'); $('button#clonebutton').addClass('hidden'); @@ -196,7 +213,7 @@ function displayMessages(key, comments) { prettyPrint(); // Display paste expiration. - if (comments[0].meta.expire_date) $('div#remainingtime').removeClass('foryoureyesonly').text('This document will expire in '+secondsToHuman(comments[0].meta.remaining_time)+'.').removeClass('hidden'); + if (comments[0].meta.expire_date) $('div#remainingtime').removeClass('foryoureyesonly').text('This document will expire in ' + secondsToHuman(comments[0].meta.remaining_time) + '.').removeClass('hidden'); if (comments[0].meta.burnafterreading) { $('div#remainingtime').addClass('foryoureyesonly').text('FOR YOUR EYES ONLY. Don\'t close this window, this message can\'t be displayed again.').removeClass('hidden'); $('button#clonebutton').addClass('hidden'); // Discourage cloning (as it can't really be prevented). @@ -207,23 +224,24 @@ function displayMessages(key, comments) { $('div#comments').html(''); // For each comment. for (var i = 1; i < comments.length; i++) { - var comment=comments[i]; - var cleartext="[Could not decrypt comment ; Wrong key ?]"; + var comment = comments[i]; + var cleartext = "[Could not decrypt comment ; Wrong key ?]"; try { cleartext = zeroDecipher(key, comment.data); - } catch(err) { } + } catch (err) { + } var place = $('div#comments'); // If parent comment exists, display below (CSS will automatically shift it right.) - var cname = 'div#comment_'+comment.meta.parentid + var cname = 'div#comment_' + comment.meta.parentid // If the element exists in page if ($(cname).length) { place = $(cname); } - var divComment = $('
' - + '
' - + '' - + '
'); + var divComment = $('
' + + '
' + + '' + + '
'); setElementText(divComment.find('div.commentdata'), cleartext); // Convert URLs to clickable links in comment. urls2links(divComment.find('div.commentdata')); @@ -232,8 +250,9 @@ function displayMessages(key, comments) { // Try to get optional nickname: try { divComment.find('span.nickname').text(zeroDecipher(key, comment.meta.nickname)); - } catch(err) { } - divComment.find('span.commentdate').text(' ('+(new Date(comment.meta.postdate*1000).toString())+')').attr('title','CommentID: ' + comment.meta.commentid); + } catch (err) { + } + divComment.find('span.commentdate').text(' (' + (new Date(comment.meta.postdate * 1000).toString()) + ')').attr('title', 'CommentID: ' + comment.meta.commentid); // If an avatar is available, display it. if (comment.meta.vizhash) { @@ -255,12 +274,12 @@ function displayMessages(key, comments) { function open_reply(source, commentid) { $('div.reply').remove(); // Remove any other reply area. source.after('
' - + '' - + '' - + '
' - + '
' - + '
'); - $('input#nickname').focus(function() { + + '' + + '' + + '
' + + '
' + + ''); + $('input#nickname').focus(function () { if ($(this).val() == $(this).attr('title')) { $(this).val(''); } @@ -274,39 +293,40 @@ function open_reply(source, commentid) { */ function send_comment(parentid) { // Do not send if no data. - if ($('textarea#replymessage').val().length==0) { + if ($('textarea#replymessage').val().length == 0) { return; } - showStatus('Sending comment...', spin=true); + showStatus('Sending comment...', spin = true); var cipherdata = zeroCipher(pageKey(), $('textarea#replymessage').val()); var ciphernickname = ''; - var nick=$('input#nickname').val(); + var nick = $('input#nickname').val(); if (nick != '' && nick != 'Optional nickname...') { ciphernickname = zeroCipher(pageKey(), nick); } - var data_to_send = { data:cipherdata, - parentid: parentid, - pasteid: pasteID(), - nickname: ciphernickname - }; + var data_to_send = { + data: cipherdata, + parentid: parentid, + pasteid: pasteID(), + nickname: ciphernickname + }; $.post(scriptLocation(), data_to_send, 'json') - .error(function() { - showError('Comment could not be sent (server error or not responding).'); - }) - .success(function(data) { - if (data.status == 0) { - showStatus('Comment posted.'); - location.reload(); - } - else if (data.status==1) { - showError('Could not post comment: '+data.message); - } - else { - showError('Could not post comment.'); - } - }); + .error(function () { + showError('Comment could not be sent (server error or not responding).'); + }) + .success(function (data) { + if (data.status == 0) { + showStatus('Comment posted.'); + location.reload(); + } + else if (data.status == 1) { + showError('Could not post comment: ' + data.message); + } + else { + showError('Could not post comment.'); + } + }); } @@ -320,51 +340,53 @@ function send_data() { } // If sjcl has not collected enough entropy yet, display a message. - if (!sjcl.random.isReady()) - { - showStatus('Sending paste (Please move your mouse for more entropy)...', spin=true); - sjcl.random.addEventListener('seeded', function(){ send_data(); }); - return; + if (!sjcl.random.isReady()) { + showStatus('Sending paste (Please move your mouse for more entropy)...', spin = true); + sjcl.random.addEventListener('seeded', function () { + send_data(); + }); + return; } - - showStatus('Sending paste...', spin=true); + + showStatus('Sending paste...', spin = true); var randomkey = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0); var cipherdata = zeroCipher(randomkey, $('textarea#message').val()); - var data_to_send = { data: cipherdata, - expire: $('select#pasteExpiration').val(), - burnafterreading: $('input#burnafterreading').is(':checked') ? 1 : 0, - opendiscussion: $('input#opendiscussion').is(':checked') ? 1 : 0 - }; + var data_to_send = { + data: cipherdata, + expire: $('select#pasteExpiration').val(), + burnafterreading: $('input#burnafterreading').is(':checked') ? 1 : 0, + opendiscussion: $('input#opendiscussion').is(':checked') ? 1 : 0 + }; $.post(scriptLocation(), data_to_send, 'json') - .error(function() { - showError('Data could not be sent (serveur error or not responding).'); - }) - .success(function(data) { - if (data.status == 0) { - stateExistingPaste(); - var url = scriptLocation() + "?" + data.id + '#' + randomkey; - var deleteUrl = scriptLocation() + "?pasteid=" + data.id + '&deletetoken=' + data.deletetoken; - showStatus(''); + .error(function () { + showError('Data could not be sent (serveur error or not responding).'); + }) + .success(function (data) { + if (data.status == 0) { + stateExistingPaste(); + var url = scriptLocation() + "?" + data.id + '#' + randomkey; + var deleteUrl = scriptLocation() + "?pasteid=" + data.id + '&deletetoken=' + data.deletetoken; + showStatus(''); - $('div#pastelink').html('Your paste is ' + url + ' (Hit CTRL+C to copy)'); - $('div#deletelink').html('Delete data'); - $('div#pasteresult').removeClass('hidden'); - selectText('pasteurl'); // We pre-select the link so that the user only has to CTRL+C the link. + $('div#pastelink').html('Your paste is ' + url + ' (Hit CTRL+C to copy)'); + $('div#deletelink').html('Delete data'); + $('div#pasteresult').removeClass('hidden'); + selectText('pasteurl'); // We pre-select the link so that the user only has to CTRL+C the link. - setElementText($('div#cleartext'), $('textarea#message').val()); - setElementText($('pre#prettyprint'), $('textarea#message').val()); - urls2links($('div#cleartext')); - showStatus(''); - prettyPrint(); - } - else if (data.status==1) { - showError('Could not create paste: '+data.message); - } - else { - showError('Could not create paste.'); - } - }); + setElementText($('div#cleartext'), $('textarea#message').val()); + setElementText($('pre#prettyprint'), $('textarea#message').val()); + urls2links($('div#cleartext')); + showStatus(''); + prettyPrint(); + } + else if (data.status == 1) { + showError('Could not create paste: ' + data.message); + } + else { + showError('Could not create paste.'); + } + }); } /** Text range selection. @@ -375,13 +397,13 @@ function selectText(element) { var doc = document , text = doc.getElementById(element) , range, selection - ; + ; if (doc.body.createTextRange) { //ms range = doc.body.createTextRange(); range.moveToElementText(text); range.select(); } else if (window.getSelection) { //all others - selection = window.getSelection(); + selection = window.getSelection(); range = doc.createRange(); range.selectNodeContents(text); selection.removeAllRanges(); @@ -400,6 +422,7 @@ function stateNewPaste() { $('div#remainingtime').addClass('hidden'); $('div#burnafterreadingoption').removeClass('hidden'); $('div#opendisc').removeClass('hidden'); + $('#password').show(); $('button#newbutton').removeClass('hidden'); $('div#pasteresult').addClass('hidden'); $('textarea#message').text(''); @@ -436,12 +459,11 @@ function stateExistingPaste() { } /** Return raw text - */ -function rawText() -{ + */ +function rawText() { var paste = $('div#cleartext').html(); var newDoc = document.open('text/html', 'replace'); - newDoc.write('
'+paste+'
'); + newDoc.write('
' + paste + '
'); newDoc.close(); } @@ -450,10 +472,10 @@ function rawText() */ function clonePaste() { stateNewPaste(); - + //Erase the id and the key in url history.replaceState(document.title, document.title, scriptLocation()); - + showStatus(''); $('textarea#message').text($('div#cleartext').text()); } @@ -517,9 +539,9 @@ function showStatus(message, spin) { */ function urls2links(element) { var re = /((http|https|ftp):\/\/[\w?=&.\/-;#@~%+-]+(?![\w\s?&.\/;#~%"=-]*>))/ig; - element.html(element.html().replace(re,'$1')); + element.html(element.html().replace(re, '$1')); var re = /((magnet):[\w?=&.\/-;#@~%+-]+)/ig; - element.html(element.html().replace(re,'$1')); + element.html(element.html().replace(re, '$1')); } /** @@ -533,27 +555,33 @@ function pageKey() { // We will strip any additional data. // First, strip everything after the equal sign (=) which signals end of base64 string. - i = key.indexOf('='); if (i>-1) { key = key.substring(0,i+1); } + i = key.indexOf('='); + if (i > -1) { + key = key.substring(0, i + 1); + } // If the equal sign was not present, some parameters may remain: - i = key.indexOf('&'); if (i>-1) { key = key.substring(0,i); } + i = key.indexOf('&'); + if (i > -1) { + key = key.substring(0, i); + } // Then add trailing equal sign if it's missing - if (key.charAt(key.length-1)!=='=') key+='='; + if (key.charAt(key.length - 1) !== '=') key += '='; return key; } -$(function() { +$(function () { // hide "no javascript" message $('#noscript').hide(); // If "burn after reading" is checked, disable discussion. - $('input#burnafterreading').change(function() { - if ($(this).is(':checked') ) { + $('input#burnafterreading').change(function () { + if ($(this).is(':checked')) { $('div#opendisc').addClass('buttondisabled'); $('input#opendiscussion').attr({checked: false}); - $('input#opendiscussion').attr('disabled',true); + $('input#opendiscussion').attr('disabled', true); } else { $('div#opendisc').removeClass('buttondisabled'); @@ -563,7 +591,7 @@ $(function() { // Display status returned by php code if any (eg. Paste was properly deleted.) if ($('div#status').text().length > 0) { - showStatus($('div#status').text(),false); + showStatus($('div#status').text(), false); return; } @@ -586,7 +614,7 @@ $(function() { displayMessages(pageKey(), messages); } // Display error message from php code. - else if ($('div#errormessage').text().length>1) { + else if ($('div#errormessage').text().length > 1) { showError($('div#errormessage').text()); } // Create a new paste. diff --git a/tpl/page.html b/tpl/page.html index ecddbb4..9a754f2 100644 --- a/tpl/page.html +++ b/tpl/page.html @@ -65,6 +65,7 @@ +