]>
Commit | Line | Data |
---|---|---|
a9f52ec5 IB |
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") |