zerobin.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. /**
  2. * ZeroBin
  3. *
  4. * a zero-knowledge paste bin
  5. *
  6. * @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
  7. * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
  8. * @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
  9. * @version 0.19
  10. */
  11. // Immediately start random number generator collector.
  12. sjcl.random.startCollectors();
  13. /**
  14. * Converts a duration (in seconds) into human readable format.
  15. *
  16. * @param int seconds
  17. * @return string
  18. */
  19. function secondsToHuman(seconds)
  20. {
  21. if (seconds<60) { var v=Math.floor(seconds); return v+' second'+((v>1)?'s':''); }
  22. if (seconds<60*60) { var v=Math.floor(seconds/60); return v+' minute'+((v>1)?'s':''); }
  23. if (seconds<60*60*24) { var v=Math.floor(seconds/(60*60)); return v+' hour'+((v>1)?'s':''); }
  24. // If less than 2 months, display in days:
  25. if (seconds<60*60*24*60) { var v=Math.floor(seconds/(60*60*24)); return v+' day'+((v>1)?'s':''); }
  26. var v=Math.floor(seconds/(60*60*24*30)); return v+' month'+((v>1)?'s':'');
  27. }
  28. /**
  29. * Converts an associative array to an encoded string
  30. * for appending to the anchor.
  31. *
  32. * @param object associative_array Object to be serialized
  33. * @return string
  34. */
  35. function hashToParameterString(associativeArray)
  36. {
  37. var parameterString = "";
  38. for (key in associativeArray)
  39. {
  40. if( parameterString === "" )
  41. {
  42. parameterString = encodeURIComponent(key);
  43. parameterString += "=" + encodeURIComponent(associativeArray[key]);
  44. } else {
  45. parameterString += "&" + encodeURIComponent(key);
  46. parameterString += "=" + encodeURIComponent(associativeArray[key]);
  47. }
  48. }
  49. //padding for URL shorteners
  50. parameterString += "&p=p";
  51. return parameterString;
  52. }
  53. /**
  54. * Converts a string to an associative array.
  55. *
  56. * @param string parameter_string String containing parameters
  57. * @return object
  58. */
  59. function parameterStringToHash(parameterString)
  60. {
  61. var parameterHash = {};
  62. var parameterArray = parameterString.split("&");
  63. for (var i = 0; i < parameterArray.length; i++) {
  64. //var currentParamterString = decodeURIComponent(parameterArray[i]);
  65. var pair = parameterArray[i].split("=");
  66. var key = decodeURIComponent(pair[0]);
  67. var value = decodeURIComponent(pair[1]);
  68. parameterHash[key] = value;
  69. }
  70. return parameterHash;
  71. }
  72. /**
  73. * Get an associative array of the parameters found in the anchor
  74. *
  75. * @return object
  76. */
  77. function getParameterHash()
  78. {
  79. var hashIndex = window.location.href.indexOf("#");
  80. if (hashIndex >= 0) {
  81. return parameterStringToHash(window.location.href.substring(hashIndex + 1));
  82. } else {
  83. return {};
  84. }
  85. }
  86. /**
  87. * Compress a message (deflate compression). Returns base64 encoded data.
  88. *
  89. * @param string message
  90. * @return base64 string data
  91. */
  92. function compress(message) {
  93. return Base64.toBase64( RawDeflate.deflate( Base64.utob(message) ) );
  94. }
  95. /**
  96. * Decompress a message compressed with compress().
  97. */
  98. function decompress(data) {
  99. return Base64.btou( RawDeflate.inflate( Base64.fromBase64(data) ) );
  100. }
  101. /**
  102. * Compress, then encrypt message with key.
  103. *
  104. * @param string key
  105. * @param string message
  106. * @return encrypted string data
  107. */
  108. function zeroCipher(key, message) {
  109. if ($('#passwordinput').val().length == 0) {
  110. return sjcl.encrypt(key, compress(message));
  111. }
  112. return sjcl.encrypt(key + sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash($("#passwordinput").val())), compress(message));
  113. }
  114. /**
  115. * Decrypt message with key, then decompress.
  116. *
  117. * @param string key
  118. * @param encrypted string data
  119. * @return string readable message
  120. */
  121. function zeroDecipher(key, data) {
  122. if (data != undefined) {
  123. try {
  124. return decompress(sjcl.decrypt(key, data));
  125. } catch (err) {
  126. try {
  127. if ($('#passwordinput').val().length > 0) {
  128. password = $('#passwordinput').val();
  129. } else {
  130. password = prompt("Please enter the password for this paste:", "");
  131. if (password == null) return null;
  132. }
  133. data = decompress(sjcl.decrypt(key + sjcl.codec.hex.fromBits(sjcl.hash.sha256.hash(password)), data));
  134. $('#passwordinput').val(password);
  135. return data;
  136. } catch (err) {
  137. return zeroDecipher(key, data);
  138. }
  139. }
  140. }
  141. }
  142. /**
  143. * Get the current script location (without search or hash part of the URL).
  144. * eg. http://server.com/zero/?aaaa#bbbb --> http://server.com/zero/
  145. *
  146. * @return string current script location
  147. */
  148. function scriptLocation() {
  149. var scriptLocation = window.location.href.substring(0,window.location.href.length
  150. - window.location.search.length - window.location.hash.length);
  151. var hashIndex = scriptLocation.indexOf("#");
  152. if (hashIndex !== -1) {
  153. scriptLocation = scriptLocation.substring(0, hashIndex);
  154. }
  155. return scriptLocation;
  156. }
  157. /**
  158. * Get the pastes unique identifier from the URL
  159. * eg. http://server.com/zero/?c05354954c49a487#xxx --> c05354954c49a487
  160. *
  161. * @return string unique identifier
  162. */
  163. function pasteID() {
  164. return window.location.search.substring(1);
  165. }
  166. /**
  167. * Convert all applicable characters to HTML entities
  168. *
  169. * @param string str
  170. * @returns string encoded string
  171. */
  172. function htmlEntities(str) {
  173. return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
  174. }
  175. /**
  176. * Set text of a DOM element (required for IE)
  177. * This is equivalent to element.text(text)
  178. *
  179. * @param object element : a DOM element.
  180. * @param string text : the text to enter.
  181. */
  182. function setElementText(element, text) {
  183. // For IE<10.
  184. if ($('#oldienotice').is(":visible")) {
  185. // IE<10 does not support white-space:pre-wrap; so we have to do this BIG UGLY STINKING THING.
  186. var html = htmlEntities(text).replace(/\n/ig,"\r\n<br>");
  187. element.html('<pre>'+html+'</pre>');
  188. }
  189. // for other (sane) browsers:
  190. else {
  191. element.text(text);
  192. }
  193. }
  194. /**
  195. * Show decrypted text in the display area, including discussion (if open)
  196. *
  197. * @param string key : decryption key
  198. * @param array comments : Array of messages to display (items = array with keys ('data','meta')
  199. */
  200. function displayMessages(key, comments) {
  201. // restore password if set in previous visit, then clear the session
  202. if (window.sessionStorage && sessionStorage.getItem(pageKey())) {
  203. $('#passwordinput').val(sessionStorage.getItem(pageKey()));
  204. sessionStorage.clear();
  205. }
  206. try { // Try to decrypt the paste.
  207. var cleartext = zeroDecipher(key, comments[0].data);
  208. if (cleartext == null) throw "password prompt canceled";
  209. } catch(err) {
  210. $('#cleartext').addClass('hidden');
  211. $('#prettymessage').addClass('hidden');
  212. $('#clonebutton').addClass('hidden');
  213. showError('Could not decrypt data (Wrong key ?)');
  214. return;
  215. }
  216. setElementText($('#cleartext'), cleartext);
  217. setElementText($('#prettyprint'), cleartext);
  218. // Convert URLs to clickable links.
  219. urls2links($('#cleartext'));
  220. urls2links($('#prettyprint'));
  221. if (typeof prettyPrint == 'function') prettyPrint();
  222. // Display paste expiration.
  223. if (comments[0].meta.expire_date) $('#remainingtime').removeClass('foryoureyesonly').text('This document will expire in '+secondsToHuman(comments[0].meta.remaining_time)+'.').removeClass('hidden');
  224. if (comments[0].meta.burnafterreading) {
  225. $.get(scriptLocation() + "?pasteid=" + pasteID() + '&deletetoken=burnafterreading', 'json')
  226. .fail(function() {
  227. showError('Could not delete the paste, it was not stored in burn after reading mode.');
  228. });
  229. $('#remainingtime').addClass('foryoureyesonly').text('FOR YOUR EYES ONLY. Don\'t close this window, this message can\'t be displayed again.').removeClass('hidden');
  230. $('#clonebutton').addClass('hidden'); // Discourage cloning (as it can't really be prevented).
  231. }
  232. // If the discussion is opened on this paste, display it.
  233. if (comments[0].meta.opendiscussion) {
  234. $('#comments').html('');
  235. // iterate over comments
  236. for (var i = 1; i < comments.length; i++) {
  237. var comment=comments[i];
  238. var cleartext="[Could not decrypt comment ; Wrong key ?]";
  239. try {
  240. cleartext = zeroDecipher(key, comment.data);
  241. } catch(err) { }
  242. var place = $('#comments');
  243. // If parent comment exists, display below (CSS will automatically shift it right.)
  244. var cname = '#comment_'+comment.meta.parentid;
  245. // If the element exists in page
  246. if ($(cname).length) {
  247. place = $(cname);
  248. }
  249. var divComment = $('<article><div class="comment" id="comment_' + comment.meta.commentid+'">'
  250. + '<div class="commentmeta"><span class="nickname"></span><span class="commentdate"></span></div><div class="commentdata"></div>'
  251. + '<button onclick="open_reply($(this),\'' + comment.meta.commentid + '\');return false;" class="btn btn-default">Reply</button>'
  252. + '</div></article>');
  253. setElementText(divComment.find('div.commentdata'), cleartext);
  254. // Convert URLs to clickable links in comment.
  255. urls2links(divComment.find('div.commentdata'));
  256. divComment.find('span.nickname').html('<i>(Anonymous)</i>');
  257. // Try to get optional nickname:
  258. try {
  259. divComment.find('span.nickname').text(zeroDecipher(key, comment.meta.nickname));
  260. } catch(err) { }
  261. divComment.find('span.commentdate').text(' ('+(new Date(comment.meta.postdate*1000).toString())+')').attr('title','CommentID: ' + comment.meta.commentid);
  262. // If an avatar is available, display it.
  263. if (comment.meta.vizhash) {
  264. divComment.find('span.nickname').before('<img src="' + comment.meta.vizhash + '" class="vizhash" title="Anonymous avatar (Vizhash of the IP address)" /> ');
  265. }
  266. place.append(divComment);
  267. }
  268. $('#comments').append('<div class="comment"><button onclick="open_reply($(this),\'' + pasteID() + '\');return false;" class="btn btn-default">Add comment</button></div>');
  269. $('#discussion').removeClass('hidden');
  270. }
  271. }
  272. /**
  273. * Open the comment entry when clicking the "Reply" button of a comment.
  274. *
  275. * @param object source : element which emitted the event.
  276. * @param string commentid = identifier of the comment we want to reply to.
  277. */
  278. function open_reply(source, commentid) {
  279. $('div.reply').remove(); // Remove any other reply area.
  280. source.after('<div class="reply">'
  281. + '<input type="text" id="nickname" class="form-control" title="Optional nickname..." value="Optional nickname..." />'
  282. + '<textarea id="replymessage" class="replymessage form-control" cols="80" rows="7"></textarea>'
  283. + '<br /><button id="replybutton" onclick="send_comment(\'' + commentid + '\');return false;" class="btn btn-default">Post comment</button>'
  284. + '<div id="replystatus"> </div>'
  285. + '</div>');
  286. $('#nickname').focus(function() {
  287. if ($(this).val() == $(this).attr('title')) {
  288. $(this).val('');
  289. }
  290. });
  291. $('#replymessage').focus();
  292. }
  293. /**
  294. * Send a reply in a discussion.
  295. *
  296. * @param string parentid : the comment identifier we want to send a reply to.
  297. */
  298. function send_comment(parentid) {
  299. // Do not send if no data.
  300. if ($('#replymessage').val().length==0) {
  301. return;
  302. }
  303. showStatus('Sending comment...', spin=true);
  304. var cipherdata = zeroCipher(pageKey(), $('#replymessage').val());
  305. var ciphernickname = '';
  306. var nick=$('#nickname').val();
  307. if (nick != '' && nick != 'Optional nickname...') {
  308. ciphernickname = zeroCipher(pageKey(), nick);
  309. }
  310. var data_to_send = { data:cipherdata,
  311. parentid: parentid,
  312. pasteid: pasteID(),
  313. nickname: ciphernickname
  314. };
  315. $.post(scriptLocation(), data_to_send, 'json')
  316. .error(function() {
  317. showError('Comment could not be sent (server error or not responding).');
  318. })
  319. .success(function(data) {
  320. if (data.status == 0) {
  321. showStatus('Comment posted.');
  322. // store password temporarily between page loads
  323. if ($('#passwordinput').val().length > 0 && window.sessionStorage) {
  324. sessionStorage.setItem(pageKey(), $('#passwordinput').val());
  325. }
  326. location.reload();
  327. }
  328. else if (data.status==1) {
  329. showError('Could not post comment: '+data.message);
  330. }
  331. else {
  332. showError('Could not post comment.');
  333. }
  334. });
  335. }
  336. /**
  337. * Send a new paste to server
  338. */
  339. function send_data() {
  340. // Do not send if no data.
  341. if ($('#message').val().length == 0) {
  342. return;
  343. }
  344. // If sjcl has not collected enough entropy yet, display a message.
  345. if (!sjcl.random.isReady())
  346. {
  347. showStatus('Sending paste (Please move your mouse for more entropy)...', spin=true);
  348. sjcl.random.addEventListener('seeded', function(){ send_data(); });
  349. return;
  350. }
  351. showStatus('Sending paste...', spin=true);
  352. var randomkey = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0);
  353. var cipherdata = zeroCipher(randomkey, $('#message').val());
  354. var data_to_send = { data: cipherdata,
  355. expire: $('#pasteExpiration').val(),
  356. burnafterreading: $('#burnafterreading').is(':checked') ? 1 : 0,
  357. opendiscussion: $('#opendiscussion').is(':checked') ? 1 : 0
  358. };
  359. $.post(scriptLocation(), data_to_send, function(data) {
  360. if (data.status == 0) {
  361. stateExistingPaste();
  362. var url = scriptLocation() + "?" + data.id + '#' + randomkey;
  363. var deleteUrl = scriptLocation() + "?pasteid=" + data.id + '&deletetoken=' + data.deletetoken;
  364. showStatus('');
  365. $('#pastelink').html('Your paste is <a id="pasteurl" href="' + url + '">' + url + '</a> <span id="copyhint">(Hit CTRL+C to copy)</span>');
  366. $('#deletelink').html('<a href="' + deleteUrl + '">Delete data</a>');
  367. $('#pasteresult').removeClass('hidden');
  368. selectText('pasteurl'); // We pre-select the link so that the user only has to CTRL+C the link.
  369. setElementText($('#cleartext'), $('#message').val());
  370. setElementText($('#prettyprint'), $('#message').val());
  371. // Convert URLs to clickable links.
  372. urls2links($('#cleartext'));
  373. urls2links($('#prettyprint'));
  374. showStatus('');
  375. if (typeof prettyPrint == 'function') prettyPrint();
  376. }
  377. else if (data.status==1) {
  378. showError('Could not create paste: '+data.message);
  379. }
  380. else {
  381. showError('Could not create paste.');
  382. }
  383. }, 'json')
  384. .fail(function() {
  385. showError('Data could not be sent (server error or not responding).');
  386. });
  387. }
  388. /**
  389. * Text range selection.
  390. * From: http://stackoverflow.com/questions/985272/jquery-selecting-text-in-an-element-akin-to-highlighting-with-your-mouse
  391. *
  392. * @param string element : Indentifier of the element to select (id="").
  393. */
  394. function selectText(element) {
  395. var doc = document
  396. , text = doc.getElementById(element)
  397. , range, selection
  398. ;
  399. if (doc.body.createTextRange) { // MS
  400. range = doc.body.createTextRange();
  401. range.moveToElementText(text);
  402. range.select();
  403. } else if (window.getSelection) { // all others
  404. selection = window.getSelection();
  405. range = doc.createRange();
  406. range.selectNodeContents(text);
  407. selection.removeAllRanges();
  408. selection.addRange(range);
  409. }
  410. }
  411. /**
  412. * Put the screen in "New paste" mode.
  413. */
  414. function stateNewPaste() {
  415. $('#sendbutton').removeClass('hidden');
  416. $('#clonebutton').addClass('hidden');
  417. $('#rawtextbutton').addClass('hidden');
  418. $('#expiration').removeClass('hidden');
  419. $('#remainingtime').addClass('hidden');
  420. $('#burnafterreadingoption').removeClass('hidden');
  421. $('#opendisc').removeClass('hidden');
  422. $('#newbutton').removeClass('hidden');
  423. $('#pasteresult').addClass('hidden');
  424. $('#message').text('');
  425. $('#message').removeClass('hidden');
  426. $('#cleartext').addClass('hidden');
  427. $('#message').focus();
  428. $('#discussion').addClass('hidden');
  429. $('#prettymessage').addClass('hidden');
  430. // Show password field
  431. $('#password').removeClass('hidden');
  432. }
  433. /**
  434. * Put the screen in "Existing paste" mode.
  435. */
  436. function stateExistingPaste() {
  437. $('#sendbutton').addClass('hidden');
  438. // No "clone" for IE<10.
  439. if ($('#oldienotice').is(":visible")) {
  440. $('#clonebutton').addClass('hidden');
  441. }
  442. else {
  443. $('#clonebutton').removeClass('hidden');
  444. }
  445. $('#rawtextbutton').removeClass('hidden');
  446. $('#expiration').addClass('hidden');
  447. $('#burnafterreadingoption').addClass('hidden');
  448. $('#opendisc').addClass('hidden');
  449. $('#newbutton').removeClass('hidden');
  450. $('#pasteresult').addClass('hidden');
  451. $('#message').addClass('hidden');
  452. $('#cleartext').addClass('hidden');
  453. $('#prettymessage').removeClass('hidden');
  454. }
  455. /**
  456. * Return raw text
  457. */
  458. function rawText()
  459. {
  460. var paste = $('#cleartext').html();
  461. var newDoc = document.open('text/html', 'replace');
  462. newDoc.write('<pre>'+paste+'</pre>');
  463. newDoc.close();
  464. }
  465. /**
  466. * Clone the current paste.
  467. */
  468. function clonePaste() {
  469. stateNewPaste();
  470. //Erase the id and the key in url
  471. history.replaceState(document.title, document.title, scriptLocation());
  472. showStatus('');
  473. $('#message').text($('#cleartext').text());
  474. }
  475. /**
  476. * Create a new paste.
  477. */
  478. function newPaste() {
  479. stateNewPaste();
  480. showStatus('');
  481. $('#message').text('');
  482. }
  483. /**
  484. * Display an error message
  485. * (We use the same function for paste and reply to comments)
  486. */
  487. function showError(message) {
  488. if ($('#status').length) {
  489. $('#status').addClass('errorMessage').text(message);
  490. } else {
  491. $('#errormessage').removeClass('hidden').append(message);
  492. }
  493. $('#replystatus').addClass('errorMessage').text(message);
  494. }
  495. /**
  496. * Display status
  497. * (We use the same function for paste and reply to comments)
  498. *
  499. * @param string message : text to display
  500. * @param boolean spin (optional) : tell if the "spinning" animation should be displayed.
  501. */
  502. function showStatus(message, spin) {
  503. $('#replystatus').removeClass('errorMessage');
  504. $('#replystatus').text(message);
  505. if (!message) {
  506. $('#status').html(' ');
  507. return;
  508. }
  509. if (message == '') {
  510. $('#status').html(' ');
  511. return;
  512. }
  513. $('#status').removeClass('errorMessage');
  514. $('#status').text(message);
  515. if (spin) {
  516. var img = '<img src="img/busy.gif" style="width:16px;height:9px;margin:0px 4px 0px 0px;" />';
  517. $('#status').prepend(img);
  518. $('#replystatus').prepend(img);
  519. }
  520. }
  521. /**
  522. * Convert URLs to clickable links.
  523. * URLs to handle:
  524. * <code>
  525. * magnet:?xt.1=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C&xt.2=urn:sha1:TXGCZQTH26NL6OUQAJJPFALHG2LTGBC7
  526. * http://localhost:8800/zero/?6f09182b8ea51997#WtLEUO5Epj9UHAV9JFs+6pUQZp13TuspAUjnF+iM+dM=
  527. * http://user:password@localhost:8800/zero/?6f09182b8ea51997#WtLEUO5Epj9UHAV9JFs+6pUQZp13TuspAUjnF+iM+dM=
  528. * </code>
  529. *
  530. * @param object element : a jQuery DOM element.
  531. */
  532. function urls2links(element) {
  533. var re = /((http|https|ftp):\/\/[\w?=&.\/-;#@~%+-]+(?![\w\s?&.\/;#~%"=-]*>))/ig;
  534. element.html(element.html().replace(re,'<a href="$1" rel="nofollow">$1</a>'));
  535. var re = /((magnet):[\w?=&.\/-;#@~%+-]+)/ig;
  536. element.html(element.html().replace(re,'<a href="$1">$1</a>'));
  537. }
  538. /**
  539. * Return the deciphering key stored in anchor part of the URL
  540. */
  541. function pageKey() {
  542. var key = window.location.hash.substring(1); // Get key
  543. // Some stupid web 2.0 services and redirectors add data AFTER the anchor
  544. // (such as &utm_source=...).
  545. // We will strip any additional data.
  546. // First, strip everything after the equal sign (=) which signals end of base64 string.
  547. i = key.indexOf('='); if (i>-1) { key = key.substring(0,i+1); }
  548. // If the equal sign was not present, some parameters may remain:
  549. i = key.indexOf('&'); if (i>-1) { key = key.substring(0,i); }
  550. // Then add trailing equal sign if it's missing
  551. if (key.charAt(key.length-1)!=='=') key+='=';
  552. return key;
  553. }
  554. /**
  555. * main application start, called when DOM is fully loaded
  556. */
  557. $(function() {
  558. // hide "no javascript" message
  559. $('#noscript').hide();
  560. // If "burn after reading" is checked, disable discussion.
  561. $('#burnafterreading').change(function() {
  562. if ($(this).is(':checked') ) {
  563. $('#opendisc').addClass('buttondisabled');
  564. $('#opendiscussion').attr({checked: false});
  565. $('#opendiscussion').attr('disabled',true);
  566. }
  567. else {
  568. $('#opendisc').removeClass('buttondisabled');
  569. $('#opendiscussion').removeAttr('disabled');
  570. }
  571. });
  572. // Display status returned by php code if any (eg. Paste was properly deleted.)
  573. if ($('#status').text().length > 0) {
  574. showStatus($('#status').text(),false);
  575. return;
  576. }
  577. $('#status').html(' '); // Keep line height even if content empty.
  578. // Display an existing paste
  579. if ($('#cipherdata').text().length > 1) {
  580. // Missing decryption key in URL ?
  581. if (window.location.hash.length == 0) {
  582. showError('Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL ?)');
  583. return;
  584. }
  585. // List of messages to display
  586. var messages = jQuery.parseJSON($('#cipherdata').text());
  587. // Show proper elements on screen.
  588. stateExistingPaste();
  589. displayMessages(pageKey(), messages);
  590. }
  591. // Display error message from php code.
  592. else if ($('#errormessage').text().length>1) {
  593. showError($('#errormessage').text());
  594. }
  595. // Create a new paste.
  596. else {
  597. newPaste();
  598. }
  599. });