Skip to content

Instantly share code, notes, and snippets.

@mcarletti
Created January 9, 2024 11:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mcarletti/3a8f73d9d63708d3a342f4d1889ddc62 to your computer and use it in GitHub Desktop.
Save mcarletti/3a8f73d9d63708d3a342f4d1889ddc62 to your computer and use it in GitHub Desktop.
Share a folder to the local network in Python. Features: credentials, timeout.
# 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