diff --git a/fastapi_ssh_server.py b/fastapi_ssh_server.py index 02167f4a5..dfee94a61 100644 --- a/fastapi_ssh_server.py +++ b/fastapi_ssh_server.py @@ -11,7 +11,8 @@ from jose import jwt, JWTError import logging app = FastAPI() -JWT_SECRET = "YOUR_SECRET_KEY" +# JWT_SECRET = "YOUR_SECRET_KEY" +JWT_SECRET = "REPLACE_ME_WITH_INSTALLER" JWT_ALGORITHM = "HS256" # Allow CORS for local dev/testing diff --git a/install/install.py b/install/install.py index 1fbdd33a0..ab3776a00 100755 --- a/install/install.py +++ b/install/install.py @@ -13,6 +13,7 @@ import socket from os.path import * from stat import * import stat +import secrets VERSION = '2.4' BUILD = 0 @@ -2639,6 +2640,20 @@ vmail command = f'chmod +x {filePath}' preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) +def configure_jwt_secret(): + import secrets + secret = secrets.token_urlsafe(32) + fastapi_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'fastapi_ssh_server.py') + with open(fastapi_file, 'r') as f: + lines = f.readlines() + with open(fastapi_file, 'w') as f: + for line in lines: + if line.strip().startswith('JWT_SECRET'): + f.write(f'JWT_SECRET = "{secret}"\n') + else: + f.write(line) + print(f"Configured JWT_SECRET in fastapi_ssh_server.py") + def main(): parser = argparse.ArgumentParser(description='CyberPanel Installer') parser.add_argument('publicip', help='Please enter public IP for your VPS or dedicated server.') @@ -2855,6 +2870,9 @@ echo $oConfig->Save() ? 'Done' : 'Error'; pass checks.fixCyberPanelPermissions() + checks.configure_jwt_secret() + + # logging.InstallLog.writeToFile("CyberPanel installation successfully completed!,80") diff --git a/plogical/upgrade.py b/plogical/upgrade.py index 424096663..dc5c8a3e5 100755 --- a/plogical/upgrade.py +++ b/plogical/upgrade.py @@ -3704,6 +3704,9 @@ pm.max_spare_servers = 3 Upgrade.installDNS_CyberPanelACMEFile() + command = 'systemctl restart fastapi_ssh_server' + Upgrade.executioner(command, command, 0) + Upgrade.stdOut("Upgrade Completed.") ### remove log file path incase its there diff --git a/websiteFunctions/views.py b/websiteFunctions/views.py index f586e5ec6..97da9a42a 100755 --- a/websiteFunctions/views.py +++ b/websiteFunctions/views.py @@ -23,6 +23,8 @@ import jwt from datetime import datetime, timedelta import OpenSSL from plogical.processUtilities import ProcessUtilities +import os +import re def loadWebsitesHome(request): val = request.session['userID'] @@ -2016,12 +2018,25 @@ def get_terminal_jwt(request): return JsonResponse({'status': 0, 'error_message': 'SSH user not configured for this website.'}) from datetime import datetime, timedelta import jwt as pyjwt + # Read JWT_SECRET from fastapi_ssh_server.py + jwt_secret = None + try: + with open(os.path.join(os.path.dirname(os.path.dirname(__file__)), '../fastapi_ssh_server.py')) as f: + for line in f: + m = re.match(r'\s*JWT_SECRET\s*=\s*[\'"](.+)[\'"]', line) + if m and m.group(1) != 'REPLACE_ME_WITH_INSTALLER': + jwt_secret = m.group(1) + break + except Exception as e: + logger.error(f"Could not read JWT_SECRET: {e}") + if not jwt_secret: + jwt_secret = 'YOUR_SECRET_KEY' # fallback, should not be used in production payload = { 'user_id': user_id, 'ssh_user': ssh_user, 'exp': datetime.utcnow() + timedelta(minutes=10) } - token = pyjwt.encode(payload, 'YOUR_SECRET_KEY', algorithm='HS256') + token = pyjwt.encode(payload, jwt_secret, algorithm='HS256') logger.error(f"JWT generated: {token}") return JsonResponse({'status': 1, 'token': token, 'ssh_user': ssh_user}) except Exception as e: diff --git a/websiteFunctions/website.py b/websiteFunctions/website.py index 2e0d6b955..2748c9856 100755 --- a/websiteFunctions/website.py +++ b/websiteFunctions/website.py @@ -4981,6 +4981,26 @@ StrictHostKeyChecking no website = Websites.objects.get(domain=self.domain) externalApp = website.externalApp + #### update jwt secret if needed + + import secrets + import re + import os + from plogical.processUtilities import ProcessUtilities + + fastapi_file = os.path.join(os.path.dirname(os.path.dirname(__file__)), '../fastapi_ssh_server.py') + try: + with open(fastapi_file, 'r') as f: + content = f.read() + m = re.search(r'JWT_SECRET\s*=\s*[\'"](.+)[\'"]', content) + if m and m.group(1) in ['REPLACE_ME_WITH_INSTALLER', 'YOUR_SECRET_KEY']: + new_secret = secrets.token_urlsafe(32) + # Use sed to replace the line in-place (macOS compatible) + sed_cmd = f"sed -i '' 's|JWT_SECRET = \"{m.group(1)}\"|JWT_SECRET = \"{new_secret}\"|' '{fastapi_file}'" + ProcessUtilities.outputExecutioner(sed_cmd) + except Exception as e: + pass + ##### from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter