-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.py
executable file
·110 lines (86 loc) · 3.44 KB
/
server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#!/usr/bin/env python3
import os
import pwd
import argparse
from flask import Flask, request, jsonify, send_from_directory
from werkzeug.utils import secure_filename
parser = argparse.ArgumentParser(description='HTTP(s) web file server for just uploading files')
parser.add_argument('-u', '--user', metavar='user', type=str, help="user that should own the uploaded files")
parser.add_argument('-i', '--ip', metavar='string', type=str, default="0.0.0.0", help="IP for the server (default: '0.0.0.0' - all ips)")
parser.add_argument('-p', '--port', metavar='string', type=str, default="443", help="port for the server (default: '443' - https)")
parser.add_argument('-v', '--verbose', action="store_true", help="verbose output")
parser.add_argument('-d', '--directory', type=str, help="directory to save files to")
parser.add_argument('-n', '--nossl', action="store_true", help="don't use https")
args = parser.parse_args()
if not args.nossl:
from flask_sslify import SSLify
if args.verbose:
print(args)
# Get the UID and GID of the specified user
if args.user:
try:
pw_record = pwd.getpwnam(args.user)
user_uid = pw_record.pw_uid
user_gid = pw_record.pw_gid
except KeyError:
print(f"User {args.user} does not exist.")
exit(1)
else:
user_uid = os.getuid()
user_gid = os.getgid()
app = Flask(
__name__,
static_url_path='',
static_folder="static/"
)
if not args.nossl:
sslify = SSLify(app)
UPLOAD_FOLDER = '.'
if args.directory is not None:
UPLOAD_FOLDER = args.directory
# Ensure upload directory exists
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
@app.route('/')
def index():
return send_from_directory('templates', 'index.html')
@app.route('/upload', methods=['POST'])
def upload_files():
if not request.content_length:
return jsonify({'error': 'No content length provided'}), 411
if request.content_length > 0:
filenames = []
failed_files = []
CHUNK_SIZE = 8192 # Define the chunk size to write in small parts
try:
# Save the file directly from the stream, without holding the file in memory
filename = request.headers.get('X-File-Name', 'uploaded_file')
filename = secure_filename(filename) # Sanitize the filename
filepath = os.path.join(UPLOAD_FOLDER, filename)
if args.verbose:
print(f"saving: {filename}")
# Write the file in chunks
with open(filepath, 'wb') as f:
while True:
chunk = request.stream.read(CHUNK_SIZE)
if not chunk:
break
f.write(chunk)
if args.verbose:
print(f"saved: {filename}")
# Change ownership of the file to the specified user
if args.verbose:
print(f"chown[{args.user}] {filepath}")
os.chown(filepath, user_uid, user_gid)
filenames.append(filename)
except Exception as e:
failed_files.append(str(e))
if failed_files:
return jsonify({'filenames': filenames, 'errors': failed_files}), 500
return jsonify({'filenames': filenames}), 200
else:
return jsonify({'error': 'File too large or no file uploaded'}), 413
if __name__ == '__main__':
if not args.nossl:
app.run(host=args.ip, port=args.port, ssl_context='adhoc')
else:
app.run(host=args.ip, port=args.port)