Created
January 9, 2024 11:00
-
-
Save mcarletti/3a8f73d9d63708d3a342f4d1889ddc62 to your computer and use it in GitHub Desktop.
Share a folder to the local network in Python. Features: credentials, timeout.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# With this script you can easily share a folder from your PC to the local network. | |
# The script creates an HTTP server protected by credentials. Basic auth only: encryption certificate not included. | |
# The server stops after a timeout is triggered (default: 1h). | |
# | |
# Example | |
# ------- | |
# python http_server_auth.py --username u53r --password p4Sw0rd --directory ~/Public | |
# | |
# Anyone on the local network can access your Public folder in your home, typing your local address+port in a browser (eg. 157.27.93.172:8000). | |
# | |
# Requirements | |
# ------------ | |
# pip install timeout_decorator | |
import argparse, base64 | |
from timeout_decorator import timeout | |
from functools import partial | |
from http.server import SimpleHTTPRequestHandler, test | |
class AuthHTTPRequestHandler(SimpleHTTPRequestHandler): | |
""" | |
Main class to present webpages and authentication. | |
""" | |
def __init__(self, *args, **kwargs): | |
username = kwargs.pop("username") | |
password = kwargs.pop("password") | |
self._auth = base64.b64encode(f"{username}:{password}".encode()).decode() | |
super().__init__(*args, **kwargs) | |
def do_HEAD(self): | |
self.send_response(200) | |
self.send_header("Content-type", "text/html") | |
self.end_headers() | |
def do_AUTHHEAD(self): | |
self.send_response(401) | |
self.send_header("WWW-Authenticate", 'Basic realm="Test"') | |
self.send_header("Content-type", "text/html") | |
self.end_headers() | |
def do_GET(self): | |
""" | |
Present frontpage with user authentication. | |
""" | |
if self.headers.get("Authorization") == None: | |
self.do_AUTHHEAD() | |
self.wfile.write(b"no auth header received") | |
elif self.headers.get("Authorization") == "Basic " + self._auth: | |
SimpleHTTPRequestHandler.do_GET(self) | |
else: | |
self.do_AUTHHEAD() | |
self.wfile.write(self.headers.get("Authorization").encode()) | |
self.wfile.write(b"not authenticated") | |
if __name__ == "__main__": | |
parser = argparse.ArgumentParser() | |
# authorization settings | |
parser.add_argument("--username", metavar="USERNAME", required=True, type=str, help="Username for basic auth.") | |
parser.add_argument("--password", metavar="PASSWORD", required=True, type=str, help="Password for basic auth.") | |
# server settings | |
parser.add_argument("--host", metavar="ADDRESS", default="0.0.0.0", type=str, help="Server address to be bind. It is accessible from local network. Example: 127.0.0.1 (localhost), 0.0.0.0 (all interfaces) [default: %(default)s]") | |
parser.add_argument("--port", metavar="PORT", default=8000, type=int, help="Server port [default: %(default)s]") | |
parser.add_argument("--directory", metavar="FOLDER", default=".", type=str, help="Path to directory to be shared [default: %(default)s]") | |
# others | |
parser.add_argument("--timeout", metavar="SECONDS", default=3600, type=int, help="Timeout for HTTP requests [default: %(default)s]") | |
args = parser.parse_args() | |
try: | |
# add a timeout to the test function | |
test = timeout(args.timeout)(test) | |
# create a partial class with the username and password | |
handler_class = partial(AuthHTTPRequestHandler, username=args.username, password=args.password, directory=args.directory) | |
# run the server | |
test(HandlerClass=handler_class, bind=args.host, port=args.port) | |
except TimeoutError: | |
print(f"Timeout of {args.timeout} seconds reached.") | |
except Exception as e: | |
print(f"Error: {e}") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment