mirror of
https://github.com/Tygs/0bin.git
synced 2023-08-10 21:13:00 +03:00
Compare commits
55 Commits
counter
...
on-pypi-ma
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcefd57875 | ||
|
|
ff60fa9a3c | ||
|
|
d599aed09a | ||
|
|
9a0efa7fa7 | ||
|
|
fb957f8cde | ||
|
|
1e3a9e227d | ||
|
|
ab9ef15de2 | ||
|
|
0c1bcfdc87 | ||
|
|
b241b86125 | ||
|
|
6170665e1c | ||
|
|
6fffdc0371 | ||
|
|
2b9bf81fcd | ||
|
|
b729a678ea | ||
|
|
d57595297e | ||
|
|
0cfd685e8c | ||
|
|
82ea02a60c | ||
|
|
28bff88784 | ||
|
|
b5de896ef6 | ||
|
|
74bfee09c8 | ||
|
|
0879a8556e | ||
|
|
b2a9812688 | ||
|
|
303905aff5 | ||
|
|
451a282684 | ||
|
|
8e318c768b | ||
|
|
54e9098999 | ||
|
|
a045de73d1 | ||
|
|
419f618a30 | ||
|
|
72fc5d4646 | ||
|
|
16f3e2e474 | ||
|
|
60ddbf49c6 | ||
|
|
6959fcbed9 | ||
|
|
d12718d9dd | ||
|
|
7b8108ea6b | ||
|
|
a824bc2a21 | ||
|
|
470194806e | ||
|
|
6860778f47 | ||
|
|
780c50f971 | ||
|
|
02a5aa6cf6 | ||
|
|
2b9a70c19b | ||
|
|
22774feb8f | ||
|
|
dc4e482bb2 | ||
|
|
7703b26333 | ||
|
|
14b0b37bfb | ||
|
|
84268bc2fe | ||
|
|
e584338776 | ||
|
|
8cb5457467 | ||
|
|
f9e4f4acc0 | ||
|
|
111255352c | ||
|
|
fb60e4e332 | ||
|
|
c96e8b6006 | ||
|
|
2b35351aeb | ||
|
|
e83a7d6a58 | ||
|
|
3a07efeec0 | ||
|
|
d72f60405a | ||
|
|
6cfd005c98 |
@@ -11,7 +11,7 @@ be pasted in it. The idea is that one can (probably...) not be legally entitled
|
||||
to `moderate the pastebin content`_ as he/she has no way to decrypt it.
|
||||
|
||||
It's an Python implementation of the
|
||||
`zerobin project`_. It's easy to
|
||||
`zerobin project`_ under the `WTF licence`_. It's easy to
|
||||
install even if you know nothing about Python.
|
||||
|
||||
For now tested with IE9, and the last opera, safari, chrome and FF.
|
||||
@@ -57,7 +57,7 @@ Other features
|
||||
- copy paste to clipboard in a click;
|
||||
- get paste short URL in a click;
|
||||
- own previous pastes history;
|
||||
- visual hash of a paste to easily tell it appart from others in a list.
|
||||
- visual hash of a paste to easily tell it apart from others in a list.
|
||||
|
||||
Technologies used
|
||||
==================
|
||||
@@ -96,4 +96,5 @@ What does 0bin not implement?
|
||||
.. _Bootstrap: http://twitter.github.com/bootstrap/
|
||||
.. _VizHash.js: https://github.com/sametmax/VizHash.js
|
||||
.. _Cherrypy: http://www.cherrypy.org/ (server only)
|
||||
.. _is not worth it: http://stackoverflow.com/questions/201705/how-many-random-elements-before-md5-produces-collisions
|
||||
.. _is not worth it: http://stackoverflow.com/questions/201705/how-many-random-elements-before-md5-produces-collisions
|
||||
.. _WTF licence: http://en.wikipedia.org/wiki/WTFPL
|
||||
|
||||
@@ -16,7 +16,7 @@ An Apache setup is still much more robust and secure than an easy installation.
|
||||
Une installation apache est aussi beaucoup plus solide et sécurisé qu'une
|
||||
installation facile. You'll benefit from having:
|
||||
|
||||
- the possiblity to have several projects listening to the port 80;
|
||||
- the possibility to have several projects listening to the port 80;
|
||||
- several Apache module at your disposal (like requests throttling);
|
||||
- Apache robustness in front end: it's secure, and there is much less chance
|
||||
it will crash under heavy load;
|
||||
@@ -97,4 +97,4 @@ CGI
|
||||
===
|
||||
|
||||
You can also run 0bin using CGI, but infortunaly we didn't have time to cover
|
||||
it yet. Please contact us if you ever get the need to use it.
|
||||
it yet. Please contact us if you ever get the need to use it.
|
||||
|
||||
@@ -45,7 +45,7 @@ Other features
|
||||
- copy paste to clipboard in a click;
|
||||
- get paste short URL in a click;
|
||||
- own previous pastes history;
|
||||
- visual hash of a paste to easily tell it appart from others in a list.
|
||||
- visual hash of a paste to easily tell it apart from others in a list.
|
||||
|
||||
Technologies used
|
||||
==================
|
||||
@@ -84,4 +84,4 @@ What does 0bin not implement?
|
||||
.. _Bootstrap: http://twitter.github.com/bootstrap/
|
||||
.. _VizHash.js: https://github.com/sametmax/VizHash.js
|
||||
.. _Cherrypy: http://www.cherrypy.org/ (server only)
|
||||
.. _is not worth it: http://stackoverflow.com/questions/201705/how-many-random-elements-before-md5-produces-collisions
|
||||
.. _is not worth it: http://stackoverflow.com/questions/201705/how-many-random-elements-before-md5-produces-collisions
|
||||
|
||||
@@ -24,7 +24,7 @@ Therefor there are two steps:
|
||||
|
||||
You will benefit from having:
|
||||
|
||||
- the possiblity to have several projects listening to the port 80;
|
||||
- the possibility to have several projects listening to the port 80;
|
||||
- several Apache module at your disposal (like requests throttling);
|
||||
- Apache robustness in front end: it's secure, and there is much less chance
|
||||
it will crash under heavy load;
|
||||
@@ -40,7 +40,7 @@ Run 0bin as usual, but this time make it listen to a local port and host. E.G::
|
||||
|
||||
zerobin --host 127.0.0.1 --port 8000
|
||||
|
||||
In PHP, when you edit a file, the changes are immediatly visible. In Python,
|
||||
In PHP, when you edit a file, the changes are immediately visible. In Python,
|
||||
the whole code is often loaded in memory for performance reasons. This means
|
||||
you have to restart the Python process to see the changes effect. Having a
|
||||
separate process let you do this without having to restart the server.
|
||||
|
||||
@@ -159,7 +159,7 @@ List of absolute path to directories containing templates that 0bin uses to
|
||||
generate the web site pages. The first list items have priotity on the later.
|
||||
|
||||
If you wish to use your own templates, add the directory containing them
|
||||
at the begining of the list::
|
||||
at the beginning of the list::
|
||||
|
||||
from zerobin.defauls_settings import TEMPLATE_DIRS
|
||||
|
||||
@@ -225,4 +225,4 @@ Valeur approximative de limite de taille d'un paste.
|
||||
|
||||
Default = 500000 octets (500 ko)
|
||||
|
||||
Command line equivalent: None
|
||||
Command line equivalent: None
|
||||
|
||||
@@ -50,7 +50,7 @@ MENU = (
|
||||
('Contact', 'mailto:your@email.com') # email
|
||||
)
|
||||
|
||||
# limit size of pasted text in bytes. Be carefull allowing too much size can slow down user's
|
||||
# limit size of pasted text in bytes. Be careful allowing too much size can slow down user's
|
||||
# browser
|
||||
MAX_SIZE = 1024 * 500
|
||||
MAX_SIZE_KB = int(math.ceil(MAX_SIZE / 1024.0))
|
||||
|
||||
@@ -33,8 +33,8 @@ Les serveurs Web Python modernes fonctionnent tous de la même manière, en suiv
|
||||
une norme d'interfaçage: WSGI.
|
||||
|
||||
C'est la solution la plus performante, et celle recommandée. Mais elle demande
|
||||
l'installation du modle Apache mod_wsgi. Si vous ne savez pas comment faire,
|
||||
ou si vous ne pouvez pas le faire (par exemple sur un hébergement mutualisé
|
||||
l'installation du model Apache mod_wsgi. Si vous ne savez pas comment faire,
|
||||
ou si vous ne pouvez pas le faire (par example sur un hébergement mutualisé
|
||||
qui ne le propose pas), il vous faudra choisir l'installation CGI.
|
||||
|
||||
Premièrement, assurez-vous d'avoir mod_wsgi installé et chargé (en tant qu'admin)::
|
||||
|
||||
@@ -40,7 +40,7 @@ solutions.
|
||||
|
||||
*Pour un petit site:*
|
||||
|
||||
Lancer simplement 0bin en processus shell d'arrière plan. Exemple sous GNU/Linux::
|
||||
Lancer simplement 0bin en processus shell d'arrière plan. Example sous GNU/Linux::
|
||||
|
||||
nohup python zerobin.py --host 0.0.0.0 --port 80 --compressed-static &
|
||||
|
||||
|
||||
@@ -1457,7 +1457,7 @@ class JSONPlugin(object):
|
||||
if isinstance(rv, dict):
|
||||
#Attempt to serialize, raises exception on failure
|
||||
json_response = dumps(rv)
|
||||
#Set content type only if serialization succesful
|
||||
#Set content type only if serialization successful
|
||||
response.content_type = 'application/json'
|
||||
return json_response
|
||||
return rv
|
||||
|
||||
@@ -96,7 +96,7 @@ try:
|
||||
from base64 import decodebytes as _base64_decodebytes
|
||||
except ImportError:
|
||||
# Python 3.0-
|
||||
# since CherryPy claims compability with Python 2.3, we must use
|
||||
# since CherryPy claims compatibility with Python 2.3, we must use
|
||||
# the legacy API of base64
|
||||
from base64 import decodestring as _base64_decodebytes
|
||||
|
||||
|
||||
@@ -598,7 +598,7 @@ class MemcachedSession(Session):
|
||||
# Wrap all .get and .set operations in a single lock.
|
||||
mc_lock = threading.RLock()
|
||||
|
||||
# This is a seperate set of locks per session id.
|
||||
# This is a separate set of locks per session id.
|
||||
locks = {}
|
||||
|
||||
servers = ['127.0.0.1:11211']
|
||||
|
||||
@@ -312,7 +312,7 @@ class Daemonizer(SimplePlugin):
|
||||
process still return proper exit codes. Therefore, if you use this
|
||||
plugin to daemonize, don't use the return code as an accurate indicator
|
||||
of whether the process fully started. In fact, that return code only
|
||||
indicates if the process succesfully finished the first fork.
|
||||
indicates if the process successfully finished the first fork.
|
||||
"""
|
||||
|
||||
def __init__(self, bus, stdin='/dev/null', stdout='/dev/null',
|
||||
|
||||
@@ -141,7 +141,7 @@ def get_sups():
|
||||
def set_sups(target_sups):
|
||||
"""
|
||||
This is designed to give us a layer of abstraction from the system calls.
|
||||
It also accomodates FreeBSD's idiosyncracy (which is POSIX-compliant) of
|
||||
It also accommodates FreeBSD's idiosyncrasy (which is POSIX-compliant) of
|
||||
keeping the egid in the supplementary groups list.
|
||||
It also makes an effort to not call the setgroups routine if the target
|
||||
group list is identical to the current one in force.
|
||||
|
||||
10
setup.py
10
setup.py
@@ -82,7 +82,7 @@ setup(
|
||||
# the notation major.minor[.patch[.sub]].
|
||||
# More defails: http://peak.telecommunity.com/DevCenter/setuptools#id6
|
||||
# E.G: "0.1", or "1.11.04", or "2"
|
||||
version="0.1",
|
||||
version="0.2",
|
||||
|
||||
# An iterable of strings with the names of all packages to be included
|
||||
# for distribution. setup() will not recurse over this package, so it
|
||||
@@ -107,7 +107,7 @@ setup(
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Parameters you definitly should fill even if they are optional #
|
||||
# Parameters you definitely should fill even if they are optional #
|
||||
# You need to either fill or comment them, or setup.py install will fail #
|
||||
##########################################################################
|
||||
|
||||
@@ -183,7 +183,7 @@ setup(
|
||||
|
||||
## Iterable of strings being names of modules you wish to include as well
|
||||
## It's more accurate than a package
|
||||
## espcially usefull if you have lonelly modules at the root level
|
||||
## espcially useful if you have lonelly modules at the root level
|
||||
# E.G: ['mod1', 'pkg.mod2'] if you have mod1.py and pkg/mod2.py
|
||||
# py_modules= ,
|
||||
|
||||
@@ -226,7 +226,7 @@ setup(
|
||||
|
||||
# Iterable of string being metadata. You can't add yours and pypi is picky
|
||||
# about the syntax, so just uncomment the one you want to set.
|
||||
# It is adviced to at least provide "Operating System" and "Licence"
|
||||
# It is advised to at least provide "Operating System" and "Licence"
|
||||
# Incompatibel with 2.2.3- or 2.3-
|
||||
classifiers=[
|
||||
'Programming Language :: Python',
|
||||
@@ -981,7 +981,7 @@ setup(
|
||||
|
||||
|
||||
## A mapping of strings / iterable, the key being the name of a extra
|
||||
## feature, and the iterable containing dependancy names.
|
||||
## feature, and the iterable containing dependency names.
|
||||
## Sometimes a project has "recommended" dependencies, that are not required
|
||||
## for all uses of the project. For example, a project might offer optional PDF
|
||||
## output if ReportLab is installed, and reStructuredText support if docutils
|
||||
|
||||
37
stats.py
37
stats.py
@@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: ai ts=4 sts=4 et sw=4
|
||||
|
||||
|
||||
"""
|
||||
Exctract usefull infos from web server logs
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
|
||||
# define your web server logs path
|
||||
LOGS_PATH = "/var/log/nginx/access_0bin.log"
|
||||
|
||||
|
||||
rexp = re.compile('(\d+\.\d+\.\d+\.\d+) - - \[([^\[\]:]+):(\d+:\d+:\d+) -(\d\d\d\d\)] ("[^"]*")(\d+) (-|\d+) ("[^"]*") (".*")\s*\Z')
|
||||
|
||||
|
||||
f = open(LOGS_PATH, 'r')
|
||||
|
||||
for line in f:
|
||||
a = rexp.match(line)
|
||||
|
||||
if not a is None:
|
||||
# a.group(1) #IP address
|
||||
# a.group(2) #day/month/year
|
||||
# a.group(3) #time of day
|
||||
# a.group(4) #timezone
|
||||
# a.group(5) #request
|
||||
# a.group(6) #code 200 for success, 404 for not found, etc.
|
||||
# a.group(7) #bytes transferred
|
||||
# a.group(8) #referrer
|
||||
# a.group(9) #browser
|
||||
print a.group(8) #referrer
|
||||
|
||||
f.close()
|
||||
@@ -4,4 +4,4 @@
|
||||
|
||||
from zerobin.routes import main
|
||||
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
|
||||
from default_settings import VERSION
|
||||
|
||||
__version__ = VERSION
|
||||
__version__ = VERSION
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
|
||||
######## NOT SETTINGS, JUST BOILER PLATE ##############
|
||||
import os
|
||||
import math
|
||||
|
||||
VERSION = '0.1'
|
||||
VERSION = '0.2'
|
||||
ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
LIBS_DIR = os.path.join(os.path.dirname(ROOT_DIR), 'libs')
|
||||
|
||||
@@ -68,6 +67,6 @@ MENU = (
|
||||
('Contact', 'mailto:your@email.com') # email
|
||||
)
|
||||
|
||||
# limit size of pasted text in bytes. Be carefull allowing too much size can
|
||||
# limit size of pasted text in bytes. Be careful allowing too much size can
|
||||
# slow down user's browser
|
||||
MAX_SIZE = 1024 * 500
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import os
|
||||
import hashlib
|
||||
import locale
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
@@ -112,10 +113,9 @@ class Paste(object):
|
||||
return cls.load_from_file(cls.get_path(uuid))
|
||||
|
||||
|
||||
|
||||
def increment_counter(self):
|
||||
"""
|
||||
Increment pastes counter
|
||||
Increment pastes counter
|
||||
"""
|
||||
|
||||
# simple counter incrementation
|
||||
@@ -131,7 +131,7 @@ class Paste(object):
|
||||
try:
|
||||
#make lock file
|
||||
flock = open(lock_file, "w")
|
||||
flock.write('lock')
|
||||
flock.write('lock')
|
||||
flock.close()
|
||||
|
||||
# init counter (first time)
|
||||
@@ -157,7 +157,7 @@ class Paste(object):
|
||||
|
||||
#remove lock file
|
||||
os.remove(lock_file)
|
||||
except (IOError, OSError):
|
||||
finally:
|
||||
if os.path.isfile(lock_file):
|
||||
#remove lock file
|
||||
os.remove(lock_file)
|
||||
@@ -205,6 +205,56 @@ class Paste(object):
|
||||
return self
|
||||
|
||||
|
||||
@classmethod
|
||||
def get_pastes_count(cls):
|
||||
"""
|
||||
Return the number of created pastes.
|
||||
(must have option DISPLAY_COUNTER enabled for the pastes to be
|
||||
be counted)
|
||||
"""
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, 'en_US')
|
||||
except:
|
||||
pass
|
||||
counter_file = os.path.join(settings.PASTE_FILES_ROOT, 'counter')
|
||||
try:
|
||||
count = long(open(counter_file).read(50))
|
||||
except (IOError, OSError):
|
||||
count = 0
|
||||
|
||||
return locale.format("%d", long(count), grouping=True)
|
||||
|
||||
|
||||
@property
|
||||
def humanized_expiration(self):
|
||||
"""
|
||||
Return the expiration date in a human friendly format.
|
||||
|
||||
In 3 minutes, or in 3 days or the 23/01/2102
|
||||
"""
|
||||
try:
|
||||
expiration = self.expiration - datetime.now()
|
||||
# in_seconds doesn't exist in python 2.6
|
||||
expiration = expiration.days * 24 * 60 * 60 + expiration.seconds
|
||||
|
||||
except TypeError:
|
||||
return None
|
||||
|
||||
if expiration < 60:
|
||||
return 'in %s s' % expiration
|
||||
|
||||
if expiration < 60 * 60:
|
||||
return 'in %s m' % int(expiration / 60)
|
||||
|
||||
if expiration < 60 * 60 * 24:
|
||||
return 'in %s h' % int(expiration / (60 * 60))
|
||||
|
||||
if expiration < 60 * 60 * 24 * 10:
|
||||
return 'in %s days(s)' % int(expiration / (60 * 60 * 24))
|
||||
|
||||
return 'the %s' % self.expiration.strftime('%m/%d/%Y')
|
||||
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Delete the paste file.
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
# vim: ai ts=4 sts=4 et sw=4
|
||||
|
||||
"""
|
||||
Main script including controller, rooting, dependancy management, and
|
||||
Main script including controller, rooting, dependency management, and
|
||||
server run.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import thread
|
||||
|
||||
import urlparse
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# add project dir and libs dir to the PYTHON PATH to ensure they are
|
||||
@@ -23,16 +23,16 @@ from bottle import (Bottle, run, static_file, view, request)
|
||||
import clize
|
||||
|
||||
from paste import Paste
|
||||
from utils import drop_privileges, dmerge, get_pastes_count
|
||||
from utils import drop_privileges, dmerge
|
||||
|
||||
|
||||
app = Bottle()
|
||||
GLOBAL_CONTEXT = {
|
||||
'settings': settings,
|
||||
'pastes_count': get_pastes_count(),
|
||||
'pastes_count': Paste.get_pastes_count(),
|
||||
'refresh_counter': datetime.now()
|
||||
}
|
||||
|
||||
|
||||
|
||||
@app.route('/')
|
||||
@view('home')
|
||||
@@ -48,42 +48,51 @@ def faq():
|
||||
|
||||
@app.route('/paste/create', method='POST')
|
||||
def create_paste():
|
||||
try:
|
||||
body = urlparse.parse_qs(request.body.read(int(settings.MAX_SIZE * 1.1)))
|
||||
except ValueError:
|
||||
return {'status': 'error',
|
||||
'message': u"Wrong data payload."}
|
||||
|
||||
try:
|
||||
content = unicode(request.forms.get('content', ''), 'utf8')
|
||||
except UnicodeDecodeError:
|
||||
content = unicode(''.join(body['content']), 'utf8')
|
||||
except (UnicodeDecodeError, KeyError):
|
||||
return {'status': 'error',
|
||||
'message': u"Encoding error: the paste couldn't be saved."}
|
||||
|
||||
if '{"iv":' not in content: # reject silently non encrypted content
|
||||
return ''
|
||||
if '{"iv":' not in content: # reject silently non encrypted content
|
||||
return {'status': 'error',
|
||||
'message': u"Wrong data payload."}
|
||||
|
||||
if content:
|
||||
# check size of the paste. if more than settings return error without saving paste.
|
||||
# prevent from unusual use of the system.
|
||||
# need to be improved
|
||||
# check size of the paste. if more than settings return error
|
||||
# without saving paste. prevent from unusual use of the
|
||||
# system. need to be improved
|
||||
if len(content) < settings.MAX_SIZE:
|
||||
expiration = request.forms.get('expiration', u'burn_after_reading')
|
||||
expiration = body.get('expiration', [u'burn_after_reading'])[0]
|
||||
paste = Paste(expiration=expiration, content=content)
|
||||
paste.save()
|
||||
|
||||
|
||||
# display counter
|
||||
if settings.DISPLAY_COUNTER:
|
||||
|
||||
#increment paste counter
|
||||
paste.increment_counter()
|
||||
|
||||
# if refresh time elapsed pick up new counter value
|
||||
if GLOBAL_CONTEXT['refresh_counter'] + timedelta(seconds=settings.REFRESH_COUNTER) < datetime.now():
|
||||
GLOBAL_CONTEXT['pastes_count'] = get_pastes_count()
|
||||
GLOBAL_CONTEXT['refresh_counter'] = datetime.now()
|
||||
|
||||
# if refresh time elapsed pick up new counter value
|
||||
now = datetime.now()
|
||||
timeout = (GLOBAL_CONTEXT['refresh_counter']
|
||||
+ timedelta(seconds=settings.REFRESH_COUNTER))
|
||||
if timeout < now:
|
||||
GLOBAL_CONTEXT['pastes_count'] = Paste.get_pastes_count()
|
||||
GLOBAL_CONTEXT['refresh_counter'] = now
|
||||
|
||||
return {'status': 'ok',
|
||||
'paste': paste.uuid}
|
||||
|
||||
return {'status': 'error',
|
||||
'message': u"Serveur error: the paste couldn't be saved. Please try later."}
|
||||
'message': u"Serveur error: the paste couldn't be saved. "
|
||||
u"Please try later."}
|
||||
|
||||
|
||||
@app.route('/paste/:paste_id')
|
||||
@@ -102,7 +111,8 @@ def display_paste(paste_id):
|
||||
# to the paste that happens during the paste creation
|
||||
try:
|
||||
keep_alive = paste.expiration.split('#')[1]
|
||||
keep_alive = datetime.strptime(keep_alive, '%Y-%m-%d %H:%M:%S.%f')
|
||||
keep_alive = datetime.strptime(keep_alive,
|
||||
'%Y-%m-%d %H:%M:%S.%f')
|
||||
keep_alive = now < keep_alive + timedelta(seconds=10)
|
||||
except IndexError:
|
||||
keep_alive = False
|
||||
@@ -114,7 +124,6 @@ def display_paste(paste_id):
|
||||
raise ValueError()
|
||||
|
||||
except (TypeError, ValueError):
|
||||
#abort(404, u"This paste doesn't exist or has expired")
|
||||
return error404(ValueError)
|
||||
|
||||
context = {'paste': paste, 'keep_alive': keep_alive}
|
||||
@@ -134,8 +143,8 @@ def server_static(filename):
|
||||
|
||||
def get_app(debug=None, settings_file='', compressed_static=None):
|
||||
"""
|
||||
Return a tuple (settings, app) configured using passed options and
|
||||
a setting file.
|
||||
Return a tuple (settings, app) configured using passed
|
||||
parameters and/or a setting file.
|
||||
"""
|
||||
if settings_file:
|
||||
settings.update_with_file(os.path.abspath(settings_file))
|
||||
@@ -157,8 +166,8 @@ def get_app(debug=None, settings_file='', compressed_static=None):
|
||||
|
||||
|
||||
@clize.clize(coerce={'debug': bool, 'compressed_static': bool})
|
||||
def runserver(host='', port='', debug=None, user='',
|
||||
group='', settings_file='', compressed_static=None, version=False):
|
||||
def runserver(host='', port='', debug=None, user='', group='',
|
||||
settings_file='', compressed_static=None, version=False):
|
||||
|
||||
settings, app = get_app(debug, settings_file, compressed_static)
|
||||
|
||||
@@ -177,7 +186,7 @@ def runserver(host='', port='', debug=None, user='',
|
||||
run(app, host=settings.HOST, port=settings.PORT, reloader=True,
|
||||
server="cherrypy")
|
||||
else:
|
||||
run(app, host=settings.HOST, port=settings.PORT, server="cherrypy")
|
||||
run(app, host=settings.HOST, port=settings.PORT, server="cherrypy")
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
|
||||
.brand {
|
||||
font-size: 38px !important;
|
||||
padding: 0px 55px 3px !important;
|
||||
padding: 0 55px 3px !important;
|
||||
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, .1), 0 0 30px rgba(255, 255, 255, .125);
|
||||
-webkit-transition: all .2s linear;
|
||||
-moz-transition: all .2s linear;
|
||||
-o-transition: all .2s linear;
|
||||
-ms-transition: all .2s linear;
|
||||
transition: all .2s linear;
|
||||
}
|
||||
|
||||
@@ -19,7 +21,6 @@
|
||||
.brand em {
|
||||
display: inline;
|
||||
color: #D40202;
|
||||
margin: 0px !important;
|
||||
font-size: 27px;
|
||||
}
|
||||
|
||||
@@ -28,7 +29,7 @@
|
||||
font-style: italic;
|
||||
text-align: right;
|
||||
padding-top: 9px;
|
||||
margin-bottom: 0px !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.center {
|
||||
@@ -94,6 +95,8 @@ h4 p {
|
||||
font-size: 80px;
|
||||
text-shadow: 1px 3px 1px #DDD, 0 0 4px #333;
|
||||
-webkit-transition: all 0.2s linear;
|
||||
-o-transition: all .2s linear;
|
||||
-ms-transition: all .2s linear;
|
||||
-moz-transition: all .2s linear;
|
||||
transition: all .2s linear;
|
||||
margin-right: 7px;
|
||||
@@ -162,7 +165,7 @@ input.hide-upload {
|
||||
position: relative;
|
||||
left: -110px;
|
||||
-moz-opacity: 0;
|
||||
filter: alpha(opacity: 0);
|
||||
filter: alpha(opacity=0);
|
||||
opacity: 0 ;
|
||||
z-index: 2;
|
||||
width: 100px;
|
||||
@@ -181,9 +184,7 @@ input.hide-upload {
|
||||
}
|
||||
|
||||
|
||||
#paste-content.done {
|
||||
background-color: white;
|
||||
padding-top:1em;
|
||||
#paste-content.linenums {
|
||||
padding-left:0;
|
||||
}
|
||||
|
||||
@@ -262,6 +263,7 @@ form {
|
||||
|
||||
form textarea {
|
||||
overflow-y:auto;
|
||||
min-height:250px;
|
||||
}
|
||||
|
||||
button.btn, input[type="submit"].btn {
|
||||
@@ -352,3 +354,37 @@ canvas {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#faq dt {
|
||||
margin:2em 0 1em 0;
|
||||
}
|
||||
|
||||
#faq p {
|
||||
margin:1em;
|
||||
}
|
||||
|
||||
#force-coloration {
|
||||
text-decoration:underline;
|
||||
}
|
||||
|
||||
#expiration-tag {
|
||||
float:right;
|
||||
margin:1em;
|
||||
background:grey;
|
||||
color:white;
|
||||
font-size:0.8em;
|
||||
padding:0 1ex;
|
||||
opacity: 0.5;
|
||||
filter: alpha(opacity=50);
|
||||
font-weight:bold;
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
-moz-background-clip: padding;
|
||||
-webkit-background-clip: padding-box;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
#content.hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
2
zerobin/static/css/style.min.css
vendored
2
zerobin/static/css/style.min.css
vendored
@@ -4,4 +4,4 @@ article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display
|
||||
/* Prettify */
|
||||
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
|
||||
/* Custom */
|
||||
.brand{font-size:38px!important;padding:0 55px 3px!important;text-shadow:0 1px 0 rgba(255,255,255,.1),0 0 30px rgba(255,255,255,.125);-webkit-transition:all .2s linear;-moz-transition:all .2s linear;transition:all .2s linear}.brand span{font-size:48px;line-height:0}.brand em{display:inline;color:#d40202;margin:0!important;font-size:27px}.about{line-height:13px;font-style:italic;text-align:right;padding-top:9px;margin-bottom:0!important}.about span{font-size:10px}body{padding-top:60px;padding-bottom:40px}.sidebar-nav{padding:9px 0}select{width:135px}label{display:inline;margin-left:18px;font-style:italic;font-size:11px;color:#888}ul,ol{padding:0;margin:0}li{margin-left:-9px}p{margin:0 0 20px}.grey{color:#999}.nav-list{padding-right:0!important;font-size:12px}blockquote{width:630px;float:left}h4 p{float:left;font-size:80px;text-shadow:1px 3px 1px #DDD,0 0 4px #333;-webkit-transition:all .2s linear;-moz-transition:all .2s linear;transition:all .2s linear;margin-right:7px;margin-top:3px}h4#pixels-total{position:relative;width:166px;float:right;margin:8px 0 0 0;padding:0 0 0 54px;font-size:1.1em;line-height:1.4;font-weight:normal;color:#777;-webkit-border-top-right-radius:6px;-webkit-border-top-left-radius:20px;-moz-border-top-right-radius:6px;-moz-border-top-left-radius:20px;border-top-right-radius:6px;border-top-left-radius:20px}.greetings{clear:both;margin:0 auto;text-align:center;margin-top:40px}.alert .title{display:block}.btn-group{float:left}html.file-upload p.file-upload{float:left;margin:22px 0 0 21px;display:none}html.file-upload p.file-upload{display:inherit}html.no-file-upload p.file-upload{display:none}input.btn-upload{position:relative;left:-6px;width:100px;z-index:1;margin-top:-13px}input.hide-upload{position:relative;left:-110px;-moz-opacity:0;filter:alpha(opacity:0);opacity:0;z-index:2;width:100px;margin-top:-20px;cursor:pointer;cursor:hand;height:49px}#paste-content{background-color:white;padding:1em}#paste-content.done{background-color:white;padding-top:1em;padding-left:0}.submit-form{display:none}.paste-option{float:right}a#clip-button.hover{cursor:pointer;text-decoration:underline}li.L0,li.L1,li.L2,li.L3,li.L4,li.L5,li.L6,li.L7,li.L8,li.L9{list-style-type:decimal;background:inherit}.prettyprint.linenums{-webkit-box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0;-moz-box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0;box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0}ol.linenums{margin:0 0 0 55px}ol.linenums li{color:#bebec5;line-height:18px;text-shadow:0 1px 0 #fff}.prettyprint{padding:8px;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,monospace,serif;line-height:21px;font-size:12px}.kwd{color:#66F}.pun,.opn,.clo{color:#0A0}.lit{color:#933}.com{color:#C0C}form{padding-bottom:3em!important;padding-right:17px}form textarea{overflow-y:auto}button.btn,input[type="submit"].btn{margin-left:5px}.well{padding-bottom:40px;padding-right:17px}.legal{margin:0 auto;width:300px;text-align:center;margin-top:30px}.btn{margin-left:5px}.btn-primary,.btn-danger{position:relative;top:-4px}#alert-template{display:none}.progress{display:none}.progress .bar{width:25%;text-indent:10px;text-align:left}.lnk-option canvas{vertical-align:middle;margin-right:10px}.previous-pastes .item{margin-top:5px;vertical-align:middle;line-height:24px;padding-left:1em}li.item{margin-left:-13px;margin-right:-5px}.previous-pastes canvas{display:block;float:left;margin-right:5px}html.local-storage .no-local-storage{display:none}html.no-local-storage .local-storage{display:none}canvas{border:1px solid white}#wrap-content{display:none}.noscript{text-align:center;color:red;font-weight:bold}
|
||||
.brand{font-size:38px!important;padding:0 55px 3px!important;text-shadow:0 1px 0 rgba(255,255,255,.1),0 0 30px rgba(255,255,255,.125);-webkit-transition:all .2s linear;-moz-transition:all .2s linear;-o-transition:all .2s linear;-ms-transition:all .2s linear;transition:all .2s linear}.brand span{font-size:48px;line-height:0}.brand em{display:inline;color:#d40202;font-size:27px}.about{line-height:13px;font-style:italic;text-align:right;padding-top:9px;margin-bottom:0!important}.center{text-align:center}.about span{font-size:10px}body{padding-top:60px;padding-bottom:40px}.sidebar-nav{padding:9px 0}select{width:135px}label{display:inline;margin-left:18px;font-style:italic;font-size:11px;color:#888}ul,ol{padding:0;margin:0}li{margin-left:-9px}p{margin:0 0 20px}.grey{color:#999}.nav-list{padding-right:0!important;font-size:12px}blockquote{width:630px;float:left}h4 p{float:left;font-size:80px;text-shadow:1px 3px 1px #DDD,0 0 4px #333;-webkit-transition:all .2s linear;-o-transition:all .2s linear;-ms-transition:all .2s linear;-moz-transition:all .2s linear;transition:all .2s linear;margin-right:7px;margin-top:3px}h4#pixels-total{position:relative;width:166px;float:right;margin:8px 0 0 0;padding:0 0 0 54px;font-size:1.1em;line-height:1.4;font-weight:normal;color:#777;-webkit-border-top-right-radius:6px;-webkit-border-top-left-radius:20px;-moz-border-top-right-radius:6px;-moz-border-top-left-radius:20px;border-top-right-radius:6px;border-top-left-radius:20px}.greetings{clear:both;margin:0 auto;text-align:center;margin-top:40px}.alert .title{display:block}.btn-group{float:left}html.file-upload p.file-upload{float:left;margin:22px 0 0 21px;display:none}html.file-upload p.file-upload{display:inherit}html.no-file-upload p.file-upload{display:none}input.btn-upload{position:relative;left:-6px;width:100px;z-index:1;margin-top:-13px}input.hide-upload{position:relative;left:-110px;-moz-opacity:0;filter:alpha(opacity=0);opacity:0;z-index:2;width:100px;margin-top:-20px;cursor:pointer;cursor:hand;height:49px}#paste-content{background-color:white;padding:1em}#paste-content.linenums{padding-left:0}.submit-form{display:none}.paste-option{float:right}a#clip-button.hover{cursor:pointer;text-decoration:underline}li.L0,li.L1,li.L2,li.L3,li.L4,li.L5,li.L6,li.L7,li.L8,li.L9{list-style-type:decimal;background:inherit}.prettyprint.linenums{-webkit-box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0;-moz-box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0;box-shadow:inset 40px 0 0 #fbfbfc,inset 41px 0 0 #ececf0}ol.linenums{margin:0 0 0 55px}ol.linenums li{color:#bebec5;line-height:18px;text-shadow:0 1px 0 #fff}.prettyprint{padding:8px;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,monospace,serif;line-height:21px;font-size:12px}.kwd{color:#66F}.pun,.opn,.clo{color:#0A0}.lit{color:#933}.com{color:#C0C}form{padding-bottom:3em!important;padding-right:17px}form textarea{overflow-y:auto;min-height:250px}button.btn,input[type="submit"].btn{margin-left:5px}.well{padding-bottom:40px;padding-right:17px}.legal{margin:0 auto;width:300px;text-align:center;margin-top:30px}.btn{margin-left:5px}.btn-primary,.btn-danger{position:relative;top:-4px}#alert-template{display:none}.progress{display:none}.progress .bar{width:25%;text-indent:10px;text-align:left}.lnk-option canvas{vertical-align:middle;margin-right:10px}.previous-pastes .item{margin-top:5px;vertical-align:middle;line-height:24px;padding-left:1em}li.item{margin-left:-13px;margin-right:-5px}.previous-pastes canvas{display:block;float:left;margin-right:5px}html.local-storage .no-local-storage{display:none}html.no-local-storage .local-storage{display:none}canvas{border:1px solid white}#wrap-content{display:none}.noscript{text-align:center;color:red;font-weight:bold}#faq dt{margin:2em 0 1em 0}#faq p{margin:1em}#force-coloration{text-decoration:underline}#expiration-tag{float:right;margin:1em;background:grey;color:white;font-size:.8em;padding:0 1ex;opacity:.5;filter:alpha(opacity=50);font-weight:bold;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-moz-background-clip:padding;-webkit-background-clip:padding-box;background-clip:padding-box}#content.hover{background-color:#eee}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
// Author: Anthony McKale
|
||||
//
|
||||
// Note: modifed to javascript from orginal as2 found below
|
||||
// Note: modifed to javascript from original as2 found below
|
||||
// basically identical actual to as2
|
||||
//
|
||||
// http://www.razorberry.com/blog/archives/2004/08/22/lzw-compression-methods-in-as2/
|
||||
|
||||
2
zerobin/static/js/main.min.js
vendored
2
zerobin/static/js/main.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -5,7 +5,6 @@ import os
|
||||
import glob
|
||||
import tempfile
|
||||
import sys
|
||||
import locale
|
||||
|
||||
import default_settings
|
||||
sys.path.append(default_settings.LIBS_DIR)
|
||||
@@ -54,23 +53,6 @@ def dmerge(*args):
|
||||
return dictionary
|
||||
|
||||
|
||||
def get_pastes_count():
|
||||
"""
|
||||
Return the number of pastes created (must have option DISPLAY_COUNTER enabled)
|
||||
"""
|
||||
locale.setlocale(locale.LC_ALL, 'en_US')
|
||||
counter_path = settings.PASTE_FILES_ROOT
|
||||
counter_file = os.path.join(counter_path, 'counter')
|
||||
try:
|
||||
with open(counter_file, "r") as f:
|
||||
count = f.read(50)
|
||||
f.close
|
||||
except IOError:
|
||||
count = 0
|
||||
|
||||
return locale.format("%d", long(float(count)), grouping=True)
|
||||
|
||||
|
||||
class SettingsContainer(object):
|
||||
"""
|
||||
Singleton containing the settings for the whole app
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<script type="text/javascript">
|
||||
zerobin.paste_not_found = true;
|
||||
</script>
|
||||
|
||||
<p class="alert alert-error">
|
||||
<a class="close" data-dismiss="alert" href="#">×</a>
|
||||
<strong class="title">404 Error!</strong>
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
|
||||
%if settings.COMPRESSED_STATIC_FILES:
|
||||
<link href="/static/css/style.min.css" rel="stylesheet" />
|
||||
<link href="/static/css/style.min.css?{{ settings.VERSION }}"
|
||||
rel="stylesheet" />
|
||||
%else:
|
||||
<link href="/static/css/prettify.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?{{ settings.VERSION }}"
|
||||
rel="stylesheet">
|
||||
%end
|
||||
|
||||
<!-- Le HTML5 shim, for IE7-8 support of HTML5 elements -->
|
||||
@@ -25,11 +27,11 @@
|
||||
<![endif]-->
|
||||
|
||||
%if settings.COMPRESSED_STATIC_FILES:
|
||||
<script src="/static/js/main.min.js"></script>
|
||||
<script src="/static/js/main.min.js?{{ settings.VERSION }}"></script>
|
||||
%else:
|
||||
<script src="/static/js/jquery-1.7.2.min.js"></script>
|
||||
<script src="/static/js/sjcl.js"></script>
|
||||
<script src="/static/js/behavior.js"></script>
|
||||
<script src="/static/js/behavior.js?{{ settings.VERSION }}"></script>
|
||||
%end
|
||||
|
||||
<script type="text/javascript">
|
||||
@@ -126,10 +128,11 @@
|
||||
<small>Edgar Allan Poe</small>
|
||||
</blockquote>
|
||||
|
||||
|
||||
%if settings.DISPLAY_COUNTER:
|
||||
<h4 id="pixels-total" >
|
||||
<p>ø</p>
|
||||
<strong>{{ pastes_count }}</strong> </br>pastes øbinned
|
||||
<strong>{{ pastes_count }}</strong> <br/>pastes øbinned
|
||||
</h4>
|
||||
%end
|
||||
|
||||
@@ -143,7 +146,7 @@
|
||||
</footer>
|
||||
|
||||
%if settings.COMPRESSED_STATIC_FILES:
|
||||
<script src="/static/js/additional.min.js"></script>
|
||||
<script src="/static/js/additional.min.js?{{ settings.VERSION }}"></script>
|
||||
%else:
|
||||
<script src="/static/js/jquery.elastic.source.js"></script>
|
||||
<script src="/static/js/lzw.js"></script>
|
||||
@@ -156,6 +159,7 @@
|
||||
<strong class="title"></strong>
|
||||
<span class="message"></span>
|
||||
</p>
|
||||
</div><!--/wrap-content-->
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
@@ -1,31 +1,67 @@
|
||||
<div class="well">
|
||||
<div class="well" id="faq">
|
||||
|
||||
<h1>FAQ</h1>
|
||||
|
||||
%for i, entry in enumerate(settings.MENU):
|
||||
%if "mailto:" in entry[1]:
|
||||
<p>If a question does not appear here you can
|
||||
<span title="{{ entry[1].replace('mailto:', '').replace('@', '__AT__') }}"
|
||||
class="email-link" >
|
||||
contact us
|
||||
</span>.
|
||||
</p>
|
||||
%end
|
||||
%end
|
||||
|
||||
<hr width="90%">
|
||||
|
||||
<dl>
|
||||
|
||||
<dt>What's the name of the captain?</dt>
|
||||
<dd>The name of the captain is Igloo !</dd>
|
||||
</br>
|
||||
<dt>What's the name of the captain?</dt>
|
||||
<dd>The name of the captain is Igloo !</dd>
|
||||
</br>
|
||||
<dt>What's the name of the captain?</dt>
|
||||
<dd>The name of the captain is Igloo !</dd>
|
||||
|
||||
<dt>How does it work?</dt>
|
||||
<dd>
|
||||
<p>We generate a random key, and encrypt the paste with it using
|
||||
the <a href="http://crypto.stanford.edu/sjcl/">sjcl</a>
|
||||
javascript library.</p>
|
||||
<p>The content is sent encrypted to the server, which returns the
|
||||
address of the newly created paste.</p>
|
||||
<p>The javascript code then redirects to this address, but it adds the
|
||||
encryption key in the URL hash (#).</p>
|
||||
<p>When somebody want to read the paste, he usually just click on a link
|
||||
with this URL. If the hash containing the key is part of it, Obin's
|
||||
javascript will use it to decrypt the content sent by the server.</p>
|
||||
<p>The browser never sends the hash to the server, so it does not
|
||||
receives the key.</p>
|
||||
</dd>
|
||||
|
||||
<dt>Javascript encryption is not secure!</dt>
|
||||
<dd>
|
||||
<p>No it's not.</p>
|
||||
<p>The goal of 0bin is <strong>not</strong> to protect the users
|
||||
or their secrets.</p>
|
||||
<p>The goal is to make it hard to sue the host because of the
|
||||
content users pasted in his service. The idea is that you can not
|
||||
require somebody to moderate something he can't read</p>
|
||||
</dd>
|
||||
<dt>What if the server changes the Javascript code? Or in the case of a man
|
||||
in the middle attack?</dt>
|
||||
<dd>
|
||||
<p>Read above.</p>
|
||||
<p>0bin the is not built to protect the users content. It is built to
|
||||
protect the host. If the user content is compromised, 0bin still
|
||||
provides the host with the main feature: ignorance of the hosted content.</p>
|
||||
<p>The case where the host himself compromises the encryption process
|
||||
to read the content makes no sense: in that case he wouldn't have
|
||||
installed 0bin in the first place. 0bin is here to protect him.</p>
|
||||
<p><strong>If you want to be sure nobody can read your content, you should
|
||||
not use 0bin</strong>. Use
|
||||
<a href="https://crypto.cat/">cryptocat</a> (but JS crypto warnings apply)
|
||||
or <a href="http://www.cypherpunks.ca/otr/">OTR</a> for chatting,
|
||||
<a href="http://gnupg.org/">GPG</a>/<a href="http://enigmail.mozdev.org/home/index.php.html">enignmail</a>
|
||||
for emails and <a href="http://www.truecrypt.org/">TrueCrypt</a> for storage.</p>
|
||||
</dd>
|
||||
<dt>How did you come out with such a cool idea?</dt>
|
||||
<dd>
|
||||
<p>We didn't, we based 0bin on
|
||||
<a href="http://sebsauvage.net/paste/">sebsauvage's work</a>.</p>
|
||||
|
||||
<p>It was a reaction to
|
||||
<a href="https://www.zdnet.com/blog/security/pastebin-to-hunt-for-hacker-pastes-anonymous-cries-censorship/11336">Pastebin been forced to moderate its content</a>
|
||||
because of so many illegal stuffed posted to it. 0bin should be used the
|
||||
same way <a href="pastebin.com">Pastebin</a> is for users. The only
|
||||
difference is that if you host it, we hope the encryption
|
||||
feature can be used as a defense. This is not proven though :-)</p>
|
||||
|
||||
</dd>
|
||||
|
||||
</dl>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
<div class="well paste-form">
|
||||
<form action="/" method="get" accept-charset="utf-8">
|
||||
<p class="lnk-option">
|
||||
<a id="clip-button">Copy To Clipboard</a>
|
||||
|
|
||||
<a id="short-url" href=""
|
||||
target="_blank">Get short url</a>
|
||||
<a id="clip-button" href="#">Copy To Clipboard</a> |
|
||||
<a id="short-url" href="#">Get short url</a> |
|
||||
<a id="email-link" href="#">Email this</a>
|
||||
|
||||
<span class="paste-option btn-group top">
|
||||
<button class="btn btn-clone"><i class="icon-camera"></i> Clone</button>
|
||||
<button class="btn">New Paste</button>
|
||||
@@ -36,8 +36,13 @@
|
||||
<div class="bar"></div>
|
||||
</div>
|
||||
|
||||
%expiration = paste.humanized_expiration
|
||||
%if expiration:
|
||||
<p id="expiration-tag">Expire {{ expiration }}</p>
|
||||
%end
|
||||
|
||||
<p>
|
||||
<pre id="paste-content" class="prettyprint linenums">
|
||||
<pre id="paste-content" class="prettyprint">
|
||||
<code>
|
||||
{{ paste.content }}
|
||||
</code>
|
||||
@@ -66,14 +71,15 @@
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
<button class="btn btn-danger">Cancel clone</button>
|
||||
</p>
|
||||
<p>
|
||||
|
||||
<div>
|
||||
<div class="progress progress-striped active">
|
||||
<div class="bar"></div>
|
||||
</div>
|
||||
<textarea rows="10" style="width:100%;"
|
||||
class="input-xlarge"
|
||||
id="content" name="content"></textarea>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user