summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimeon Simeonov2023-07-07 10:04:04 +0200
committerSimeon Simeonov2023-07-07 10:04:04 +0200
commitc4cc9c90b3546e72efbaeb9cb632b9d98288bac1 (patch)
treec3ca05b349f719ecc1afd2ebb7016373f030d7c1
parente62d7c5ea3bc014123cf6f78e5345c588cd4f068 (diff)
Add basic https support and format the code using black -S
-rw-r--r--README.md20
-rw-r--r--src/ngus/__main__.py103
2 files changed, 95 insertions, 28 deletions
diff --git a/README.md b/README.md
index 670720a..b5409c6 100644
--- a/README.md
+++ b/README.md
@@ -31,8 +31,8 @@ To my amazement I wasn't able to find any free software matching that criteria.
31The main purpose of *ngus* is to accept file uploads as POST requests from an 31The main purpose of *ngus* is to accept file uploads as POST requests from an
32HTTP client. 32HTTP client.
33 33
34Currently *ngus* does not provide encryption (HTTPS) support. Many different 34Currently *ngus* provides only simple encryption (HTTPS) support. Many
35tools can be employed to serve as an HTTPS proxy. 35different tools can be employed to serve as an HTTPS proxy.
36 36
37See the examples bellow for more details! 37See the examples bellow for more details!
38 38
@@ -49,7 +49,9 @@ See the examples bellow for more details!
49### Gentoo 49### Gentoo
50 50
51 ```bash 51 ```bash
52 layman -a sgs 52 # add sgs' custom repository using app-eselect/eselect-repository
53 eselect repository add sgs
54
53 emerge www-servers/ngus 55 emerge www-servers/ngus
54 ``` 56 ```
55 57
@@ -107,6 +109,16 @@ The default form input field name is *ufile*. That can be changed by using the
107 curl --basic -u uname -F "uploadfile=@myfile.zip" http://158.39.125.240:8080 109 curl --basic -u uname -F "uploadfile=@myfile.zip" http://158.39.125.240:8080
108 ``` 110 ```
109 111
112Simple encryption (HTTPS) support
113
114 ```bash
115 # creating a self-signed key / certificate pair valid for 356 days
116 openssl req -sha256 -newkey rsa:4096 -nodes -x509 -extensions v3_ca -subj "/C=NO/O=MyOrg/CN=uploads.myhostname.net" -days 365 -keyout uploads.myhostname.net.key.pem -out uploads.myhostname.net.cert.pem
117 python -m ngus -H 0.0.0.0 -p 8080 -b "uname:foo" -k uploads.myhostname.net.key.pem -c uploads.myhostname.net.cert.pem -u /home/s/uploads
118 # since the certificate is self-signed, it can serve as a CA to itself in this example
119 curl --basic -u uname -F "ufile=@myfile.zip" --cacert uploads.myhostname.net.cert.pem https://uploads.myhostname.net:8080
120 ```
121
110 122
111### Using *nginx* as a proxy 123### Using *nginx* as a proxy
112 124
@@ -138,7 +150,7 @@ described in the examples above.
138 150
139 location / { 151 location / {
140 # point at the ngus instance running on a private network address 152 # point at the ngus instance running on a private network address
141 proxy_pass http://192.168.1.240:8080/; 153 proxy_pass http://158.39.125.240:8080/;
142 } 154 }
143 155
144 } 156 }
diff --git a/src/ngus/__main__.py b/src/ngus/__main__.py
index efa2c4a..a1f3992 100644
--- a/src/ngus/__main__.py
+++ b/src/ngus/__main__.py
@@ -18,6 +18,7 @@ import argparse
18import base64 18import base64
19import logging 19import logging
20import pathlib 20import pathlib
21import ssl
21import sys 22import sys
22 23
23import ngus 24import ngus
@@ -31,75 +32,129 @@ def eprint(*arg, **kwargs):
31def main(inargs=None): 32def main(inargs=None):
32 """main entry point""" 33 """main entry point"""
33 parser = argparse.ArgumentParser( 34 parser = argparse.ArgumentParser(
34 description='The following options are available') 35 description='The following options are available'
36 )
35 parser.add_argument( 37 parser.add_argument(
36 '-b', '--basic-auth', 38 '-b',
39 '--basic-auth',
37 metavar='<username:password>', 40 metavar='<username:password>',
38 type=str, 41 type=str,
39 dest='basic_auth', 42 dest='basic_auth',
40 default='', 43 default='',
41 help=('Require Basic auth from the client in order to POST a file ' 44 help=(
42 '(default: No basic auth required)')) 45 'Require Basic auth from the client in order to POST a file '
46 '(default: No basic auth required)'
47 ),
48 )
43 parser.add_argument( 49 parser.add_argument(
44 '-H', '--hostname', 50 '-H',
51 '--hostname',
45 metavar='<hostname>', 52 metavar='<hostname>',
46 type=str, 53 type=str,
47 dest='hostname', 54 dest='hostname',
48 default='127.0.0.1', 55 default='127.0.0.1',
49 help='ngus server IP / hostname (default: 127.0.0.1)') 56 help='ngus server IP / hostname (default: 127.0.0.1)',
57 )
50 parser.add_argument( 58 parser.add_argument(
51 '-i', '--input-name', 59 '-c',
60 '--certfile',
61 metavar='<certfile>',
62 type=pathlib.Path,
63 dest='certfile',
64 default=None,
65 help=(
66 'Certfile (PEM) for TLS/SSL connections '
67 '(default: SSL/TLS disabled)'
68 ),
69 )
70 parser.add_argument(
71 '-i',
72 '--input-name',
52 metavar='<name>', 73 metavar='<name>',
53 type=str, 74 type=str,
54 dest='input_name', 75 dest='input_name',
55 default='ufile', 76 default='ufile',
56 help='The name of the form input field (default: "ufile")') 77 help='The name of the form input field (default: "ufile")',
78 )
79 parser.add_argument(
80 '-k',
81 '--keyfile',
82 metavar='<keyfile>',
83 type=pathlib.Path,
84 dest='keyfile',
85 default=None,
86 help='Keyfile for TLS/SSL connections (default: SSL/TLS disabled)',
87 )
57 parser.add_argument( 88 parser.add_argument(
58 '-p', '--port', 89 '-p',
90 '--port',
59 metavar='<port>', 91 metavar='<port>',
60 type=int, 92 type=int,
61 dest='port', 93 dest='port',
62 default=8080, 94 default=8080,
63 help='ngus server port (default: 8080)') 95 help='ngus server port (default: 8080)',
96 )
64 parser.add_argument( 97 parser.add_argument(
65 '-u', '--upload-dir', 98 '-u',
99 '--upload-dir',
66 metavar='<dir>', 100 metavar='<dir>',
67 type=pathlib.Path, 101 type=pathlib.Path,
68 dest='upload_dir', 102 dest='upload_dir',
69 default=pathlib.Path.cwd(), 103 default=pathlib.Path.cwd(),
70 help='ngus server upload dir (default: CWD)') 104 help='ngus server upload dir (default: CWD)',
105 )
71 parser.add_argument( 106 parser.add_argument(
72 '-U', '--upload-page', 107 '-U',
108 '--upload-page',
73 metavar='<filename>', 109 metavar='<filename>',
74 type=argparse.FileType('rb'), 110 type=argparse.FileType('rb'),
75 dest='upload_page', 111 dest='upload_page',
76 default=None, 112 default=None,
77 help='Alternative upload page (form) to display (default: None)') 113 help='Alternative upload page (form) to display (default: None)',
114 )
78 parser.add_argument( 115 parser.add_argument(
79 '-v', '--version', 116 '-v',
117 '--version',
80 action='version', 118 action='version',
81 version=f'%(prog)s {ngus.__version__}', 119 version=f'%(prog)s {ngus.__version__}',
82 help='Display program-version and exit') 120 help='Display program-version and exit',
121 )
83 args = parser.parse_args(inargs) 122 args = parser.parse_args(inargs)
84 try: 123 try:
85 logging.basicConfig(format='%(asctime)s - %(levelname)s - %(message)s', 124 logging.basicConfig(
86 level=logging.DEBUG) 125 format='%(asctime)s - %(levelname)s - %(message)s',
126 level=logging.DEBUG,
127 )
87 logger = logging.getLogger('ngus') 128 logger = logging.getLogger('ngus')
88 logger.info('ngus starting') 129 logger.info('ngus starting')
89 server_params = { 130 server_params = {
90 'input_name': args.input_name, 131 'input_name': args.input_name,
91 'upload_dir': args.upload_dir 132 'upload_dir': args.upload_dir,
92 } 133 }
93 if args.upload_page is not None: 134 if args.upload_page is not None:
94 server_params['upload_page'] = args.upload_page.read() 135 server_params['upload_page'] = args.upload_page.read()
95 if args.basic_auth and len(args.basic_auth.split(':')) == 2: 136 if args.basic_auth and len(args.basic_auth.split(':')) == 2:
96 server_params['basic_auth'] = base64.b64encode( 137 server_params['basic_auth'] = base64.b64encode(
97 args.basic_auth.strip().encode('utf-8')).decode() 138 args.basic_auth.strip().encode('utf-8')
139 ).decode()
98 logger.info('Requiring basic-auth') 140 logger.info('Requiring basic-auth')
99 ngus_server = ngus.NgusHTTPServer((args.hostname, args.port), 141 ngus_server = ngus.NgusHTTPServer(
100 ngus.NgusBaseHTTPRequestHandler, 142 (args.hostname, args.port),
101 **server_params) 143 ngus.NgusBaseHTTPRequestHandler,
102 logger.info(f'Listening on {args.hostname}:{args.port}') 144 **server_params,
145 )
146 if args.certfile and args.keyfile:
147 context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
148 context.load_cert_chain(
149 certfile=args.certfile, keyfile=args.keyfile
150 )
151 ngus_server.socket = context.wrap_socket(
152 ngus_server.socket, server_side=True
153 )
154 logger.info(
155 f'Listening on {args.hostname}:{args.port}'
156 f'{" (SSL/TLS)" if args.certfile and args.keyfile else ""}'
157 )
103 logger.info('Done!') 158 logger.info('Done!')
104 ngus_server.serve_forever() 159 ngus_server.serve_forever()
105 except KeyboardInterrupt: 160 except KeyboardInterrupt: