2012-04-22 12:45:45 +02:00
/ * *
2012-04-30 22:58:08 +02:00
* ZeroBin
2012-04-23 16:30:02 +02:00
*
2012-04-30 22:58:08 +02:00
* a zero - knowledge paste bin
*
* @ link http : //sebsauvage.net/wiki/doku.php?id=php:zerobin
* @ copyright 2012 Sébastien SAUVAGE ( sebsauvage . net )
* @ license http : //www.opensource.org/licenses/zlib-license.php The zlib/libpng License
2015-09-03 22:22:59 +02:00
* @ version 0.20
2012-04-22 12:45:45 +02:00
* /
2012-04-21 21:59:45 +02:00
// Immediately start random number generator collector.
sjcl . random . startCollectors ( ) ;
2012-04-22 12:45:45 +02:00
/ * *
2015-08-31 21:14:12 +02:00
* Converts a duration ( in seconds ) into human readable format .
2012-04-23 16:30:02 +02:00
*
2015-08-31 21:14:12 +02:00
* @ param int seconds
* @ return string
2012-04-22 12:45:45 +02:00
* /
2012-04-21 21:59:45 +02:00
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' : '' ) ;
}
2012-07-28 21:35:14 +02:00
/ * *
* Converts an associative array to an encoded string
* for appending to the anchor .
*
* @ param object associative _array Object to be serialized
* @ return string
* /
function hashToParameterString ( associativeArray )
{
2015-08-31 21:14:12 +02:00
var parameterString = "" ;
2012-07-28 21:35:14 +02:00
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" ;
2015-08-22 17:23:41 +02:00
2012-07-28 21:35:14 +02:00
return parameterString ;
}
/ * *
* Converts a string to an associative array .
*
* @ 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 ;
}
2015-08-16 11:20:06 +02:00
2012-07-28 21:35:14 +02:00
return parameterHash ;
}
/ * *
* Get an associative array of the parameters found in the anchor
*
* @ return object
2015-08-31 21:14:12 +02:00
* /
2012-07-28 21:35:14 +02:00
function getParameterHash ( )
{
var hashIndex = window . location . href . indexOf ( "#" ) ;
if ( hashIndex >= 0 ) {
return parameterStringToHash ( window . location . href . substring ( hashIndex + 1 ) ) ;
} else {
return { } ;
2015-08-16 11:20:06 +02:00
}
2012-07-28 21:35:14 +02:00
}
2012-04-22 12:45:45 +02:00
/ * *
* Compress a message ( deflate compression ) . Returns base64 encoded data .
2012-04-23 16:30:02 +02:00
*
2012-04-22 12:45:45 +02:00
* @ param string message
* @ return base64 string data
* /
function compress ( message ) {
2012-04-23 16:30:02 +02:00
return Base64 . toBase64 ( RawDeflate . deflate ( Base64 . utob ( message ) ) ) ;
2012-04-22 12:45:45 +02:00
}
2012-04-21 21:59:45 +02:00
2012-04-22 12:45:45 +02:00
/ * *
* Decompress a message compressed with compress ( ) .
* /
function decompress ( data ) {
2012-04-23 16:30:02 +02:00
return Base64 . btou ( RawDeflate . inflate ( Base64 . fromBase64 ( data ) ) ) ;
2012-04-22 12:45:45 +02:00
}
/ * *
* Compress , then encrypt message with key .
2012-04-23 16:30:02 +02:00
*
2012-04-22 12:45:45 +02:00
* @ param string key
* @ param string message
* @ return encrypted string data
* /
function zeroCipher ( key , message ) {
2015-08-31 21:14:12 +02:00
if ( $ ( '#passwordinput' ) . val ( ) . length == 0 ) {
2015-08-22 17:23:41 +02:00
return sjcl . encrypt ( key , compress ( message ) ) ;
}
2015-08-31 21:14:12 +02:00
return sjcl . encrypt ( key + sjcl . codec . hex . fromBits ( sjcl . hash . sha256 . hash ( $ ( "#passwordinput" ) . val ( ) ) ) , compress ( message ) ) ;
2012-04-21 21:59:45 +02:00
}
2013-02-23 15:11:45 +01:00
2012-04-22 12:45:45 +02:00
/ * *
2015-08-31 21:14:12 +02:00
* Decrypt message with key , then decompress .
2012-04-23 16:30:02 +02:00
*
2015-08-31 21:14:12 +02:00
* @ param string key
* @ param encrypted string data
* @ return string readable message
2012-04-22 12:45:45 +02:00
* /
function zeroDecipher ( key , data ) {
2015-08-22 17:23:41 +02:00
if ( data != undefined ) {
try {
return decompress ( sjcl . decrypt ( key , data ) ) ;
} catch ( err ) {
2015-08-31 21:14:12 +02:00
try {
if ( $ ( '#passwordinput' ) . val ( ) . length > 0 ) {
password = $ ( '#passwordinput' ) . val ( ) ;
} else {
password = prompt ( "Please enter the password for this paste:" , "" ) ;
if ( password == null ) return null ;
}
data = decompress ( sjcl . decrypt ( key + sjcl . codec . hex . fromBits ( sjcl . hash . sha256 . hash ( password ) ) , data ) ) ;
$ ( '#passwordinput' ) . val ( password ) ;
return data ;
} catch ( err ) {
return zeroDecipher ( key , data ) ;
}
2015-08-22 17:23:41 +02:00
}
}
2012-04-21 21:59:45 +02:00
}
2012-04-22 12:45:45 +02:00
/ * *
2015-08-31 21:14:12 +02:00
* Get the current script location ( without search or hash part of the URL ) .
* eg . http : //server.com/zero/?aaaa#bbbb --> http://server.com/zero/
*
* @ return string current script location
2012-04-22 12:45:45 +02:00
* /
function scriptLocation ( ) {
2012-07-28 21:35:14 +02:00
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 ) {
2015-08-31 21:14:12 +02:00
scriptLocation = scriptLocation . substring ( 0 , hashIndex ) ;
2012-07-28 21:35:14 +02:00
}
2015-08-31 21:14:12 +02:00
return scriptLocation ;
2012-04-21 21:59:45 +02:00
}
2012-04-23 16:30:02 +02:00
/ * *
2015-08-31 21:14:12 +02:00
* Get the pastes unique identifier from the URL
* eg . http : //server.com/zero/?c05354954c49a487#xxx --> c05354954c49a487
*
* @ return string unique identifier
2012-04-22 12:45:45 +02:00
* /
function pasteID ( ) {
2012-04-21 21:59:45 +02:00
return window . location . search . substring ( 1 ) ;
}
2015-08-31 21:14:12 +02:00
/ * *
* Convert all applicable characters to HTML entities
*
* @ param string str
* @ returns string encoded string
* /
2013-07-05 01:14:23 +02:00
function htmlEntities ( str ) {
return String ( str ) . replace ( /&/g , '&' ) . replace ( /</g , '<' ) . replace ( />/g , '>' ) . replace ( /"/g , '"' ) ;
}
2012-04-22 12:45:45 +02:00
/ * *
* Set text of a DOM element ( required for IE )
* This is equivalent to element . text ( text )
2015-08-31 21:14:12 +02:00
*
2012-04-22 12:45:45 +02:00
* @ param object element : a DOM element .
* @ param string text : the text to enter .
* /
function setElementText ( element , text ) {
// For IE<10.
2015-08-17 23:19:15 +02:00
if ( $ ( '#oldienotice' ) . is ( ":visible" ) ) {
2013-02-24 21:59:10 +01:00
// IE<10 does not support white-space:pre-wrap; so we have to do this BIG UGLY STINKING THING.
2013-07-05 01:14:23 +02:00
var html = htmlEntities ( text ) . replace ( /\n/ig , "\r\n<br>" ) ;
element . html ( '<pre>' + html + '</pre>' ) ;
2012-04-21 21:59:45 +02:00
}
2012-04-22 12:45:45 +02:00
// for other (sane) browsers:
else {
2012-04-21 21:59:45 +02:00
element . text ( text ) ;
}
}
2012-04-22 12:45:45 +02:00
/ * *
* Show decrypted text in the display area , including discussion ( if open )
2012-04-23 16:30:02 +02:00
*
2012-04-22 12:45:45 +02:00
* @ param string key : decryption key
* @ param array comments : Array of messages to display ( items = array with keys ( 'data' , 'meta' )
* /
function displayMessages ( key , comments ) {
2012-04-21 21:59:45 +02:00
try { // Try to decrypt the paste.
2012-04-23 16:30:02 +02:00
var cleartext = zeroDecipher ( key , comments [ 0 ] . data ) ;
2015-08-31 21:14:12 +02:00
if ( cleartext == null ) throw "password prompt canceled" ;
2012-04-23 16:30:02 +02:00
} catch ( err ) {
2015-08-17 23:19:15 +02:00
$ ( '#cleartext' ) . addClass ( 'hidden' ) ;
$ ( '#prettymessage' ) . addClass ( 'hidden' ) ;
$ ( '#clonebutton' ) . addClass ( 'hidden' ) ;
2012-04-23 16:30:02 +02:00
showError ( 'Could not decrypt data (Wrong key ?)' ) ;
2012-04-21 21:59:45 +02:00
return ;
}
2015-08-17 23:19:15 +02:00
setElementText ( $ ( '#cleartext' ) , cleartext ) ;
setElementText ( $ ( '#prettyprint' ) , cleartext ) ;
2015-08-27 23:58:28 +02:00
// Convert URLs to clickable links.
urls2links ( $ ( '#cleartext' ) ) ;
urls2links ( $ ( '#prettyprint' ) ) ;
if ( typeof prettyPrint == 'function' ) prettyPrint ( ) ;
2012-04-23 16:30:02 +02:00
2012-04-21 21:59:45 +02:00
// Display paste expiration.
2015-08-17 23:19:15 +02:00
if ( comments [ 0 ] . meta . expire _date ) $ ( '#remainingtime' ) . removeClass ( 'foryoureyesonly' ) . text ( 'This document will expire in ' + secondsToHuman ( comments [ 0 ] . meta . remaining _time ) + '.' ) . removeClass ( 'hidden' ) ;
2012-04-22 12:45:45 +02:00
if ( comments [ 0 ] . meta . burnafterreading ) {
2015-08-31 22:10:41 +02:00
$ . get ( scriptLocation ( ) + "?pasteid=" + pasteID ( ) + '&deletetoken=burnafterreading' , 'json' )
. fail ( function ( ) {
showError ( 'Could not delete the paste, it was not stored in burn after reading mode.' ) ;
} ) ;
2015-08-17 23:19:15 +02:00
$ ( '#remainingtime' ) . addClass ( 'foryoureyesonly' ) . text ( 'FOR YOUR EYES ONLY. Don\'t close this window, this message can\'t be displayed again.' ) . removeClass ( 'hidden' ) ;
$ ( '#clonebutton' ) . addClass ( 'hidden' ) ; // Discourage cloning (as it can't really be prevented).
2012-04-21 21:59:45 +02:00
}
2012-04-23 16:30:02 +02:00
// If the discussion is opened on this paste, display it.
2012-04-22 12:45:45 +02:00
if ( comments [ 0 ] . meta . opendiscussion ) {
2015-08-17 23:19:15 +02:00
$ ( '#comments' ) . html ( '' ) ;
2015-08-31 21:14:12 +02:00
// iterate over comments
2012-04-22 12:45:45 +02:00
for ( var i = 1 ; i < comments . length ; i ++ ) {
2012-04-23 16:30:02 +02:00
var comment = comments [ i ] ;
var cleartext = "[Could not decrypt comment ; Wrong key ?]" ;
2012-04-22 12:45:45 +02:00
try {
2012-04-23 16:30:02 +02:00
cleartext = zeroDecipher ( key , comment . data ) ;
} catch ( err ) { }
2015-08-17 23:19:15 +02:00
var place = $ ( '#comments' ) ;
2012-04-21 21:59:45 +02:00
// If parent comment exists, display below (CSS will automatically shift it right.)
2015-08-31 21:14:12 +02:00
var cname = '#comment_' + comment . meta . parentid ;
2012-04-23 16:30:02 +02:00
2012-04-22 12:45:45 +02:00
// If the element exists in page
if ( $ ( cname ) . length ) {
place = $ ( cname ) ;
}
2012-08-26 00:49:11 +02:00
var divComment = $ ( '<article><div class="comment" id="comment_' + comment . meta . commentid + '">'
2012-04-22 12:45:45 +02:00
+ '<div class="commentmeta"><span class="nickname"></span><span class="commentdate"></span></div><div class="commentdata"></div>'
2015-08-23 15:49:51 +02:00
+ '<button onclick="open_reply($(this),\'' + comment . meta . commentid + '\');return false;" class="btn btn-default">Reply</button>'
2012-08-26 00:49:11 +02:00
+ '</div></article>' ) ;
2012-04-22 12:45:45 +02:00
setElementText ( divComment . find ( 'div.commentdata' ) , cleartext ) ;
// Convert URLs to clickable links in comment.
urls2links ( divComment . find ( 'div.commentdata' ) ) ;
2012-04-21 21:59:45 +02:00
divComment . find ( 'span.nickname' ) . html ( '<i>(Anonymous)</i>' ) ;
2012-04-23 16:30:02 +02:00
2012-04-21 21:59:45 +02:00
// Try to get optional nickname:
2012-04-23 16:30:02 +02:00
try {
2012-04-22 12:45:45 +02:00
divComment . find ( 'span.nickname' ) . text ( zeroDecipher ( key , comment . meta . nickname ) ) ;
2012-04-23 16:30:02 +02:00
} catch ( err ) { }
2012-04-30 22:58:08 +02:00
divComment . find ( 'span.commentdate' ) . text ( ' (' + ( new Date ( comment . meta . postdate * 1000 ) . toString ( ) ) + ')' ) . attr ( 'title' , 'CommentID: ' + comment . meta . commentid ) ;
2012-04-23 16:30:02 +02:00
2012-04-21 21:59:45 +02:00
// If an avatar is available, display it.
2012-04-22 12:45:45 +02:00
if ( comment . meta . vizhash ) {
2015-08-31 21:14:12 +02:00
divComment . find ( 'span.nickname' ) . before ( '<img src="' + comment . meta . vizhash + '" class="vizhash" title="Anonymous avatar (Vizhash of the IP address)" /> ' ) ;
2012-04-22 12:45:45 +02:00
}
2012-04-23 16:30:02 +02:00
2012-04-21 21:59:45 +02:00
place . append ( divComment ) ;
}
2015-08-23 15:49:51 +02:00
$ ( '#comments' ) . append ( '<div class="comment"><button onclick="open_reply($(this),\'' + pasteID ( ) + '\');return false;" class="btn btn-default">Add comment</button></div>' ) ;
2015-08-17 23:19:15 +02:00
$ ( '#discussion' ) . removeClass ( 'hidden' ) ;
2012-04-21 21:59:45 +02:00
}
}
2012-04-22 12:45:45 +02:00
/ * *
* Open the comment entry when clicking the "Reply" button of a comment .
2015-08-31 21:14:12 +02:00
*
2012-04-22 12:45:45 +02:00
* @ param object source : element which emitted the event .
* @ param string commentid = identifier of the comment we want to reply to .
* /
function open _reply ( source , commentid ) {
2012-04-21 21:59:45 +02:00
$ ( 'div.reply' ) . remove ( ) ; // Remove any other reply area.
source . after ( '<div class="reply">'
2015-08-23 15:49:51 +02:00
+ '<input type="text" id="nickname" class="form-control" title="Optional nickname..." value="Optional nickname..." />'
+ '<textarea id="replymessage" class="replymessage form-control" cols="80" rows="7"></textarea>'
+ '<br /><button id="replybutton" onclick="send_comment(\'' + commentid + '\');return false;" class="btn btn-default">Post comment</button>'
2012-08-26 00:49:11 +02:00
+ '<div id="replystatus"> </div>'
2012-04-22 12:45:45 +02:00
+ '</div>' ) ;
2015-08-17 23:19:15 +02:00
$ ( '#nickname' ) . focus ( function ( ) {
2012-04-22 12:45:45 +02:00
if ( $ ( this ) . val ( ) == $ ( this ) . attr ( 'title' ) ) {
$ ( this ) . val ( '' ) ;
}
2012-04-23 16:30:02 +02:00
} ) ;
2015-08-17 23:19:15 +02:00
$ ( '#replymessage' ) . focus ( ) ;
2012-04-21 21:59:45 +02:00
}
2012-04-22 12:45:45 +02:00
/ * *
* Send a reply in a discussion .
2015-08-31 21:14:12 +02:00
*
2012-04-22 12:45:45 +02:00
* @ param string parentid : the comment identifier we want to send a reply to .
* /
function send _comment ( parentid ) {
// Do not send if no data.
2015-08-17 23:19:15 +02:00
if ( $ ( '#replymessage' ) . val ( ) . length == 0 ) {
2012-04-22 12:45:45 +02:00
return ;
}
2012-04-23 16:30:02 +02:00
showStatus ( 'Sending comment...' , spin = true ) ;
2015-08-17 23:19:15 +02:00
var cipherdata = zeroCipher ( pageKey ( ) , $ ( '#replymessage' ) . val ( ) ) ;
2012-04-22 12:45:45 +02:00
var ciphernickname = '' ;
2015-09-01 22:33:07 +02:00
var nick = $ ( '#nickname' ) . val ( ) ;
2012-04-22 12:45:45 +02:00
if ( nick != '' && nick != 'Optional nickname...' ) {
2012-04-22 20:43:11 +02:00
ciphernickname = zeroCipher ( pageKey ( ) , nick ) ;
2012-04-22 12:45:45 +02:00
}
var data _to _send = { data : cipherdata ,
parentid : parentid ,
pasteid : pasteID ( ) ,
nickname : ciphernickname
} ;
2012-04-21 21:59:45 +02:00
2015-09-01 22:33:07 +02:00
$ . post ( scriptLocation ( ) , data _to _send , function ( data ) {
2013-02-23 15:11:45 +01:00
if ( data . status == 0 ) {
showStatus ( 'Comment posted.' ) ;
2015-09-01 22:33:07 +02:00
$ . get ( scriptLocation ( ) + "?" + pasteID ( ) + "&json" , function ( data ) {
if ( data . status == 0 ) {
displayMessages ( pageKey ( ) , data . messages ) ;
}
else if ( data . status == 1 ) {
showError ( 'Could not refresh display: ' + data . message ) ;
}
else
{
showError ( 'Could not refresh display: unknown status' ) ;
}
} , 'json' )
. fail ( function ( ) {
showError ( 'Could not refresh display (server error or not responding).' ) ;
} ) ;
2013-02-23 15:11:45 +01:00
}
2015-09-01 22:33:07 +02:00
else if ( data . status == 1 ) {
showError ( 'Could not post comment: ' + data . message ) ;
2013-02-23 15:11:45 +01:00
}
2015-09-01 22:33:07 +02:00
else
{
showError ( 'Could not post comment: unknown status' ) ;
2013-02-23 15:11:45 +01:00
}
2015-09-01 22:33:07 +02:00
} , 'json' )
. fail ( function ( ) {
showError ( 'Comment could not be sent (server error or not responding).' ) ;
2013-02-23 15:11:45 +01:00
} ) ;
}
2012-04-22 12:45:45 +02:00
/ * *
2015-08-31 21:14:12 +02:00
* Send a new paste to server
2012-04-22 12:45:45 +02:00
* /
function send _data ( ) {
// Do not send if no data.
2015-08-17 23:19:15 +02:00
if ( $ ( '#message' ) . val ( ) . length == 0 ) {
2012-04-22 12:45:45 +02:00
return ;
}
2013-02-24 21:59:10 +01:00
// 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 ) ;
2015-08-16 11:20:06 +02:00
sjcl . random . addEventListener ( 'seeded' , function ( ) { send _data ( ) ; } ) ;
2015-08-22 17:23:41 +02:00
return ;
2013-02-24 21:59:10 +01:00
}
2015-08-22 17:23:41 +02:00
2012-04-23 16:30:02 +02:00
showStatus ( 'Sending paste...' , spin = true ) ;
2013-02-24 21:59:10 +01:00
2012-04-22 12:45:45 +02:00
var randomkey = sjcl . codec . base64 . fromBits ( sjcl . random . randomWords ( 8 , 0 ) , 0 ) ;
2015-08-17 23:19:15 +02:00
var cipherdata = zeroCipher ( randomkey , $ ( '#message' ) . val ( ) ) ;
2012-04-22 12:45:45 +02:00
var data _to _send = { data : cipherdata ,
2015-08-17 23:19:15 +02:00
expire : $ ( '#pasteExpiration' ) . val ( ) ,
burnafterreading : $ ( '#burnafterreading' ) . is ( ':checked' ) ? 1 : 0 ,
opendiscussion : $ ( '#opendiscussion' ) . is ( ':checked' ) ? 1 : 0
2012-04-23 16:30:02 +02:00
} ;
2015-08-31 22:10:41 +02:00
$ . post ( scriptLocation ( ) , data _to _send , function ( data ) {
2013-02-23 15:11:45 +01:00
if ( data . status == 0 ) {
stateExistingPaste ( ) ;
var url = scriptLocation ( ) + "?" + data . id + '#' + randomkey ;
var deleteUrl = scriptLocation ( ) + "?pasteid=" + data . id + '&deletetoken=' + data . deletetoken ;
showStatus ( '' ) ;
2013-11-01 01:15:14 +01:00
2015-08-17 23:19:15 +02:00
$ ( '#pastelink' ) . html ( 'Your paste is <a id="pasteurl" href="' + url + '">' + url + '</a> <span id="copyhint">(Hit CTRL+C to copy)</span>' ) ;
$ ( '#deletelink' ) . html ( '<a href="' + deleteUrl + '">Delete data</a>' ) ;
$ ( '#pasteresult' ) . removeClass ( 'hidden' ) ;
2013-02-23 15:11:45 +01:00
selectText ( 'pasteurl' ) ; // We pre-select the link so that the user only has to CTRL+C the link.
2013-11-01 01:15:14 +01:00
2015-08-17 23:19:15 +02:00
setElementText ( $ ( '#cleartext' ) , $ ( '#message' ) . val ( ) ) ;
setElementText ( $ ( '#prettyprint' ) , $ ( '#message' ) . val ( ) ) ;
2015-08-27 23:58:28 +02:00
// Convert URLs to clickable links.
2015-08-17 23:19:15 +02:00
urls2links ( $ ( '#cleartext' ) ) ;
2015-08-27 23:58:28 +02:00
urls2links ( $ ( '#prettyprint' ) ) ;
2013-02-23 15:11:45 +01:00
showStatus ( '' ) ;
2015-08-27 23:58:28 +02:00
if ( typeof prettyPrint == 'function' ) prettyPrint ( ) ;
2013-02-23 15:11:45 +01:00
}
else if ( data . status == 1 ) {
2015-09-01 22:33:07 +02:00
showError ( 'Could not create paste: ' + data . message ) ;
2013-02-23 15:11:45 +01:00
}
else {
showError ( 'Could not create paste.' ) ;
}
2015-08-31 22:10:41 +02:00
} , 'json' )
. fail ( function ( ) {
showError ( 'Data could not be sent (server error or not responding).' ) ;
2013-02-23 15:11:45 +01:00
} ) ;
}
2015-08-31 21:14:12 +02:00
/ * *
* Text range selection .
* From : http : //stackoverflow.com/questions/985272/jquery-selecting-text-in-an-element-akin-to-highlighting-with-your-mouse
*
* @ param string element : Indentifier of the element to select ( id = "" ) .
2013-02-23 15:11:45 +01:00
* /
function selectText ( element ) {
var doc = document
, text = doc . getElementById ( element )
, range , selection
2015-08-16 11:20:06 +02:00
;
2015-08-31 21:14:12 +02:00
if ( doc . body . createTextRange ) { // MS
2013-02-23 15:11:45 +01:00
range = doc . body . createTextRange ( ) ;
range . moveToElementText ( text ) ;
range . select ( ) ;
2015-08-31 21:14:12 +02:00
} else if ( window . getSelection ) { // all others
2015-08-22 17:23:41 +02:00
selection = window . getSelection ( ) ;
2013-02-23 15:11:45 +01:00
range = doc . createRange ( ) ;
range . selectNodeContents ( text ) ;
selection . removeAllRanges ( ) ;
selection . addRange ( range ) ;
}
2012-04-21 21:59:45 +02:00
}
2012-04-22 12:45:45 +02:00
/ * *
* Put the screen in "New paste" mode .
* /
function stateNewPaste ( ) {
2015-08-17 23:19:15 +02:00
$ ( '#sendbutton' ) . removeClass ( 'hidden' ) ;
$ ( '#clonebutton' ) . addClass ( 'hidden' ) ;
$ ( '#rawtextbutton' ) . addClass ( 'hidden' ) ;
$ ( '#expiration' ) . removeClass ( 'hidden' ) ;
$ ( '#remainingtime' ) . addClass ( 'hidden' ) ;
$ ( '#burnafterreadingoption' ) . removeClass ( 'hidden' ) ;
$ ( '#opendisc' ) . removeClass ( 'hidden' ) ;
$ ( '#newbutton' ) . removeClass ( 'hidden' ) ;
$ ( '#pasteresult' ) . addClass ( 'hidden' ) ;
$ ( '#message' ) . text ( '' ) ;
$ ( '#message' ) . removeClass ( 'hidden' ) ;
$ ( '#cleartext' ) . addClass ( 'hidden' ) ;
$ ( '#message' ) . focus ( ) ;
$ ( '#discussion' ) . addClass ( 'hidden' ) ;
$ ( '#prettymessage' ) . addClass ( 'hidden' ) ;
2015-08-30 14:33:09 +02:00
// Show password field
2015-08-31 00:01:35 +02:00
$ ( '#password' ) . removeClass ( 'hidden' ) ;
2012-04-21 21:59:45 +02:00
}
2012-04-22 12:45:45 +02:00
/ * *
* Put the screen in "Existing paste" mode .
* /
function stateExistingPaste ( ) {
2015-08-17 23:19:15 +02:00
$ ( '#sendbutton' ) . addClass ( 'hidden' ) ;
2012-04-23 16:30:02 +02:00
2012-04-22 12:45:45 +02:00
// No "clone" for IE<10.
2015-08-17 23:19:15 +02:00
if ( $ ( '#oldienotice' ) . is ( ":visible" ) ) {
$ ( '#clonebutton' ) . addClass ( 'hidden' ) ;
2012-04-22 20:43:11 +02:00
}
else {
2015-08-17 23:19:15 +02:00
$ ( '#clonebutton' ) . removeClass ( 'hidden' ) ;
2012-04-22 12:45:45 +02:00
}
2015-08-17 23:19:15 +02:00
$ ( '#rawtextbutton' ) . removeClass ( 'hidden' ) ;
$ ( '#expiration' ) . addClass ( 'hidden' ) ;
$ ( '#burnafterreadingoption' ) . addClass ( 'hidden' ) ;
$ ( '#opendisc' ) . addClass ( 'hidden' ) ;
$ ( '#newbutton' ) . removeClass ( 'hidden' ) ;
$ ( '#pasteresult' ) . addClass ( 'hidden' ) ;
$ ( '#message' ) . addClass ( 'hidden' ) ;
$ ( '#cleartext' ) . addClass ( 'hidden' ) ;
$ ( '#prettymessage' ) . removeClass ( 'hidden' ) ;
2012-04-21 21:59:45 +02:00
}
2015-08-31 21:14:12 +02:00
/ * *
* Return raw text
* /
2013-02-24 16:29:13 +01:00
function rawText ( )
{
2015-08-17 23:19:15 +02:00
var paste = $ ( '#cleartext' ) . html ( ) ;
2014-01-20 21:06:31 +01:00
var newDoc = document . open ( 'text/html' , 'replace' ) ;
newDoc . write ( '<pre>' + paste + '</pre>' ) ;
2013-02-24 16:29:13 +01:00
newDoc . close ( ) ;
}
2012-04-22 12:45:45 +02:00
/ * *
* Clone the current paste .
* /
function clonePaste ( ) {
2012-04-21 21:59:45 +02:00
stateNewPaste ( ) ;
2015-08-30 14:33:09 +02:00
2012-05-10 20:35:33 +02:00
//Erase the id and the key in url
history . replaceState ( document . title , document . title , scriptLocation ( ) ) ;
2015-08-30 14:33:09 +02:00
2012-04-21 21:59:45 +02:00
showStatus ( '' ) ;
2015-08-17 23:19:15 +02:00
$ ( '#message' ) . text ( $ ( '#cleartext' ) . text ( ) ) ;
2012-04-21 21:59:45 +02:00
}
2012-04-22 12:45:45 +02:00
/ * *
* Create a new paste .
* /
function newPaste ( ) {
2012-04-21 21:59:45 +02:00
stateNewPaste ( ) ;
showStatus ( '' ) ;
2015-08-17 23:19:15 +02:00
$ ( '#message' ) . text ( '' ) ;
2012-04-21 21:59:45 +02:00
}
2012-04-22 12:45:45 +02:00
/ * *
* Display an error message
* ( We use the same function for paste and reply to comments )
* /
function showError ( message ) {
2015-08-31 21:14:12 +02:00
if ( $ ( '#status' ) . length ) {
$ ( '#status' ) . addClass ( 'errorMessage' ) . text ( message ) ;
} else {
$ ( '#errormessage' ) . removeClass ( 'hidden' ) . append ( message ) ;
}
2015-08-17 23:19:15 +02:00
$ ( '#replystatus' ) . addClass ( 'errorMessage' ) . text ( message ) ;
2012-04-21 21:59:45 +02:00
}
2012-04-22 12:45:45 +02:00
/ * *
* Display status
* ( We use the same function for paste and reply to comments )
2012-04-23 16:30:02 +02:00
*
2012-04-22 12:45:45 +02:00
* @ param string message : text to display
* @ param boolean spin ( optional ) : tell if the "spinning" animation should be displayed .
* /
function showStatus ( message , spin ) {
2015-08-17 23:19:15 +02:00
$ ( '#replystatus' ) . removeClass ( 'errorMessage' ) ;
$ ( '#replystatus' ) . text ( message ) ;
2012-04-23 16:30:02 +02:00
if ( ! message ) {
2015-08-17 23:19:15 +02:00
$ ( '#status' ) . html ( ' ' ) ;
2012-04-22 12:45:45 +02:00
return ;
}
if ( message == '' ) {
2015-08-17 23:19:15 +02:00
$ ( '#status' ) . html ( ' ' ) ;
2012-04-23 16:30:02 +02:00
return ;
2012-04-22 12:45:45 +02:00
}
2015-08-17 23:19:15 +02:00
$ ( '#status' ) . removeClass ( 'errorMessage' ) ;
$ ( '#status' ) . text ( message ) ;
2012-04-22 12:45:45 +02:00
if ( spin ) {
var img = '<img src="img/busy.gif" style="width:16px;height:9px;margin:0px 4px 0px 0px;" />' ;
2015-08-17 23:19:15 +02:00
$ ( '#status' ) . prepend ( img ) ;
$ ( '#replystatus' ) . prepend ( img ) ;
2012-04-21 21:59:45 +02:00
}
}
2012-04-22 12:45:45 +02:00
/ * *
* Convert URLs to clickable links .
* URLs to handle :
* < code >
* magnet : ? xt . 1 = urn : sha1 : YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C & xt . 2 = urn : sha1 : TXGCZQTH26NL6OUQAJJPFALHG2LTGBC7
* http : //localhost:8800/zero/?6f09182b8ea51997#WtLEUO5Epj9UHAV9JFs+6pUQZp13TuspAUjnF+iM+dM=
* http : //user:password@localhost:8800/zero/?6f09182b8ea51997#WtLEUO5Epj9UHAV9JFs+6pUQZp13TuspAUjnF+iM+dM=
* < / c o d e >
2012-04-23 16:30:02 +02:00
*
2012-04-22 12:45:45 +02:00
* @ param object element : a jQuery DOM element .
* /
function urls2links ( element ) {
2012-04-21 21:59:45 +02:00
var re = /((http|https|ftp):\/\/[\w?=&.\/-;#@~%+-]+(?![\w\s?&.\/;#~%"=-]*>))/ig ;
element . html ( element . html ( ) . replace ( re , '<a href="$1" rel="nofollow">$1</a>' ) ) ;
var re = /((magnet):[\w?=&.\/-;#@~%+-]+)/ig ;
element . html ( element . html ( ) . replace ( re , '<a href="$1">$1</a>' ) ) ;
}
2012-04-22 12:45:45 +02:00
/ * *
* Return the deciphering key stored in anchor part of the URL
* /
function pageKey ( ) {
2012-04-21 21:59:45 +02:00
var key = window . location . hash . substring ( 1 ) ; // Get key
2012-04-23 16:30:02 +02:00
2012-04-21 21:59:45 +02:00
// Some stupid web 2.0 services and redirectors add data AFTER the anchor
// (such as &utm_source=...).
// We will strip any additional data.
2012-04-23 16:30:02 +02:00
2012-04-21 21:59:45 +02:00
// 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 ) ; }
2012-04-23 16:30:02 +02:00
2012-04-21 21:59:45 +02:00
// If the equal sign was not present, some parameters may remain:
i = key . indexOf ( '&' ) ; if ( i > - 1 ) { key = key . substring ( 0 , i ) ; }
2012-04-23 16:30:02 +02:00
2012-04-21 21:59:45 +02:00
// Then add trailing equal sign if it's missing
if ( key . charAt ( key . length - 1 ) !== '=' ) key += '=' ;
return key ;
}
2015-08-31 21:14:12 +02:00
/ * *
* main application start , called when DOM is fully loaded
* /
2012-04-22 12:45:45 +02:00
$ ( function ( ) {
2012-08-26 00:49:11 +02:00
// hide "no javascript" message
$ ( '#noscript' ) . hide ( ) ;
2013-02-24 14:33:51 +01:00
// If "burn after reading" is checked, disable discussion.
2015-08-17 23:19:15 +02:00
$ ( '#burnafterreading' ) . change ( function ( ) {
2015-08-16 11:20:06 +02:00
if ( $ ( this ) . is ( ':checked' ) ) {
2015-08-17 23:19:15 +02:00
$ ( '#opendisc' ) . addClass ( 'buttondisabled' ) ;
$ ( '#opendiscussion' ) . attr ( { checked : false } ) ;
$ ( '#opendiscussion' ) . attr ( 'disabled' , true ) ;
2012-04-22 12:45:45 +02:00
}
else {
2015-08-17 23:19:15 +02:00
$ ( '#opendisc' ) . removeClass ( 'buttondisabled' ) ;
$ ( '#opendiscussion' ) . removeAttr ( 'disabled' ) ;
2012-04-22 12:45:45 +02:00
}
2012-04-21 21:59:45 +02:00
} ) ;
2013-11-01 01:15:14 +01:00
// Display status returned by php code if any (eg. Paste was properly deleted.)
2015-08-17 23:19:15 +02:00
if ( $ ( '#status' ) . text ( ) . length > 0 ) {
showStatus ( $ ( '#status' ) . text ( ) , false ) ;
2013-11-01 01:15:14 +01:00
return ;
}
2015-08-17 23:19:15 +02:00
$ ( '#status' ) . html ( ' ' ) ; // Keep line height even if content empty.
2013-11-01 01:15:14 +01:00
2012-04-22 12:45:45 +02:00
// Display an existing paste
2015-08-17 23:19:15 +02:00
if ( $ ( '#cipherdata' ) . text ( ) . length > 1 ) {
2012-04-23 16:30:02 +02:00
// Missing decryption key in URL ?
2012-04-22 12:45:45 +02:00
if ( window . location . hash . length == 0 ) {
2012-04-21 21:59:45 +02:00
showError ( 'Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL ?)' ) ;
return ;
}
2012-04-23 16:30:02 +02:00
2012-04-22 12:45:45 +02:00
// List of messages to display
2015-08-17 23:19:15 +02:00
var messages = jQuery . parseJSON ( $ ( '#cipherdata' ) . text ( ) ) ;
2012-04-23 16:30:02 +02:00
// Show proper elements on screen.
2012-04-22 12:45:45 +02:00
stateExistingPaste ( ) ;
2012-04-23 16:30:02 +02:00
2012-04-22 12:45:45 +02:00
displayMessages ( pageKey ( ) , messages ) ;
2012-04-21 21:59:45 +02:00
}
2012-04-22 12:45:45 +02:00
// Display error message from php code.
2015-08-17 23:19:15 +02:00
else if ( $ ( '#errormessage' ) . text ( ) . length > 1 ) {
showError ( $ ( '#errormessage' ) . text ( ) ) ;
2012-04-21 21:59:45 +02:00
}
2012-04-22 12:45:45 +02:00
// Create a new paste.
else {
2012-04-21 21:59:45 +02:00
newPaste ( ) ;
}
} ) ;