Implement ImunifyAV asset management and routing

- Added a static method to ensure ImunifyAV assets are created and permissions set correctly in CageFS.py.
- Updated the URL routing in urls.py to include paths for ImunifyAV, supporting both legacy and new routes.
- Modified the ImunifyAV HTML template to use Django's URL template tag for better maintainability.
- Enhanced the cyberpanel_fixes.sh script to ensure ImunifyAV UI assets are installed during fixes.
- Improved database user resolution and password handling in mysqlUtilities.py for better security and reliability.

This update enhances the integration and management of ImunifyAV within the CyberPanel environment.
This commit is contained in:
Master3395
2025-11-15 23:25:13 +01:00
parent 34f10cebe3
commit 0aca2a5aaf
8 changed files with 352 additions and 13 deletions

View File

@@ -0,0 +1,103 @@
import sys
import types
import unittest
from unittest import mock
# Provide minimal stubs when running tests outside the target servers.
if 'django' not in sys.modules:
django_stub = types.ModuleType("django")
django_stub.setup = lambda: None
sys.modules['django'] = django_stub
if 'MySQLdb' not in sys.modules:
mysql_stub = types.ModuleType("MySQLdb")
mysql_stub.connect = lambda *args, **kwargs: None
cursors_stub = types.SimpleNamespace(SSCursor=object)
mysql_stub.cursors = cursors_stub
sys.modules['MySQLdb'] = mysql_stub
sys.modules['MySQLdb.cursors'] = types.ModuleType("MySQLdb.cursors")
sys.modules['MySQLdb.cursors'].SSCursor = object
from plogical import mysqlUtilities
class DummyConnection:
def __init__(self, literal_side_effect=None):
self.literal_calls = []
self.literal_side_effect = literal_side_effect
self.closed = False
def literal(self, value):
if self.literal_side_effect:
raise self.literal_side_effect
self.literal_calls.append(value)
return f"'{value}'"
def close(self):
self.closed = True
class DummyCursor:
def __init__(self):
self.executed = []
self.fetchone_value = None
def execute(self, query, params=None):
self.executed.append((query, params))
def fetchone(self):
return self.fetchone_value
class MysqlUtilitiesChangePasswordTests(unittest.TestCase):
def test_numeric_password_is_coerced_and_sanitized(self):
connection = DummyConnection()
cursor = DummyCursor()
with mock.patch.object(mysqlUtilities.mysqlUtilities, 'setupConnection', return_value=(connection, cursor)), \
mock.patch.object(mysqlUtilities.mysqlUtilities, 'resolve_mysql_username', return_value='demo_user'), \
mock.patch('plogical.mysqlUtilities.os.path.exists', return_value=False):
result = mysqlUtilities.mysqlUtilities.changePassword('demo_user', 987654321)
self.assertEqual(result, 1)
self.assertIn('987654321', connection.literal_calls)
self.assertEqual(len(cursor.executed), 2) # USE mysql + password update
self.assertIn("PASSWORD('987654321')", cursor.executed[-1][0])
def test_logs_error_when_literal_fails(self):
connection = DummyConnection(literal_side_effect=ValueError("boom"))
cursor = DummyCursor()
with mock.patch.object(mysqlUtilities.mysqlUtilities, 'setupConnection', return_value=(connection, cursor)), \
mock.patch.object(mysqlUtilities.mysqlUtilities, 'resolve_mysql_username', return_value='demo_user'), \
mock.patch('plogical.mysqlUtilities.os.path.exists', return_value=False), \
mock.patch('plogical.mysqlUtilities.logging.CyberCPLogFileWriter.writeToFile') as log_mock:
result = mysqlUtilities.mysqlUtilities.changePassword('demo_user', 'secret')
self.assertEqual(result, 0)
log_calls = [call.args[0] for call in log_mock.call_args_list]
self.assertTrue(any('[mysqlUtilities.changePassword.literal]' in msg for msg in log_calls))
class MysqlUtilitiesResolveUserTests(unittest.TestCase):
def test_resolves_username_when_orm_missing(self):
class _StubManager:
def get(self, *args, **kwargs):
raise Exception("not found")
dbusers_stub = types.SimpleNamespace(objects=_StubManager())
databases_stub = types.SimpleNamespace(objects=_StubManager())
cursor = DummyCursor()
cursor.fetchone_value = None
with mock.patch('plogical.mysqlUtilities.DBUsers', dbusers_stub, create=True), \
mock.patch('plogical.mysqlUtilities.Databases', databases_stub, create=True):
resolved = mysqlUtilities.mysqlUtilities.resolve_mysql_username('mystery_user', cursor)
self.assertEqual(resolved, 'mystery_user')
if __name__ == "__main__":
unittest.main()