From 013effb9af8ab5426c367a15f4c3def9e9ee673b Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 25 Oct 2017 04:38:17 +0200 Subject: Initial version --- Makefile | 30 ++++++++++++++++++++ README.md | 45 ++++++++++++++++++++++++++++++ __init__.py | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ app.cfg | 5 ++++ deployment-config.mk | 4 +++ 5 files changed, 161 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 __init__.py create mode 100644 app.cfg create mode 100644 deployment-config.mk diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a4b2b97 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +.PHONY: deploy + +include deployment-config.mk + +SSH_OPTS := -q -o ControlMaster=auto -o ControlPath=.ssh-deployment.sock + +deploy: + @echo " SSH $(WEB_SERVER)" + @ssh $(SSH_OPTS) -Nf $(WEB_SERVER) + + @echo " RSYNC . $(WEB_SERVER):$(FLASK_PATH)" + @ssh -t $(SSH_OPTS) $(WEB_SERVER) "sudo -u $(FLASK_USER) -v" + @rsync -aizm --delete-excluded --exclude=.ssh-deployment.sock --exclude=.git --exclude=Makefile --exclude="*.pyc" --exclude="*.mk" --exclude=.gitignore --exclude="*.swp" \ + --filter="P pastes/" --rsh="ssh $(SSH_OPTS)" --rsync-path="sudo -n -u $(FLASK_USER) rsync" \ + . "$(WEB_SERVER):$(FLASK_PATH)" + + @echo " CHMOD 750/640 $(WEB_SERVER):$(FLASK_PATH)/*" + @ssh -t $(SSH_OPTS) $(WEB_SERVER) "sudo find -P '$(FLASK_PATH)' \! -path '$(FLASK_PATH)/pastes/*' -type f -exec chmod 640 {} \;; \ + sudo find -P '$(FLASK_PATH)' \! -path '$(FLASK_PATH)/pastes/*' -type d -exec chmod 750 {} \;;" + + @echo " CHOWN $(FLASK_USER):$(NGINX_USER) $(WEB_SERVER):$(FLASK_PATH)/pastes" + @ssh -t $(SSH_OPTS) $(WEB_SERVER) "sudo mkdir -p '$(FLASK_PATH)/pastes'; sudo chown $(FLASK_USER):$(NGINX_USER) '$(FLASK_PATH)' '$(FLASK_PATH)/pastes'" + @echo " CHMOD 710 $(WEB_SERVER):$(FLASK_PATH)" + @ssh -t $(SSH_OPTS) $(WEB_SERVER) "sudo chmod 710 '$(FLASK_PATH)'" + + @echo " UWSGI restart $(WEB_SERVER)" + @ssh -t $(SSH_OPTS) $(WEB_SERVER) "sudo /etc/init.d/uwsgi restart" + + @echo " SSH $(WEB_SERVER)" + @ssh -O exit $(SSH_OPTS) $(WEB_SERVER) diff --git a/README.md b/README.md new file mode 100644 index 0000000..450502e --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +## [Aleph Paste](https://git.zx2c4.com/alephpaste/about) +#### by [Jason A. Donenfeld](mailto:jason@zx2c4.com) + +This is a basic boring private pastebin. It doesn't do much. + + - https://א.cc/ID -- plain text + - https://א.cc/ID/ -- auto-guess syntax highlighting + - https://א.cc/ID/LANG -- use LANG syntax highlighting + +### NGINX Configuration Block + +``` +location / { + include uwsgi_params; + uwsgi_pass unix:/var/run/uwsgi-apps/alephpaste.socket; +} +location /pastes/ { + internal; + alias /var/www/uwsgi/alephpaste/pastes/; +} +``` + +### CLI Script + +``` +#!/bin/bash +DOMAIN="https://א.cc" +alp() { + local opts="--basic --user zx2c4:hGha6tahjofaip4Osa7" + while getopts ":hd:" x; do + case $x in + h) echo "alp [-d ID]"; return;; + d) curl $opts -X DELETE "$DOMAIN"/$OPTARG; return;; + esac + done + trap 'rm -f "$file"' EXIT + file="$(mktemp)" + cat > "$file" + url="$(curl $opts -F "paste=@$file" "$DOMAIN")" + xclip -selection clipboard <<<"$url" + echo "$url" +} + +alp $* +``` diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..4c7f696 --- /dev/null +++ b/__init__.py @@ -0,0 +1,77 @@ +from pygments.lexers import guess_lexer, guess_lexer_for_filename +from pygments.formatters import HtmlFormatter +from pygments import highlight +from flask import Flask, Response, request, abort, redirect +from random import SystemRandom +from functools import wraps +import string +import os.path + +app = Flask(__name__) +app.config.from_pyfile(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'app.cfg')) +rng = SystemRandom() + +def check_auth(username, password): + # Side channel attack on string comparison! + return username == app.config['USERNAME'] and password == app.config['PASSWORD'] + +def requires_auth(f): + @wraps(f) + def decorated(*args, **kwargs): + auth = request.authorization + if not auth or not check_auth(auth.username, auth.password): + return Response('Wrong username/password', 401, {'WWW-Authenticate': 'Basic realm="Aleph Paste"'}) + return f(*args, **kwargs) + return decorated + +@app.route('/') +def landing(): + return redirect('https://git.zx2c4.com/alephpaste/about/', code=302) + +@app.route('/', methods=['POST']) +@requires_auth +def new_paste(): + if 'paste' not in request.files: + abort(400) + while True: + paste = ''.join(rng.choice(string.ascii_letters + string.digits) for _ in range(8)) + file_name = os.path.join(app.config['FILES_PATH'], paste + '.txt') + if not os.path.exists(file_name): + break + f = request.files['paste'] + f.save(file_name) + f.close() + return app.config['URI_BASE'] + '/' + paste + '\n' + + +@app.route('/', methods=['DELETE']) +@requires_auth +def delete_paste(paste): + try: + os.unlink(os.path.join(app.config['FILES_PATH'], paste + '.txt')) + except: + abort(404) + return '' + +@app.route('/') +def send_paste(paste): + return Response(mimetype='text/plain', headers={'X-Accel-Redirect': os.path.join(app.config['FILES_ACCEL'], paste + '.txt')}) + +@app.route('//') +def send_highlighted_paste_guess(paste): + return send_highlighted_paste(paste, None) + +@app.route('//') +def send_highlighted_paste(paste, ftype): + try: + f = open(os.path.join(app.config['FILES_PATH'], paste + '.txt'), 'r') + text = f.read() + f.close() + if ftype is None or len(ftype) == 0: + lexer = guess_lexer(text) + else: + lexer = guess_lexer_for_filename(paste + '.' + ftype, text) + formatter = HtmlFormatter(style='pastie', full=True, title='{0} - Aleph Paste'.format(paste), linenos='table', anchorlinenos=True, lineanchors="line") + return highlight(text, lexer, formatter) + except: + return send_paste(paste) diff --git a/app.cfg b/app.cfg new file mode 100644 index 0000000..89bf1cf --- /dev/null +++ b/app.cfg @@ -0,0 +1,5 @@ +FILES_PATH = "/var/www/uwsgi/alephpaste/pastes" +FILES_ACCEL = "/pastes" +USERNAME = "zx2c4" +PASSWORD = "hGha6tahjofaip4Osa7" +URI_BASE = "https://א.cc" diff --git a/deployment-config.mk b/deployment-config.mk new file mode 100644 index 0000000..114382a --- /dev/null +++ b/deployment-config.mk @@ -0,0 +1,4 @@ +WEB_SERVER := metheny.zx2c4.com +NGINX_USER := nginx +FLASK_USER := alephpaste +FLASK_PATH := /var/www/uwsgi/alephpaste -- cgit v1.2.3-59-g8ed1b