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:
parent
2180d00dda
commit
2264d79d02
18
src/paste.py
18
src/paste.py
@ -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)
|
||||||
|
22
start.py
22
start.py
@ -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
|
||||||
|
@ -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
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
236
static/js/lzw.js
Normal 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;
|
||||||
|
}
|
@ -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>
|
||||||
|
@ -1,17 +1,8 @@
|
|||||||
<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>
|
|
||||||
<button class="btn"><i class="icon-camera"></i> 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="burn_after_reading">Burn after reading</option>
|
||||||
<option value="10_minutes">10 minutes</option>
|
<option value="10_minutes">10 minutes</option>
|
||||||
<option value="1_hour">1 hour</option>
|
<option value="1_hour">1 hour</option>
|
||||||
@ -19,10 +10,8 @@
|
|||||||
<option value="1_month">1 month</option>
|
<option value="1_month">1 month</option>
|
||||||
<option value="never">Never</option>
|
<option value="never">Never</option>
|
||||||
</select>
|
</select>
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
<span>
|
<p>
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<textarea rows="10" style="width:100%;"
|
<textarea rows="10" style="width:100%;"
|
||||||
@ -31,18 +20,9 @@
|
|||||||
</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>
|
|
||||||
<button class="btn"><i class="icon-camera"></i> 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="burn_after_reading">Burn after reading</option>
|
||||||
<option value="10_minutes">10 minutes</option>
|
<option value="10_minutes">10 minutes</option>
|
||||||
<option value="1_hour">1 hour</option>
|
<option value="1_hour">1 hour</option>
|
||||||
@ -50,9 +30,9 @@
|
|||||||
<option value="1_month">1 month</option>
|
<option value="1_month">1 month</option>
|
||||||
<option value="never">Never</option>
|
<option value="never">Never</option>
|
||||||
</select>
|
</select>
|
||||||
<button type="submit" class="btn btn-primary">Submit</button>
|
<button type="submit" class="btn btn-primary">Submit</button>
|
||||||
<span>
|
<p>
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
@ -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> 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> 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
|
Loading…
Reference in New Issue
Block a user