1
0
mirror of https://github.com/Tygs/0bin.git synced 2023-08-10 21:13:00 +03:00

Loading bar works and encryption/decryption is now a serie of continuations

This commit is contained in:
sam 2012-04-30 00:50:39 +07:00
parent e34e740808
commit 65d75f2faf
5 changed files with 253 additions and 84 deletions

View File

@ -165,3 +165,20 @@ text-decoration:underline;
display:none; display:none;
} }
/** Progress bar */
.progress {
display:none;
}
.progress .bar {
width: 25%;
text-indent: 10px;
text-align:left;
}
-webkit-transition: width 0.1s ease;
-moz-transition: width 0.1s ease;
-ms-transition: width 0.1s ease;
-o-transition: width 0.1s ease;
transition: width 0.1s ease;

View File

@ -5,24 +5,119 @@ sjcl.random.startCollectors();
/* Ensure jquery use cache for ajax requests */ /* Ensure jquery use cache for ajax requests */
$.ajaxSetup({ cache: true }); $.ajaxSetup({ cache: true });
zerobin = { zerobin = {
encrypt: function(key, content) {
content = sjcl.codec.base64.fromBits(sjcl.codec.utf8String.toBits(content)); /** Base64 + compress + encrypt, with callbacks before each operation,
return sjcl.encrypt(key, lzw.compress(content)); and all of them are executed in a timed continuation to give
a change to the UI to respond.
*/
encrypt: function(key, content, toBase64Callback,
compressCallback, encryptCallback, doneCallback) {
setTimeout (function(){
content = sjcl.codec.utf8String.toBits(content);
if (toBase64Callback) {toBase64Callback()}
setTimeout(function(){
content = sjcl.codec.base64.fromBits(content);
if (compressCallback) {compressCallback()}
setTimeout(function(){
content = lzw.compress(content);
if (encryptCallback) {encryptCallback()}
setTimeout(function(){
content = sjcl.encrypt(key, content);
if (doneCallback) {doneCallback(content)}
}, 250);
}, 250);
}, 250);
}, 250);
}, },
decrypt: function(key, content) {
content = lzw.decompress(sjcl.decrypt(key, content)); /** Base64 decoding + uncompress + decrypt, with callbacks before each operation,
return sjcl.codec.utf8String.fromBits(sjcl.codec.base64.toBits(content)); and all of them are executed in a timed continuation to give
a change to the UI to respond.
This is where using a library to fake synchronicity could start to be
useful, this code is starting be difficult to read. If anyone read this
and got a suggestion, by all means, speak your mind.
*/
decrypt: function(key, content, errorCallback, uncompressCallback,
fromBase64Callback, toStringCallback, doneCallback) {
/* Decrypt */
setTimeout(function(){
try {
content = sjcl.decrypt(key, content);
if (uncompressCallback) {uncompressCallback()}
/* Decompress */
setTimeout(function(){
try {
content = lzw.decompress(content);
if (fromBase64Callback) {fromBase64Callback()}
/* From base 64 to bits */
setTimeout(function(){
try {
content = sjcl.codec.base64.toBits(content);
if (toStringCallback) {toStringCallback()}
/* From bits to string */
setTimeout(function(){
try {
content = sjcl.codec.utf8String.fromBits(content);
if (doneCallback) {doneCallback(content)}
} catch (err) {
errorCallback(err);
}
}, 250); /* "End of from bits to string" */
} catch (err) {
errorCallback(err);
}
}, 250); /* End of "from base 64 to bits" */
} catch (err) {
errorCallback(err);
}
}, 250); /* End of "decompress" */
} catch (err) {
errorCallback(err);
}
}, 250); /* End of "decrypt" */
}, },
/** Create a random base64 string long enought to be suitable as
an encryption key */
make_key: function() { make_key: function() {
return sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0); return sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0);
}, },
get_date: function(){ get_date: function(){
var date = new Date(); var date = new Date();
return date.getDate()+"-"+(date.getMonth()+1)+"-"+date.getFullYear(); return date.getDate()+"-"+(date.getMonth()+1)+"-"+date.getFullYear();
}, },
get_time: function(){ get_time: function(){
var date = new Date(); var date = new Date();
var h=date.getHours(); var h=date.getHours();
@ -33,9 +128,11 @@ zerobin = {
if (s<10) {s = "0" + s} if (s<10) {s = "0" + s}
return h+":"+m+":"+s; return h+":"+m+":"+s;
}, },
numOrdA: function(a, b){
return (a-b); numOrdA: function(a, b){
return (a-b);
}, },
get_keys: function(){ get_keys: function(){
var keys = new Array(); var keys = new Array();
for(i=0; i<=localStorage.length; i++){ for(i=0; i<=localStorage.length; i++){
@ -44,6 +141,7 @@ zerobin = {
} }
return keys.sort(zerobin.numOrdA); return keys.sort(zerobin.numOrdA);
}, },
/** Get a tinyurl using JSONP */ /** Get a tinyurl using JSONP */
getTinyURL: function(longURL, success) { getTinyURL: function(longURL, success) {
@ -56,6 +154,7 @@ zerobin = {
var api = 'http://json-tinyurl.appspot.com/?url='; var api = 'http://json-tinyurl.appspot.com/?url=';
$.getJSON(api + encodeURIComponent(longURL) + '&callback=' + callback); $.getJSON(api + encodeURIComponent(longURL) + '&callback=' + callback);
}, },
support_localstorage: function(){ support_localstorage: function(){
if (localStorage){ if (localStorage){
return true; return true;
@ -63,6 +162,7 @@ zerobin = {
return false; return false;
} }
}, },
store_paste: function(url){ store_paste: function(url){
if (zerobin.support_localstorage){ if (zerobin.support_localstorage){
var date = new Date(); var date = new Date();
@ -77,9 +177,10 @@ zerobin = {
localStorage.setItem(keys.reverse()[0]+1, paste); localStorage.setItem(keys.reverse()[0]+1, paste);
} }
}, },
get_pastes: function(){ get_pastes: function(){
if (zerobin.support_localstorage){ if (zerobin.support_localstorage){
var pastes = ''; var pastes = '';
var keys = zerobin.get_keys(); var keys = zerobin.get_keys();
keys.reverse(); keys.reverse();
@ -94,7 +195,7 @@ zerobin = {
var on_at = 'on '; var on_at = 'on ';
} }
pastes = pastes + '<li><a class="items" href="' + paste.split(';')[1] + '">' + on_at + display_date + '</a></li>'; pastes = pastes + '<li><a class="items" href="' + paste.split(';')[1] + '">' + on_at + display_date + '</a></li>';
} }
if (!pastes){ if (!pastes){
return '<i class="grey">Your previous pastes will be saved in your browser using <a href="http://www.w3.org/TR/webstorage/">localStorage</a>.</i>'; return '<i class="grey">Your previous pastes will be saved in your browser using <a href="http://www.w3.org/TR/webstorage/">localStorage</a>.</i>';
} }
@ -103,7 +204,8 @@ zerobin = {
return 'Sorry your browser does not support LocalStorage, We cannot display your previous pastes.'; return 'Sorry your browser does not support LocalStorage, We cannot display your previous pastes.';
} }
}, },
get_paste_content: function(){
getPasteContent: function(){
var content_clone = '' ; var content_clone = '' ;
$("#paste-content li").each(function(index) { $("#paste-content li").each(function(index) {
content_clone = content_clone + $(this).text() + '\n'; content_clone = content_clone + $(this).text() + '\n';
@ -127,73 +229,137 @@ $('button[type=submit]').live("click", function(e){
var paste = $('textarea').val(); var paste = $('textarea').val();
if (paste.trim()) { if (paste.trim()) {
var expiration = $('#expiration').val();
var key = zerobin.make_key();
var data = {content: zerobin.encrypt(key, paste), expiration: expiration}
$.post('/paste/create', data) $('form.well p').hide();
.error(function(error) { $loading = $('form.well .progress').show();
alert('Paste could not be saved. Please try again later.'); var $loading = $('form.well .progress .bar')
}) .css('width', '25%')
.success(function(data) { .text('Converting paste to bits...');
var paste_url = '/paste/' + data['paste'] + '#' + key;
window.location = (paste_url); /* Encode, compress, encrypt and send the paste then redirect the user
zerobin.store_paste(paste_url); to the new paste. We ensure a loading animation is updated
}); during the process by passing callbacks.
*/
try {
var expiration = $('#expiration').val();
var key = zerobin.make_key();
zerobin.encrypt(key, paste,
function(){$loading.text('Encoding to base64...').css('width', '45%')},
function(){$loading.text('Compressing...').css('width', '65%')},
function(){$loading.text('Encrypting...').css('width', '85%')},
/* This block deal with sending the data, redirection or error handling */
function(content){
$loading.text('Sending...').css('width', '95%');
var data = {content: content, expiration: expiration};
$.post('/paste/create', data)
.error(function(error) {
$('form.well p').show();
$loading.hide();
alert('Error: paste could not be saved. Please try again later.');
})
.success(function(data) {
$loading.text('Redirecting to new paste...').css('width', '100%');
var paste_url = '/paste/' + data['paste'] + '#' + key;
zerobin.store_paste(paste_url);
window.location = (paste_url);
});
}
);
} catch (err) {
$('form.well p').show();
$loading.hide();
alert('Error: paste could not be encrypted. Aborting.');
}
} }
}); });
/** On the display paste page. /**
Decrypt and decompress the paste content, add syntax coloration then DECRYPTION:
setup the copy to clipboard button. On the display paste page, decrypt and decompress the paste content,
add syntax coloration then setup the copy to clipboard button.
*/ */
var content = $('#paste-content').text().trim(); var content = $('#paste-content').text().trim();
var key = window.location.hash.substring(1); var key = window.location.hash.substring(1);
var error = false; var error = false;
if (content && key) { if (content && key) {
try {
$('#paste-content').text(zerobin.decrypt(key, content));
} catch(err) {
error = true;
alert('Could not decrypt data (Wrong key ?)');
}
content = ''; var $bar = $('.well form .progress').show();
var $loading = $('.well form .progress .bar').css('width', '25%')
.text('Decrypting paste...');
if (!error) { zerobin.decrypt(key, content,
$('#short-url').click(function(e) { /* On error*/
e.preventDefault(); function(){
$('#short-url').text('Loading short url...'); $bar.hide();
zerobin.getTinyURL(window.location.toString(), function(tinyurl){ alert('Could not decrypt data (Wrong key ?)');
clip.setText(tinyurl); },
$('#copy-success').hide();
$('#short-url-success') /* Update progress bar */
.html('Short url: <a href="' + tinyurk + '">' + tinyurk + '</a>') function(){$loading.text('Decompressing...').css('width', '45%')},
.show('fadeUp'); function(){$loading.text('Base64 decoding...').css('width', '65%')},
$('#short-url').text('Get short url'); function(){$loading.text('From bits to string...').css('width', '85%')},
/* When done */
function(content){
/* Decrypted content goes back to initial container*/
$('#paste-content').text(content);
content = '';
$loading.text('Code coloration...').css('width', '95%');
/* Add a continuation to let the UI redraw */
setTimeout(function(){
/* Setup link to get the paste short url*/
$('#short-url').click(function(e) {
e.preventDefault();
$('#short-url').text('Loading short url...');
zerobin.getTinyURL(window.location.toString(), function(tinyurl){
clip.setText(tinyurl);
$('#copy-success').hide();
$('#short-url-success')
.html('Short url: <a href="' + tinyurk + '">' + tinyurk + '</a>')
.show('fadeUp');
$('#short-url').text('Get short url');
});
}); });
});
prettyPrint(); /* Setup flash clipboard button */
ZeroClipboard.setMoviePath('/static/js/ZeroClipboard.swf' );
/* Setup flash clipboard button */ var clip = new ZeroClipboard.Client();
ZeroClipboard.setMoviePath('/static/js/ZeroClipboard.swf' ); clip.addEventListener('mouseup', function(){
clip.setText(zerobin.getPasteContent());
});
clip.addEventListener('complete', function(){
$('#copy-success').show('fadeUp', function(){clip.reposition()});
});
clip.glue('clip-button');
var clip = new ZeroClipboard.Client(); window.onresize = clip.reposition;
clip.addEventListener('mouseup', function(){
clip.setText(zerobin.get_paste_content()); /** Syntaxic coloration */
}); prettyPrint();
clip.addEventListener('complete', function(){
$('#copy-success').show('fadeUp', function(){clip.reposition()}); /* Display result */
}); $loading.text('Done').css('width', '100%');
clip.glue('clip-button'); $bar.hide();
}, 250);
window.onresize = clip.reposition;
} }
);
} /* End of "DECRYPTION" */
}
/* Synchronize expiration select boxes value */ /* Synchronize expiration select boxes value */
$('.paste-option select').live('change', function(){ $('.paste-option select').live('change', function(){
@ -201,11 +367,9 @@ $('.paste-option select').live('change', function(){
$('.paste-option select').val(value); $('.paste-option select').val(value);
}); });
/* Resize Textarea according to content */ /* Resize Textarea according to content */
$('#content').elastic(); $('#content').elastic();
/* Display bottom paste option buttons when needed */ /* Display bottom paste option buttons when needed */
$('#content').live('keyup change', function(){ $('#content').live('keyup change', function(){
if($('#content').height() < 400 ){ if($('#content').height() < 400 ){
@ -221,33 +385,14 @@ $('#content').live('keyup change', function(){
/* Display previous pastes */ /* Display previous pastes */
$('.previous-pastes .items').html(zerobin.get_pastes()); $('.previous-pastes .items').html(zerobin.get_pastes());
/* clone a paste */ /* clone a paste */
$('.btn-clone').click(function(e){ $('.btn-clone').click(function(e){
e.preventDefault(); e.preventDefault();
var content_clone = zerobin.get_paste_content(); var content_clone = zerobin.getPasteContent();
$('.submit-form').show(); $('.submit-form').show();
$('.paste-form').remove(); $('.paste-form').remove();
$('#content').val(content_clone); $('#content').val(content_clone);
$('#content').trigger('change'); $('#content').trigger('change');
}); });
}); }); /* End of "document ready" jquery callback */

View File

@ -9,7 +9,7 @@
pastebin featuring burn after reading, an history and pastebin featuring burn after reading, an history and
a clipboard"> a clipboard">
<link rel="shortcut icon" href="/static/ico/favicon.ico"> <link rel="shortcut icon" href="/static/ico/favicon.ico">
<link href="/static/css/prettify.css" rel="stylesheet" /> <link href="/static/css/prettify.css" rel="stylesheet" />
<link href="/static/css/bootstrap.css" rel="stylesheet"> <link href="/static/css/bootstrap.css" rel="stylesheet">
<link href="/static/css/style.css" rel="stylesheet"> <link href="/static/css/style.css" rel="stylesheet">

View File

@ -14,6 +14,9 @@
class="input-xlarge" class="input-xlarge"
id="content" name="content"></textarea> id="content" name="content"></textarea>
</p> </p>
<div class="progress progress-striped active">
<div class="bar"></div>
</div>
</form> </form>

View File

@ -33,6 +33,10 @@
</span> </span>
</p> </p>
<div class="progress progress-striped active">
<div class="bar"></div>
</div>
<p> <p>
<pre id="paste-content" class="prettyprint linenums"> <pre id="paste-content" class="prettyprint linenums">
<code> <code>