def display_paste(paste_id): now = datetime.now() keep_alive = False try: paste = Paste.load(paste_id) # Delete the paste if it expired: if not isinstance(paste.expiration, datetime): # burn_after_reading contains the paste creation date # if this read appends 10 seconds after the creation date # we don't delete the paste because it means it's the redirection # 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 = now < keep_alive + timedelta(seconds=10) except IndexError: keep_alive = False if not keep_alive: paste.delete() elif paste.expiration < now: paste.delete() raise ValueError() except (TypeError, ValueError): return error404(ValueError) context = {'paste': paste, 'keep_alive': keep_alive} return dmerge(context, GLOBAL_CONTEXT)
def create_paste(): # Reject what is too small, too big, or what does not seem encrypted to # limit a abuses content = request.forms.get("content", "") if '{"iv":' not in content or not (0 < len(content) < settings.MAX_SIZE): return {"status": "error", "message": "Wrong data payload."} expiration = request.forms.get("expiration", "burn_after_reading") title = request.forms.get("title", "") paste = Paste( expiration=expiration, content=content, uuid_length=settings.PASTE_ID_LENGTH, title=title, ) paste.save() # If refresh time elapsed pick up, update the counter if settings.DISPLAY_COUNTER: paste.increment_counter() 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, "owner_key": paste.owner_key}
def delete_paste(quiet=False, *pastes): """ Remove pastes, given its ID or its URL quiet: Don't print anything pastes: List of pastes, given by ID or URL """ for paste_uuid in map(unpack_paste, pastes): try: Paste.load(paste_uuid).delete() if not quiet: print('Paste {} is removed'.format(paste_uuid)) except ValueError: if not quiet: print('Paste {} doesn\'t exist'.format(paste_uuid))
def create_paste(): try: body = urlparse.parse_qs( request.body.read(int(settings.MAX_SIZE * 1.1))) except ValueError: return {'status': 'error', 'message': "Wrong data payload."} try: content = "".join(x.decode('utf8') for x in body[b'content']) except (UnicodeDecodeError, KeyError): return { 'status': 'error', 'message': "Encoding error: the paste couldn't be saved." } if '{"iv":' not in content: # reject silently non encrypted content return {'status': 'error', 'message': "Wrong data payload."} # 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 0 < len(content) < settings.MAX_SIZE: expiration = body.get(b'expiration', ['burn_after_reading'])[0] paste = Paste(expiration=expiration.decode('utf8'), content=content, uuid_length=settings.PASTE_ID_LENGTH) paste.save() # display counter if settings.DISPLAY_COUNTER: #increment paste counter paste.increment_counter() # 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': "Serveur error: the paste couldn't be saved. " "Please try later." }
def delete_paste(paste_id): try: paste = Paste.load(paste_id) except (TypeError, ValueError): return error404(ValueError) if paste.owner_key != request.forms.get("owner_key", None): return HTTPResponse(status=403, body="Wrong owner key") paste.delete() return { "status": "ok", "message": "Paste deleted", }
def clean_expired_pastes( *, dry_run=False, verbose=False, config_dir="", data_dir="", ): """ Clean expired file pastes and empty paste directories This features delete files from the data dir, make sure it's safe. Use "dry_run" and "verbose" options to check first """ ensure_app_context(config_dir=config_dir, data_dir=data_dir) print("Deleting expired pastes...") i = 0 for p in Paste.iter_all(): if p.has_expired: if not dry_run: p.delete() if verbose: print(p.path, "has expired") i += 1 if dry_run: print(f"{i} pastes would have been deleted") else: print(f"{i} pastes deleted") print("Deleting empty paste directories...") i = 0 for p in settings.DATA_DIR.rglob("*"): try: if p.is_dir() and not next(p.iterdir(), None): if not dry_run: p.rmdir() if verbose: print(p, "is empty") i += 1 except OSError as e: print(f'Error while processing "{p}: {e}') if dry_run: print(f"{i} directories would have been deleted") else: print(f"{i} directories deleted") print("Done")
def admin(): session = request.environ.get("beaker.session") if not session or not session.get("is_authenticated"): redirect(ADMIN_LOGIN_URL) paste_id = request.forms.get("paste", "") if paste_id: try: if "/paste/" in paste_id: paste_id = urlparse(paste_id).path.split("/paste/")[-1] paste = Paste.load(paste_id) paste.delete() except (TypeError, ValueError, FileNotFoundError): return { "status": "error", "message": f"Cannot find paste '{paste_id}'", **GLOBAL_CONTEXT, } return {"status": "ok", "message": "Paste deleted", **GLOBAL_CONTEXT} return {"status": "ok", "message": "", **GLOBAL_CONTEXT}
def create_paste(): try: body = urlparse.parse_qs(request.body.read(int(settings.MAX_SIZE * 1.1))) except ValueError: return {'status': 'error', 'message': "Wrong data payload."} try: content = "".join(x.decode('utf8') for x in body[b'content']) except (UnicodeDecodeError, KeyError): return {'status': 'error', 'message': "Encoding error: the paste couldn't be saved."} if '{"iv":' not in content: # reject silently non encrypted content return {'status': 'error', 'message': "Wrong data payload."} # 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 0 < len(content) < settings.MAX_SIZE: expiration = body.get(b'expiration', ['burn_after_reading'])[0] paste = Paste(expiration=expiration.decode('utf8'), content=content, uuid_length=settings.PASTE_ID_LENGTH) paste.save() # display counter if settings.DISPLAY_COUNTER: #increment paste counter paste.increment_counter() # 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': "Serveur error: the paste couldn't be saved. " "Please try later."}
def post_admin_page(admin_url): # If ADMIN_SECRET doesn't exist, return 404 error if not hasattr(settings, 'ADMIN_SECRET'): return error404(ValueError) # Verification process admin_secret = settings.ADMIN_SECRET good_url = admin_url == admin_secret['url'] good_pwd = request.forms.get('inputPassword') == admin_secret['password'] if good_url and good_pwd: try: Paste(request.forms.get('inputUuid')).delete() confirmation = True except FileNotFoundError: confirmation = False else: confirmation = False # Confirmation evaluate to True if the paste has been removed, # or to False if an error occured return get_admin_page(admin_url, confirmation)
# add project dir and libs dir to the PYTHON PATH to ensure they are # importable from zerobin.utils import (settings, SettingsValidationError, drop_privileges, dmerge) import bottle from bottle import (Bottle, run, static_file, view, request) import clize from zerobin.paste import Paste app = Bottle() GLOBAL_CONTEXT = { 'settings': settings, 'pastes_count': Paste.get_pastes_count(), 'refresh_counter': datetime.now() } @app.route('/') @view('home') def index(): return GLOBAL_CONTEXT @app.route('/faq/') @view('faq') def faq(): return GLOBAL_CONTEXT
# add project dir and libs dir to the PYTHON PATH to ensure they are # importable from zerobin.utils import (settings, SettingsValidationError, drop_privileges, dmerge) import bottle from bottle import (Bottle, run, static_file, view, request) from zerobin.paste import Paste app = Bottle() GLOBAL_CONTEXT = { 'settings': settings, 'pastes_count': Paste.get_pastes_count(), 'refresh_counter': datetime.now() } @app.route('/') @view('home') def index(): return GLOBAL_CONTEXT @app.route('/faq/') @view('faq') def faq(): return GLOBAL_CONTEXT
from zerobin import __version__ from zerobin.utils import ( SettingsValidationError, ensure_app_context, check_password, settings, ) from zerobin.paste import Paste ensure_app_context() GLOBAL_CONTEXT = { "settings": settings, "VERSION": __version__, "pastes_count": Paste.get_pastes_count(), "refresh_counter": datetime.now(), } app = Bottle() ADMIN_LOGIN_URL = settings.ADMIN_URL + "login/" @app.route("/") @view("home") def index(): return GLOBAL_CONTEXT @app.get("/faq/")