forked from Red-Eyed/python_ftp_server
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathftp_server.py
More file actions
158 lines (121 loc) · 4.62 KB
/
Copy pathftp_server.py
File metadata and controls
158 lines (121 loc) · 4.62 KB
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import logging
__author__ = "Vadym Stupakov"
__maintainer__ = "Vadym Stupakov"
__email__ = "vadim.stupakov@gmail.com"
import argparse
import platform
import random
import socket
import string
from pathlib import Path
import requests
from OpenSSL import crypto, SSL
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import TLS_FTPHandler, FTPHandler
from pyftpdlib.servers import FTPServer as FTPServer
logging.basicConfig(level=logging.INFO)
def generate_password(strength):
chars = string.ascii_letters
passwd = "".join(random.choice(chars) for i in range(strength))
return passwd
def get_local_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('192.255.255.255', 1))
ip = s.getsockname()[0]
except:
ip = '127.0.0.1'
finally:
s.close()
return ip
def get_hostname():
return socket.gethostname()
def get_public_ip():
return requests.get('http://ip.42.pl/raw').text
def create_self_signed_cert(cert_file: Path, key_file: Path):
if cert_file.exists() and key_file.exists():
return
else:
try:
cert_file.unlink()
key_file.unlink()
except FileNotFoundError:
print("Generating cert files")
# create a key pair
k = crypto.PKey()
k.generate_key(crypto.TYPE_RSA, 2048)
# create a self-signed cert
cert = crypto.X509()
cert.set_version(2)
cert.set_serial_number(random.randint(50000000, 100000000))
cert.get_subject().CN = get_hostname()
cert.gmtime_adj_notBefore(0)
cert.gmtime_adj_notAfter(10 * 365 * 24 * 60 * 60)
cert.set_issuer(cert.get_subject())
cert.set_pubkey(k)
cert.set_pubkey(k)
cert.sign(k, 'sha256')
with open(str(cert_file), "wt") as f:
f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode("utf8"))
with open(str(key_file), "wt") as f:
f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k).decode("utf8"))
def main():
example_text = "example:\n" \
" {0} -u user -p password\n" \
" {0} -u user -p password --readonly\n" \
" {0} -u user -p password --dir /tmp\n".format(__file__)
parser = argparse.ArgumentParser(prog="ftp_server",
description="FTP server for file sharing over internet or local network",
epilog=example_text,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("--tls", action="store_true")
parser.add_argument("-u", "--user", type=str, default="user")
parser.add_argument("-p", "--password", type=str, default=generate_password(strength=20))
parser.add_argument("-r", "--readonly", action="store_true")
parser.add_argument("-d", "--dir", type=Path, default=Path().cwd())
parser.add_argument("-g", "--use_public", action="store_true")
parser.add_argument("--ip", type=str, default=get_local_ip())
parser.add_argument("--port", type=int, default=60000)
parser.add_argument("--port_range", default=range(60001, 60101))
args = parser.parse_args()
if args.use_public:
args.ip = get_public_ip()
perm_read = "elr"
perm_write = "adfmw"
permissions = perm_read + perm_write
if args.readonly:
permissions = perm_read
authorizer = DummyAuthorizer()
authorizer.add_user(args.user, args.password, str(args.dir), perm=permissions)
if args.tls:
handler = TLS_FTPHandler
temp_dir = Path(__file__).absolute().parent / "temp"
temp_dir.mkdir(exist_ok=True)
cert_file = temp_dir / "cert_file.crt"
key_file = temp_dir / "key_file.key"
create_self_signed_cert(cert_file, key_file)
handler.certfile = str(cert_file.absolute())
handler.keyfile = str(key_file.absolute())
handler.tls_control_required = True
handler.tls_data_required = True
handler.ssl_protocol = SSL.TLSv1_2_METHOD
else:
handler = FTPHandler
handler.passive_ports = args.port_range
handler.authorizer = authorizer
if "Linux" in platform.system():
handler.use_sendfile = True
server = FTPServer((args.ip, args.port), handler)
print("\n\n\n\n")
print(f"Local address: ftp://{args.ip}:{args.port}")
if args.use_public:
print(f"Global address: ftp://{args.ip}:{args.port}")
print(f"User: {args.user}")
print(f"Password: {args.password}")
print()
server.serve_forever()
if __name__ == '__main__':
main()