diff --git a/Borealis.ps1 b/Borealis.ps1 index f1bb5f3..068955e 100644 --- a/Borealis.ps1 +++ b/Borealis.ps1 @@ -958,6 +958,7 @@ switch ($choice) { New-Item -Path $dataDestination -ItemType Directory -Force | Out-Null Copy-Item "$dataSource\Server\Python_API_Endpoints" $dataDestination -Recurse Copy-Item "$dataSource\Server\Sounds" $dataDestination -Recurse + Copy-Item "$dataSource\Server\Modules" $dataDestination -Recurse Copy-Item "$dataSource\Server\server.py" $dataDestination Copy-Item "$dataSource\Server\job_scheduler.py" $dataDestination } diff --git a/Data/Server/Modules/crypto/certificates.py b/Data/Server/Modules/crypto/certificates.py index adbae73..b50c40f 100644 --- a/Data/Server/Modules/crypto/certificates.py +++ b/Data/Server/Modules/crypto/certificates.py @@ -42,7 +42,11 @@ def ensure_certificate(common_name: str = "Borealis Server") -> Tuple[Path, Path try: with _CERT_FILE.open("rb") as fh: cert = x509.load_pem_x509_certificate(fh.read()) - if cert.not_valid_after.replace(tzinfo=timezone.utc) <= datetime.now(tz=timezone.utc): + try: + expiry = cert.not_valid_after_utc # type: ignore[attr-defined] + except AttributeError: + expiry = cert.not_valid_after.replace(tzinfo=timezone.utc) + if expiry <= datetime.now(tz=timezone.utc): regenerate = True except Exception: regenerate = True @@ -130,4 +134,3 @@ def build_ssl_context() -> ssl.SSLContext: def certificate_paths() -> Tuple[str, str, str]: cert_path, key_path, bundle_path = ensure_certificate() return str(cert_path), str(key_path), str(bundle_path) - diff --git a/Data/Server/WebUI/vite.config.mts b/Data/Server/WebUI/vite.config.mts index f3d5aaa..c43aa0a 100644 --- a/Data/Server/WebUI/vite.config.mts +++ b/Data/Server/WebUI/vite.config.mts @@ -4,13 +4,32 @@ import react from '@vitejs/plugin-react'; import path from 'path'; import fs from 'fs'; -const defaultCert = path.resolve(__dirname, '../certs/borealis-server-cert.pem'); -const defaultKey = path.resolve(__dirname, '../certs/borealis-server-key.pem'); +const certCandidates = [ + process.env.BOREALIS_TLS_CERT, + path.resolve(__dirname, '../certs/borealis-server-cert.pem'), + path.resolve(__dirname, '../../Data/Server/certs/borealis-server-cert.pem'), +] as const; -const certPath = process.env.BOREALIS_TLS_CERT ?? defaultCert; -const keyPath = process.env.BOREALIS_TLS_KEY ?? defaultKey; +const keyCandidates = [ + process.env.BOREALIS_TLS_KEY, + path.resolve(__dirname, '../certs/borealis-server-key.pem'), + path.resolve(__dirname, '../../Data/Server/certs/borealis-server-key.pem'), +] as const; -const httpsOptions = fs.existsSync(certPath) && fs.existsSync(keyPath) +const pickFirst = (candidates: readonly (string | undefined)[]) => { + for (const candidate of candidates) { + if (!candidate) continue; + if (fs.existsSync(candidate)) { + return candidate; + } + } + return undefined; +}; + +const certPath = pickFirst(certCandidates); +const keyPath = pickFirst(keyCandidates); + +const httpsOptions = certPath && keyPath ? { cert: fs.readFileSync(certPath), key: fs.readFileSync(keyPath), diff --git a/Data/Server/server.py b/Data/Server/server.py index d943ef3..f657bef 100644 --- a/Data/Server/server.py +++ b/Data/Server/server.py @@ -18,6 +18,22 @@ Section Guide: * WebSocket Event Handling and Entrypoint """ +import os +import sys + +# Ensure the modular server package is importable when the runtime is launched +# from a packaged directory (e.g., Server/Borealis). We look for the canonical +# Data/Server location as well as a sibling Modules folder. +_SERVER_DIR = os.path.abspath(os.path.dirname(__file__)) +_SEARCH_ROOTS = [ + _SERVER_DIR, + os.path.abspath(os.path.join(_SERVER_DIR, "..", "..", "Data", "Server")), +] +for root in _SEARCH_ROOTS: + modules_dir = os.path.join(root, "Modules") + if os.path.isdir(modules_dir) and root not in sys.path: + sys.path.insert(0, root) + import eventlet # Monkey-patch stdlib for cooperative sockets (keep real threads for tpool usage) eventlet.monkey_patch(thread=False) @@ -34,7 +50,6 @@ from werkzeug.middleware.proxy_fix import ProxyFix from itsdangerous import URLSafeTimedSerializer, BadSignature, SignatureExpired import time -import os # To Read Production ReactJS Server Folder import json # For reading workflow JSON files import shutil # For moving workflow files and folders from typing import List, Dict, Tuple, Optional, Any, Set, Sequence @@ -8125,5 +8140,11 @@ def relay_ansible_run(data): if __name__ == "__main__": # Use SocketIO runner so WebSocket transport works with eventlet. - ssl_context = certificates.build_ssl_context() - socketio.run(app, host="0.0.0.0", port=5000, ssl_context=ssl_context) + # Eventlet's WSGI server expects raw cert/key paths rather than an ssl.SSLContext. + socketio.run( + app, + host="0.0.0.0", + port=5000, + certfile=TLS_CERT_PATH, + keyfile=TLS_KEY_PATH, + )