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

Now with encryption and compression

This commit is contained in:
sam 2012-04-26 16:38:55 +07:00
parent 2180d00dda
commit 2264d79d02
8 changed files with 395 additions and 62 deletions

View File

@ -26,24 +26,24 @@ class Paste(object):
def __init__(self, uuid=None, content=None, def __init__(self, uuid=None, content=None,
expire_in=u'burn_after_reading', expiration=u'burn_after_reading',
comments=None): comments=None):
self.content = content.encode('utf8') self.content = content.encode('utf8')
self.uuid = uuid or hashlib.sha1(self.content).hexdigest() self.uuid = uuid or hashlib.sha1(self.content).hexdigest()
self.expire_in = self.get_expiration(expire_in) self.expiration = self.get_expiration(expiration)
self.comments = comments self.comments = comments
def get_expiration(self, expire_in): def get_expiration(self, expiration):
""" """
Return a tuple with the date at which the Paste will expire Return a tuple with the date at which the Paste will expire
or if it should be destroyed after first reading. or if it should be destroyed after first reading.
""" """
try: try:
return datetime.now() + timedelta(seconds=self.DURATIONS[expire_in]) return datetime.now() + timedelta(seconds=self.DURATIONS[expiration])
except KeyError: except KeyError:
return u'burn_after_reading' return u'burn_after_reading'
@ -82,19 +82,19 @@ class Paste(object):
try: try:
paste = open(path) paste = open(path)
uuid = os.path.basename(path) uuid = os.path.basename(path)
expire_in = paste.next() expiration = paste.next()
data = paste.next() data = paste.next()
comments = paste.read()[:-1] # remove the last coma comments = paste.read()[:-1] # remove the last coma
if expire_in != u'burn_after_reading': if expiration != u'burn_after_reading':
expire_in = datetime.strptime(expire_in, '%Y-%m-%d %H:%M:%S.%f') expiration = datetime.strptime(expiration, '%Y-%m-%d %H:%M:%S.%f')
except StopIteration: except StopIteration:
raise TypeError(u'File %s is malformed' % path) raise TypeError(u'File %s is malformed' % path)
except (IOError, OSError): except (IOError, OSError):
raise ValueError(u'Can not open paste from file %s' % path) raise ValueError(u'Can not open paste from file %s' % path)
return Paste(uuid=uuid, comments=comments, expire_in=expire_in, **data) return Paste(uuid=uuid, comments=comments, expiration=expiration, **data)
@classmethod @classmethod
@ -136,7 +136,7 @@ class Paste(object):
self.DIR_CACHE.add((head, tail)) self.DIR_CACHE.add((head, tail))
with open(self.path, 'w') as f: with open(self.path, 'w') as f:
f.write(unicode(self.expire_in) + '\n') f.write(unicode(self.expiration) + '\n')
f.write(self.content + '\n') f.write(self.content + '\n')
if self.comments: if self.comments:
f.write(comments) f.write(comments)

View File

@ -31,8 +31,26 @@ def create_paste():
content = u'' content = u''
if content: if content:
expire_in = request.forms.get('expire_in', u'burn_after_reading') expiration = request.forms.get('expiration', u'burn_after_reading')
paste = Paste(expire_in=expire_in, content=content) paste = Paste(expiration=expiration, content=content)
paste.save()
return paste.uuid
return ''
@app.route('/paste/<paste_id>')
def display_paste(paste_id):
try:
paste = Paste.load(paste_id)
except (TypeError, ValueError):
return ''
if content:
expiration = request.forms.get('expiration', u'burn_after_reading')
paste = Paste(expiration=expiration, content=content)
paste.save() paste.save()
return paste.uuid return paste.uuid

View File

@ -1,11 +1,46 @@
;
// Start random number generator seeding ASAP // Start random number generator seeding ASAP
sjcl.random.startCollectors(); sjcl.random.startCollectors();
$(function(){ $(function(){
function encrypt(key, content) {
content = lzw.compress(sjcl.encrypt(key, content));
content = sjcl.codec.utf8String.toBits(content);
return sjcl.codec.base64.fromBits(content);
}
function decrypt(key, content) {
content = sjcl.codec.base64.toBits(content);
content = sjcl.codec.utf8String.fromBits(content);
return sjcl.decrypt(key, lzw.decompress(content));
}
function make_key() {
return sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 0), 0);
}
$('button[type=submit]').click(function(e){
e.preventDefault();
var paste = $('textarea').val();
if (paste.trim()) {
var expiration = $('#expiration').val();
var key = make_key();
var data = {content: encrypt(key, paste), expiration: expiration}
$.post('/paste/create', data)
.error(function() {
alert('Paste could not be saved. Please try again later.');
})
.success(function(data) {
alert('success');
window.location = '/paste/' + data + '#' + key;
});
}
});
}); });

4
static/js/jquery-1.7.2.min.js vendored Normal file

File diff suppressed because one or more lines are too long

236
static/js/lzw.js Normal file
View File

@ -0,0 +1,236 @@
// Author: Anthony McKale
//
// Note: modifed to javascript from orginal as2 found below
// basically identical actual to as2
//
//
// http://www.razorberry.com/blog/archives/2004/08/22/lzw-compression-methods-in-as2/
//
// A class for LZW compression modified from code posted at the following URL's
// http://www.shoe-box.org/blog/index.php/2004/05/05/13-CompressionLzw
// http://www.lalex.com/blog/comments/200405/164-compression-lzw-actionscript-2.html
//
var lzw = {
// Change this variable to output an xml safe string
xmlsafe : false,
compress : function(str){
var dico = new Array();
var skipnum = lzw.xmlsafe?5:0;
for (var i = 0; i < 256; i++)
{
dico[String.fromCharCode(i)] = i;
}
if (lzw.xmlsafe)
{
dico["<"] = 256;
dico[">"] = 257;
dico["&"] = 258;
dico["\""] = 259;
dico["'"] = 260;
}
var res = "";
var txt2encode = str;
var splitStr = txt2encode.split("");
var len = splitStr.length;
var nbChar = 256+skipnum;
var buffer = "";
for (var i = 0; i <= len; i++)
{
var current = splitStr[i];
if (dico[buffer + current] !== undefined)
{
buffer += current;
}
else
{
res += String.fromCharCode(dico[buffer]);
dico[buffer + current] = nbChar;
nbChar++;
buffer = current;
}
}
return res;
},
decompress : function (str)
{
var dico = new Array();
var skipnum = lzw.xmlsafe?5:0;
for (var i = 0; i < 256; i++)
{
var c = String.fromCharCode(i);
dico[i] = c;
}
if (lzw.xmlsafe)
{
dico[256] = "<";
dico[257] = ">";
dico[258] = "&";
dico[259] = "\"";
dico[260] = "'";
}
var txt2encode = str;
var splitStr = txt2encode.split("");
var length = splitStr.length;
var nbChar = 256+skipnum;
var buffer = "";
var chaine = "";
var result = "";
for (var i = 0; i < length; i++)
{
var code = txt2encode.charCodeAt(i);
var current = dico[code];
if (buffer == "")
{
buffer = current;
result += current;
}
else
{
if (code <= 255+skipnum)
{
result += current;
chaine = buffer + current;
dico[nbChar] = chaine;
nbChar++;
buffer = current;
}
else
{
chaine = dico[code];
if (chaine == undefined) chaine = buffer + buffer.slice(0,1);
result += chaine;
dico[nbChar] = buffer + chaine.slice(0, 1);
nbChar++;
buffer = chaine;
}
}
}
return result;
}
}
// LZW-compress a string
function lzw_encode(s) {
var dict = {};
var data = (s + "").split("");
var out = [];
var currChar;
var phrase = data[0];
var code = 256;
for (var i=1; i<data.length; i++) {
currChar=data[i];
if (dict[phrase + currChar] != null) {
phrase += currChar;
}
else {
out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
dict[phrase + currChar] = code;
code++;
phrase=currChar;
}
}
out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
for (var i=0; i<out.length; i++) {
out[i] = String.fromCharCode(out[i]);
}
return out.join("");
}
// Decompress an LZW-encoded string
function lzw_decode(s) {
var dict = {};
var data = (s + "").split("");
var currChar = data[0];
var oldPhrase = currChar;
var out = [currChar];
var code = 256;
var phrase;
for (var i=1; i<data.length; i++) {
var currCode = data[i].charCodeAt(0);
if (currCode < 256) {
phrase = data[i];
}
else {
phrase = dict[currCode] ? dict[currCode] : (oldPhrase + currChar);
}
out.push(phrase);
currChar = phrase.charAt(0);
dict[code] = oldPhrase + currChar;
code++;
oldPhrase = phrase;
}
return out.join("");
}
/* utf.js - UTF-8 <=> UTF-16 convertion
*
* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
* Version: 1.0
* LastModified: Dec 25 1999
* This library is free. You can redistribute it and/or modify it.
*/
/*
* Interfaces:
* utf8 = utf16to8(utf16);
* utf16 = utf16to8(utf8);
*/
function utf16to8(str) {
var out, i, len, c;
out = "";
len = str.length;
for(i = 0; i < len; i++) {
c = str.charCodeAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
out += str.charAt(i);
} else if (c > 0x07FF) {
out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
} else {
out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
}
}
return out;
}
function utf8to16(str) {
var out, i, len, c;
var char2, char3;
out = "";
len = str.length;
i = 0;
while(i < len) {
c = str.charCodeAt(i++);
switch(c >> 4)
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
// 0xxxxxxx
out += str.charAt(i-1);
break;
case 12: case 13:
// 110x xxxx 10xx xxxx
char2 = str.charCodeAt(i++);
out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
break;
case 14:
// 1110 xxxx 10xx xxxx 10xx xxxx
char2 = str.charCodeAt(i++);
char3 = str.charCodeAt(i++);
out += String.fromCharCode(((c & 0x0F) << 12) |
((char2 & 0x3F) << 6) |
((char3 & 0x3F) << 0));
break;
}
}
return out;
}

View File

@ -8,7 +8,7 @@
content="0bin is a client-side-encrypted content="0bin is a client-side-encrypted
pastebin with a burn after reading feature"> pastebin with a burn after reading feature">
<!-- Le styles --> <link rel="shortcut icon" href="/static/ico/favicon.ico">
<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">
@ -17,8 +17,10 @@
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]--> <![endif]-->
<!-- Le fav and touch icons --> <script src="/static/js/sjcl.js"></script>
<link rel="shortcut icon" href="/static/ico/favicon.ico"> <script src="/static/js/jquery-1.7.2.min.js"></script>
<script src="/static/js/behavior.js"></script>
</head> </head>
<body> <body>
@ -82,9 +84,7 @@
</div><!--/.fluid-container--> </div><!--/.fluid-container-->
<script src="/static/js/sjcl.js"></script> <script src="/static/js/lzw.js"></script>
<script src="/static/js/jquery.js"></script>
<script src="/static/js/behavior.js"></script>
<!-- <!--
<script src="/static/js/jquery.js"></script> <script src="/static/js/jquery.js"></script>

View File

@ -1,28 +1,17 @@
<form class="well" method="post" action="/paste/create"> <form class="well" method="post" action="/paste/create">
<ul> <p class="paste-option">
<li> <label >Expiration:</label>
<span class="btn-group"> <select id="expiration" name="expiration">
<button class="btn">New Paste</button> <option value="burn_after_reading">Burn after reading</option>
<button class="btn"><i class="icon-camera"></i>&nbsp;Clone</button> <option value="10_minutes">10 minutes</option>
</span> <option value="1_hour">1 hour</option>
</li> <option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<li> <option value="never">Never</option>
<span class="paste-option"> </select>
<label for='expire_in'>Expiration:</label> <button type="submit" class="btn btn-primary">Submit</button>
<select id="expire_in" name="expire_in"> <p>
<option value="burn_after_reading">Burn after reading</option>
<option value="10_minutes">10 minutes</option>
<option value="1_hour">1 hour</option>
<option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<option value="never">Never</option>
</select>
<button type="submit" class="btn btn-primary">Submit</button>
<span>
</li>
</ul>
<p> <p>
<textarea rows="10" style="width:100%;" <textarea rows="10" style="width:100%;"
@ -31,28 +20,19 @@
</p> </p>
<ul> <p class="paste-option">
<li> <label >Expiration:</label>
<span class="btn-group"> <select id="expiration" name="expiration">
<button class="btn">New Paste</button> <option value="burn_after_reading">Burn after reading</option>
<button class="btn"><i class="icon-camera"></i>&nbsp;Clone</button> <option value="10_minutes">10 minutes</option>
</span> <option value="1_hour">1 hour</option>
</li> <option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<option value="never">Never</option>
</select>
<button type="submit" class="btn btn-primary">Submit</button>
<p>
<li>
<span class="paste-option">
<label >Expiration:</label>
<select id="expire_in" name="expire_in">
<option value="burn_after_reading">Burn after reading</option>
<option value="10_minutes">10 minutes</option>
<option value="1_hour">1 hour</option>
<option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<option value="never">Never</option>
</select>
<button type="submit" class="btn btn-primary">Submit</button>
<span>
</li>
</ul> </ul>
</form> </form>

View File

@ -0,0 +1,60 @@
<form class="well" method="post" action="/paste/create">
<ul>
<li>
<span class="btn-group">
<button class="btn">New Paste</button>
<button class="btn"><i class="icon-camera"></i>&nbsp;Clone</button>
</span>
</li>
<li>
<span class="paste-option">
<label for='expire_in'>Expiration:</label>
<select id="expire_in" name="expire_in">
<option value="burn_after_reading">Burn after reading</option>
<option value="10_minutes">10 minutes</option>
<option value="1_hour">1 hour</option>
<option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<option value="never">Never</option>
</select>
<button type="submit" class="btn btn-primary">Submit</button>
<span>
</li>
</ul>
<p>
<textarea rows="10" style="width:100%;"
class="input-xlarge"
id="content" name="content"></textarea>
</p>
<ul>
<li>
<span class="btn-group">
<button class="btn">New Paste</button>
<button class="btn"><i class="icon-camera"></i>&nbsp;Clone</button>
</span>
</li>
<li>
<span class="paste-option">
<label >Expiration:</label>
<select id="expire_in" name="expire_in">
<option value="burn_after_reading">Burn after reading</option>
<option value="10_minutes">10 minutes</option>
<option value="1_hour">1 hour</option>
<option selected value="1_day">1 day</option>
<option value="1_month">1 month</option>
<option value="never">Never</option>
</select>
<button type="submit" class="btn btn-primary">Submit</button>
<span>
</li>
</ul>
</form>
%rebase base