diff options
Diffstat (limited to 'flakes/paste/paste/paste.py')
-rw-r--r-- | flakes/paste/paste/paste.py | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/flakes/paste/paste/paste.py b/flakes/paste/paste/paste.py new file mode 100644 index 0000000..86666b8 --- /dev/null +++ b/flakes/paste/paste/paste.py | |||
@@ -0,0 +1,124 @@ | |||
1 | import os | ||
2 | import secrets | ||
3 | from flask import Flask, abort, request, Response, url_for | ||
4 | from pygments.formatters.html import HtmlFormatter | ||
5 | from pygments import highlight | ||
6 | import pygments.lexers as lexers | ||
7 | import base64 | ||
8 | import magic | ||
9 | import mimetypes | ||
10 | |||
11 | magic = magic.Magic(mime=True) | ||
12 | |||
13 | config = { | ||
14 | "directory": os.environ["PASTE_DIRECTORY"], | ||
15 | "self_paste_id": "abcd123", | ||
16 | "max_content_length": 16 * 1000 * 1000 | ||
17 | } | ||
18 | |||
19 | app = Flask(__name__) | ||
20 | app.config['MAX_CONTENT_LENGTH'] = config["max_content_length"] | ||
21 | |||
22 | def file_location(paste_id): | ||
23 | if paste_id == config["self_paste_id"]: | ||
24 | return os.path.realpath(__file__) | ||
25 | else: | ||
26 | return os.path.join(config['directory'], paste_id + ".dat") | ||
27 | |||
28 | def read_paste(paste_id): | ||
29 | file = file_location(paste_id) | ||
30 | if os.path.isfile(file): | ||
31 | content = open(file, "rb").read() | ||
32 | mime = magic.from_buffer(content) | ||
33 | if mime.startswith("text/x-script."): | ||
34 | mime="text/plain" | ||
35 | return (content, mime) | ||
36 | else: | ||
37 | abort(404) | ||
38 | |||
39 | def generate_paste_id(n=3, attempts=0): | ||
40 | path = secrets.token_hex(n)[:n] | ||
41 | file = file_location(path) | ||
42 | if os.path.isfile(file): | ||
43 | attempts = attempts + 1 | ||
44 | if attempts > 5: | ||
45 | n = n + 1 | ||
46 | return generate_paste_id(n, attempts) | ||
47 | return path | ||
48 | |||
49 | @app.route('/', methods=["GET"]) | ||
50 | def index(): | ||
51 | return Response('''<pre> | ||
52 | $ curl -X POST --data-binary @{self} {host} | ||
53 | {paste} | ||
54 | |||
55 | -> GET {paste} | ||
56 | guesses mimetype | ||
57 | -> GET {paste}/raw | ||
58 | text/plain | ||
59 | -> GET {paste}/bin | ||
60 | application/octet-stream | ||
61 | -> GET {paste}/b64 | ||
62 | base64 encoded | ||
63 | -> GET {paste}/ub64 | ||
64 | tries to decode base64 | ||
65 | -> GET {paste}/python | ||
66 | pretty-print python (replace with anything known by pygments) | ||
67 | -> GET {paste}/guess | ||
68 | pretty-print (language guessed by pygments) | ||
69 | -> GET {paste}/download | ||
70 | force download of file | ||
71 | </pre> | ||
72 | <a href="{paste}/py">Get the source</a> | ||
73 | '''.format(host=url_for('post_paste', _external=True, _scheme="https"), | ||
74 | paste=url_for('get_paste', _external=True, _scheme="https", paste_id=config["self_paste_id"]), | ||
75 | self=os.path.basename(__file__) | ||
76 | ), mimetype="text/html") | ||
77 | |||
78 | @app.route('/', methods=["POST"]) | ||
79 | def post_paste(): | ||
80 | content = request.get_data() | ||
81 | paste_id = generate_paste_id() | ||
82 | with open(file_location(paste_id), "wb") as f: | ||
83 | f.write(content) | ||
84 | return url_for('get_paste', _external=True, _scheme="https", paste_id=paste_id) + "\n" | ||
85 | |||
86 | |||
87 | @app.route('/<paste_id>', methods=["GET"]) | ||
88 | def get_paste(paste_id): | ||
89 | content, mime = read_paste(paste_id) | ||
90 | return Response(content, mimetype=mime) | ||
91 | |||
92 | @app.route('/<paste_id>/<lang>', methods=["GET"]) | ||
93 | def get_paste_with(paste_id, lang): | ||
94 | content, mime = read_paste(paste_id) | ||
95 | if lang == "raw": | ||
96 | return Response(content, mimetype="text/plain") | ||
97 | elif lang == "bin": | ||
98 | return Response(content, mimetype="application/octet-stream") | ||
99 | elif lang == "b64": | ||
100 | return Response(base64.encodebytes(content), mimetype="text/plain") | ||
101 | elif lang == "download": | ||
102 | extension = mimetypes.guess_extension(mime, strict=False) | ||
103 | if extension is None: | ||
104 | cd = "attachment" | ||
105 | else: | ||
106 | cd = 'attachment; filename="{}{}"'.format(paste_id, extension) | ||
107 | return Response(content, mimetype=mime, | ||
108 | headers={"Content-Disposition": cd}) | ||
109 | elif lang == "ub64": | ||
110 | try: | ||
111 | return base64.b64decode(content) | ||
112 | except: | ||
113 | abort(400) | ||
114 | try: | ||
115 | if lang == "guess": | ||
116 | lexer = lexers.guess_lexer(content) | ||
117 | else: | ||
118 | lexer = lexers.find_lexer_class_by_name(lang)() | ||
119 | except: | ||
120 | abort(400) | ||
121 | fmter = HtmlFormatter( | ||
122 | noclasses=True, full=True, style="colorful", linenos="table") | ||
123 | |||
124 | return Response(highlight(content, lexer, fmter), mimetype="text/html") | ||