diff --git a/FreeTAKServer-UI/app/__init__.py b/FreeTAKServer-UI/app/__init__.py index 75dbc88..feb005f 100644 --- a/FreeTAKServer-UI/app/__init__.py +++ b/FreeTAKServer-UI/app/__init__.py @@ -90,7 +90,7 @@ def create_app(config, selenium=False): # UI configuration # UI version DO NOT modify it - app.config['UIVERSION'] = '2.2' + app.config['UIVERSION'] = '2.2.1' # number of milliseconds to query FTS for connected Users, health, a System status app.config['USERINTERVAL'] = '180000'; diff --git a/FreeTAKServer-UI/cert_gen.py b/FreeTAKServer-UI/cert_gen.py new file mode 100644 index 0000000..1f8066f --- /dev/null +++ b/FreeTAKServer-UI/cert_gen.py @@ -0,0 +1,80 @@ +""" +Module for generating RSA key pairs and self-signed certificates. +""" + +import datetime +import pathlib + +from cryptography import x509 +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import rsa + +CERT_NAME = "cert.pem" +KEY_NAME = "key.pem" +BASE_PATH = pathlib.Path("/opt/fts/fts_ui") + +def generate_rsa_key_pair() -> tuple[rsa.RSAPrivateKey, rsa.RSAPublicKey]: + """ + Generate a RSA key pair and return the private and public keys. + """ + private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048 + ) + return private_key, private_key.public_key() + + +def generate_self_signed_cert(common_name: str, public_key: rsa.RSAPublicKey, private_key: rsa.RSAPrivateKey): + """ + Generate a self-signed certificate with the given common name and public key. + """ + subject = issuer = x509.Name([ + x509.NameAttribute(x509.NameOID.COMMON_NAME, common_name) + ]) + + cert = x509.CertificateBuilder().subject_name( + subject + ).issuer_name( + issuer + ).public_key( + public_key + ).serial_number( + x509.random_serial_number() + ).not_valid_before( + datetime.datetime.utcnow() + ).not_valid_after( + datetime.datetime.utcnow() + datetime.timedelta(days=10 * 365) + ).add_extension( + x509.SubjectAlternativeName([x509.DNSName("localhost"), x509.DNSName("127.0.0.1")]), + critical=False, + ).sign(private_key, hashes.SHA256()) + return cert + + +def generate_certificates() -> tuple[pathlib.Path, pathlib.Path]: + """ + Generate a self-signed certificate and private key, and return their paths. + """ + cert_path = BASE_PATH / CERT_NAME + key_path = BASE_PATH / KEY_NAME + if not BASE_PATH.exists(): + BASE_PATH.mkdir(parents=True, exist_ok=True) + + if cert_path.exists() and key_path.exists(): + return cert_path, key_path + + private_key, public_key = generate_rsa_key_pair() + + cert = generate_self_signed_cert("localhost", public_key, private_key) + + with open(cert_path, "wb") as cf: + cf.write(cert.public_bytes(serialization.Encoding.PEM)) + + with open(key_path, "wb") as kf: + kf.write(private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + )) + + return cert_path, key_path diff --git a/FreeTAKServer-UI/run.py b/FreeTAKServer-UI/run.py index 5e10360..c3e7894 100644 --- a/FreeTAKServer-UI/run.py +++ b/FreeTAKServer-UI/run.py @@ -34,6 +34,7 @@ from os import environ from sys import exit from decouple import config +from cert_gen import generate_certificates from config import config_dict from app import create_app, db @@ -136,6 +137,7 @@ if __name__ == "__main__": import eventlet from eventlet import wsgi, wrap_ssl - wsgi.server(sock = eventlet.listen((app_config.APPIP, app_config.APPPort)), site=app) + cert, key = generate_certificates() + wsgi.server(sock = wrap_ssl(eventlet.listen((app_config.APPIP, app_config.APPPort)), serverside=True, keyfile=key, certfile=cert), site=app) #app.run(debug=True) # app.run() diff --git a/pyproject.toml b/pyproject.toml index cf72111..e931172 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "freetakserver-ui" -version = "2.2" +version = "2.2.1" description = "an optional UI for FreeTAKServer" authors = ["FreeTAKTeam "] readme= "README.md"