#! /usr/bin/env bash # # The authors of this file have waived all copyright and # related or neighboring rights to the extent permitted by # law as described by the CC0 1.0 Universal Public Domain # Dedication. You should have received a copy of the full # dedication along with this file, typically as a file # named . If not, it may be available at # . # # # This is Qhttpd, a simple web server. # # See . # #----------------------------------------------------------------------- # Set up initial error handling #----------------------------------------------------------------------- set -e -u || exit #----------------------------------------------------------------------- # Set up qsh #----------------------------------------------------------------------- # # This section was generated using qsh. # See . # # The authors of this section have waived all copyright and # related or neighboring rights to the extent permitted by # law as described by the CC0 1.0 Universal Public Domain # Dedication. You should have received a copy of the full # dedication along with this file, typically as a file # named . If not, it may be available at # . # qsh_barf() { case $# in (0) set "Unknown error" esac qsh_barf_message="$0: Error:" for qsh_barf_text; do qsh_barf_message="$qsh_barf_message $qsh_barf_text" done qsh_barf_message=$qsh_barf_message. printf '%s\n' "$qsh_barf_message" >&2 exit "${qsh_exit_status-1}" } #----------------------------------------------------------------------- # Set up Bash #----------------------------------------------------------------------- case ${BASH_VERSINFO-} in ('' | *[!0-9]* | 0* | [0-4]) qsh_barf \ "This script requires Bash version 5.0 or later." \ "You have version ${BASH_VERSION-unknown}" \ ; esac set -o pipefail shopt -s \ inherit_errexit \ ; #----------------------------------------------------------------------- cert=${HOME?}/.qhttpd/cert.pem readonly cert key=${HOME?}/.qhttpd/key.pem readonly key unset cert_found if test -f "${cert?}"; then printf '%s\n' "Certificate found: ${cert?}" || exit $? cert_found=1 else printf '%s\n' "Certificate not found: ${cert?}" || exit $? cert_found=0 fi readonly cert_found unset key_found if test -f "${key?}"; then printf '%s\n' "Key found: ${key?}" || exit $? key_found=1 else printf '%s\n' "Key not found: ${key?}" || exit $? key_found=0 fi readonly key_found unset regen case ${cert_found?}${key_found?} in 11) if openssl x509 -checkend 31536000 -in "${cert?}"; then printf '%s\n' "Certificate is good for a while" || exit $? a=`openssl x509 -modulus -in "${cert?}" -noout | openssl sha256` || exit $? b=`openssl rsa -modulus -in "${key?}" -noout | openssl sha256` || exit $? case ${a?} in "${b?}") printf '%s\n' "Certificate matches key" || exit $? regen=0 ;; *) printf '%s\n' "Certificate mismatches key" || exit $? regen=1 esac else printf '%s\n' "Certificate expires soon" || exit $? regen=1 fi ;; *) regen=1 esac readonly regen case ${regen?} in 1) printf '%s\n' "Regenerating certificate and key" || exit $? case ${cert_found?} in 0) mkdir -p -- "${cert?}" || exit $? rmdir -- "${cert?}" || exit $? esac case ${key_found?} in 0) mkdir -p -- "${key?}" || exit $? rmdir -- "${key?}" || exit $? esac openssl req \ -days 36500 \ -keyout "${key?}" \ -newkey rsa:2048 \ -nodes \ -out "${cert?}" \ -subj '/C=XX/ST=Test/L=Test/O=Test/CN=Test' \ -x509 \ || exit $?; esac python3 - "${cert?}" "${key?}" "$@" <<'EOF' from http.server import HTTPServer, SimpleHTTPRequestHandler import os import ssl import sys class MyHandler(SimpleHTTPRequestHandler): def end_headers(self): self.send_header("Access-Control-Allow-Origin", "*") self.send_header("Cross-Origin-Embedder-Policy", "require-corp") self.send_header("Cross-Origin-Opener-Policy", "same-origin") super().end_headers() cert = sys.argv[1] key = sys.argv[2] if len(sys.argv) > 3: port = int(sys.argv[3]) else: port = 8443 host = "0.0.0.0" httpd = HTTPServer((host, port), MyHandler) try: httpd.socket = ssl.wrap_socket(httpd.socket, certfile=cert, keyfile=key, server_side=True) except: ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) ctx.load_cert_chain(certfile=cert, keyfile=key) httpd.socket = ctx.wrap_socket(httpd.socket, server_side=True) print(f"Running HTTPS server on {host}:{port}") httpd.serve_forever() EOF