From d9329e2a218cbbd6bda0c1a296bbd09736635974 Mon Sep 17 00:00:00 2001 From: master3395 Date: Tue, 3 Feb 2026 00:00:59 +0100 Subject: [PATCH] Remove bundled plugins from v2.5.5-dev - plugins live in cyberpanel-plugins only Removed: emailMarketing, examplePlugin, paypalPremiumPlugin, premiumPlugin, testPlugin All plugins are now installed via Plugin Store from https://github.com/master3395/cyberpanel-plugins --- emailMarketing/.DS_Store | Bin 6148 -> 0 bytes emailMarketing/__init__.py | 1 - emailMarketing/admin.py | 6 - emailMarketing/apps.py | 10 - emailMarketing/emACL.py | 66 - emailMarketing/emailMarketing.py | 427 ----- emailMarketing/emailMarketingManager.py | 899 --------- emailMarketing/meta.xml | 7 - emailMarketing/migrations/__init__.py | 0 emailMarketing/models.py | 56 - emailMarketing/signals.py | 0 .../static/emailMarketing/checklist.png | Bin 1755 -> 0 bytes .../static/emailMarketing/compose.png | Bin 1842 -> 0 bytes .../static/emailMarketing/emailMarketing.js | 1468 --------------- .../static/emailMarketing/mailing.png | Bin 1950 -> 0 bytes .../static/emailMarketing/paper-plane.png | Bin 2226 -> 0 bytes .../static/emailMarketing/post-office.png | Bin 1548 -> 0 bytes .../emailMarketing/composeMessages.html | 90 - .../emailMarketing/configureVerify.html | 99 - .../emailMarketing/createEmailList.html | 75 - .../emailMarketing/emailMarketing.html | 72 - .../templates/emailMarketing/manageLists.html | 315 ---- .../emailMarketing/manageSMTPHosts.html | 126 -- .../templates/emailMarketing/sendEmails.html | 204 --- .../templates/emailMarketing/website.html | 1134 ------------ emailMarketing/tests.py | 6 - emailMarketing/urls.py | 31 - emailMarketing/views.py | 215 --- examplePlugin/__init__.py | 1 - examplePlugin/admin.py | 3 - examplePlugin/apps.py | 8 - examplePlugin/enable_migrations | 0 examplePlugin/meta.xml | 8 - examplePlugin/migrations/__init__.py | 0 examplePlugin/models.py | 9 - examplePlugin/post_install | 4 - examplePlugin/pre_install | 4 - examplePlugin/pre_remove | 4 - examplePlugin/signals.py | 17 - .../static/examplePlugin/examplePlugin.js | 3 - .../examplePlugin/examplePlugin.html | 52 - examplePlugin/tests.py | 3 - examplePlugin/urls.py | 7 - examplePlugin/views.py | 7 - install/install.py | 2 +- paypalPremiumPlugin/README.md | 58 - paypalPremiumPlugin/__init__.py | 4 - paypalPremiumPlugin/api_encryption.py | 80 - paypalPremiumPlugin/apps.py | 5 - paypalPremiumPlugin/meta.xml | 30 - .../migrations/0001_initial.py | 27 - paypalPremiumPlugin/migrations/__init__.py | 1 - paypalPremiumPlugin/models.py | 40 - .../templates/paypalPremiumPlugin/index.html | 96 - .../paypalPremiumPlugin/settings.html | 331 ---- .../subscription_required.html | 139 -- paypalPremiumPlugin/urls.py | 12 - paypalPremiumPlugin/views.py | 387 ---- premiumPlugin/.gitignore | 6 - premiumPlugin/README-REMOTE-VERIFICATION.md | 81 - premiumPlugin/README.md | 58 - premiumPlugin/SECURITY.md | 57 - premiumPlugin/__init__.py | 4 - premiumPlugin/api_encryption.py | 83 - premiumPlugin/apps.py | 5 - premiumPlugin/meta.xml | 30 - premiumPlugin/migrations/0001_initial.py | 27 - premiumPlugin/migrations/__init__.py | 1 - premiumPlugin/models.py | 42 - .../templates/premiumPlugin/index.html | 96 - .../templates/premiumPlugin/settings.html | 315 ---- .../premiumPlugin/subscription_required.html | 139 -- premiumPlugin/urls.py | 12 - premiumPlugin/views.py | 406 ----- premiumPlugin/views_remote.py | 236 --- testPlugin/OS_COMPATIBILITY.md | 464 ----- testPlugin/SECURITY.md | 247 --- testPlugin/__init__.py | 2 - testPlugin/admin.py | 20 - testPlugin/apps.py | 11 - testPlugin/install.sh | 580 ------ testPlugin/meta.xml | 26 - testPlugin/middleware.py | 208 --- testPlugin/models.py | 35 - testPlugin/os_config.py | 365 ---- testPlugin/security.py | 256 --- testPlugin/signals.py | 15 - .../static/testPlugin/css/testPlugin.css | 418 ----- testPlugin/static/testPlugin/js/testPlugin.js | 323 ---- testPlugin/templates/testPlugin/index.html | 71 - .../templates/testPlugin/plugin_docs.html | 1624 ----------------- .../templates/testPlugin/plugin_home.html | 571 ------ .../templates/testPlugin/plugin_logs.html | 291 --- .../templates/testPlugin/plugin_settings.html | 264 --- .../templates/testPlugin/security_info.html | 499 ----- testPlugin/templates/testPlugin/settings.html | 165 -- testPlugin/test_os_compatibility.py | 446 ----- testPlugin/urls.py | 8 - testPlugin/views.py | 54 - 99 files changed, 1 insertion(+), 15209 deletions(-) delete mode 100644 emailMarketing/.DS_Store delete mode 100644 emailMarketing/__init__.py delete mode 100644 emailMarketing/admin.py delete mode 100644 emailMarketing/apps.py delete mode 100644 emailMarketing/emACL.py delete mode 100644 emailMarketing/emailMarketing.py delete mode 100644 emailMarketing/emailMarketingManager.py delete mode 100644 emailMarketing/meta.xml delete mode 100644 emailMarketing/migrations/__init__.py delete mode 100644 emailMarketing/models.py delete mode 100644 emailMarketing/signals.py delete mode 100644 emailMarketing/static/emailMarketing/checklist.png delete mode 100644 emailMarketing/static/emailMarketing/compose.png delete mode 100644 emailMarketing/static/emailMarketing/emailMarketing.js delete mode 100644 emailMarketing/static/emailMarketing/mailing.png delete mode 100644 emailMarketing/static/emailMarketing/paper-plane.png delete mode 100644 emailMarketing/static/emailMarketing/post-office.png delete mode 100644 emailMarketing/templates/emailMarketing/composeMessages.html delete mode 100644 emailMarketing/templates/emailMarketing/configureVerify.html delete mode 100644 emailMarketing/templates/emailMarketing/createEmailList.html delete mode 100644 emailMarketing/templates/emailMarketing/emailMarketing.html delete mode 100644 emailMarketing/templates/emailMarketing/manageLists.html delete mode 100644 emailMarketing/templates/emailMarketing/manageSMTPHosts.html delete mode 100644 emailMarketing/templates/emailMarketing/sendEmails.html delete mode 100644 emailMarketing/templates/emailMarketing/website.html delete mode 100644 emailMarketing/tests.py delete mode 100644 emailMarketing/urls.py delete mode 100644 emailMarketing/views.py delete mode 100644 examplePlugin/__init__.py delete mode 100644 examplePlugin/admin.py delete mode 100644 examplePlugin/apps.py delete mode 100644 examplePlugin/enable_migrations delete mode 100644 examplePlugin/meta.xml delete mode 100644 examplePlugin/migrations/__init__.py delete mode 100644 examplePlugin/models.py delete mode 100644 examplePlugin/post_install delete mode 100644 examplePlugin/pre_install delete mode 100644 examplePlugin/pre_remove delete mode 100644 examplePlugin/signals.py delete mode 100644 examplePlugin/static/examplePlugin/examplePlugin.js delete mode 100644 examplePlugin/templates/examplePlugin/examplePlugin.html delete mode 100644 examplePlugin/tests.py delete mode 100644 examplePlugin/urls.py delete mode 100644 examplePlugin/views.py delete mode 100644 paypalPremiumPlugin/README.md delete mode 100644 paypalPremiumPlugin/__init__.py delete mode 100644 paypalPremiumPlugin/api_encryption.py delete mode 100644 paypalPremiumPlugin/apps.py delete mode 100644 paypalPremiumPlugin/meta.xml delete mode 100644 paypalPremiumPlugin/migrations/0001_initial.py delete mode 100644 paypalPremiumPlugin/migrations/__init__.py delete mode 100644 paypalPremiumPlugin/models.py delete mode 100644 paypalPremiumPlugin/templates/paypalPremiumPlugin/index.html delete mode 100644 paypalPremiumPlugin/templates/paypalPremiumPlugin/settings.html delete mode 100644 paypalPremiumPlugin/templates/paypalPremiumPlugin/subscription_required.html delete mode 100644 paypalPremiumPlugin/urls.py delete mode 100644 paypalPremiumPlugin/views.py delete mode 100644 premiumPlugin/.gitignore delete mode 100644 premiumPlugin/README-REMOTE-VERIFICATION.md delete mode 100644 premiumPlugin/README.md delete mode 100644 premiumPlugin/SECURITY.md delete mode 100644 premiumPlugin/__init__.py delete mode 100644 premiumPlugin/api_encryption.py delete mode 100644 premiumPlugin/apps.py delete mode 100644 premiumPlugin/meta.xml delete mode 100644 premiumPlugin/migrations/0001_initial.py delete mode 100644 premiumPlugin/migrations/__init__.py delete mode 100644 premiumPlugin/models.py delete mode 100644 premiumPlugin/templates/premiumPlugin/index.html delete mode 100644 premiumPlugin/templates/premiumPlugin/settings.html delete mode 100644 premiumPlugin/templates/premiumPlugin/subscription_required.html delete mode 100644 premiumPlugin/urls.py delete mode 100644 premiumPlugin/views.py delete mode 100644 premiumPlugin/views_remote.py delete mode 100644 testPlugin/OS_COMPATIBILITY.md delete mode 100644 testPlugin/SECURITY.md delete mode 100644 testPlugin/__init__.py delete mode 100644 testPlugin/admin.py delete mode 100644 testPlugin/apps.py delete mode 100644 testPlugin/install.sh delete mode 100644 testPlugin/meta.xml delete mode 100644 testPlugin/middleware.py delete mode 100644 testPlugin/models.py delete mode 100644 testPlugin/os_config.py delete mode 100644 testPlugin/security.py delete mode 100644 testPlugin/signals.py delete mode 100644 testPlugin/static/testPlugin/css/testPlugin.css delete mode 100644 testPlugin/static/testPlugin/js/testPlugin.js delete mode 100644 testPlugin/templates/testPlugin/index.html delete mode 100644 testPlugin/templates/testPlugin/plugin_docs.html delete mode 100644 testPlugin/templates/testPlugin/plugin_home.html delete mode 100644 testPlugin/templates/testPlugin/plugin_logs.html delete mode 100644 testPlugin/templates/testPlugin/plugin_settings.html delete mode 100644 testPlugin/templates/testPlugin/security_info.html delete mode 100644 testPlugin/templates/testPlugin/settings.html delete mode 100644 testPlugin/test_os_compatibility.py delete mode 100644 testPlugin/urls.py delete mode 100644 testPlugin/views.py diff --git a/emailMarketing/.DS_Store b/emailMarketing/.DS_Store deleted file mode 100644 index 74248247034fb6268d3f3a976e89c26fdb49f3a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKOHRWu5FNJ>P1{Y`b%V$WDshAK!vYCbJpl9*MHL~b`U7^^Bd)*|5QpI~tl-Vq zLXDetiBRRK?B_Ud#-0}^u8BzX*3%2377_Ui41^C@<$~!xwl(ygB=c^=}jFW5(2D7>-oo_L;_>(ZADLud^mG|A|zgzqo z_;dW0Wo&h3v3-gVyGwn#F6F;i{8QnNFq?#KFw%nV(X*1-#ibFxtO)Ic5jbXw5`(oU zi&u%Qcs}OOGZ=yWgmzNYv+`;28=_^5=p&hThVhm~pK9OoslzA3Q;3jtsjk%z%cB9_ z3|Vk4dwjfe%jX0>oCm8pDbC1yJ;dD%7ip5EtPJ)Csv`nF)j3AyXpxS0B}V|Dhi);n`OgCT1O`KcxklW9DeVf>uF4!Sly*mdV0fXyT%&d;Wey+8 zjI7KFMak%h9|)aPsL|C<0jEGwfvUc2@&13g|NLKca#v0Pr@&DupuE9w&_haQZ{10b v_u2sE4uy?*xkhn8Wwv8!@K)SL5yQQJ8^F+Dt`R*j_eVfvaFtWwPZjt9SEb~A diff --git a/emailMarketing/__init__.py b/emailMarketing/__init__.py deleted file mode 100644 index d33aad86a..000000000 --- a/emailMarketing/__init__.py +++ /dev/null @@ -1 +0,0 @@ -default_app_config = 'emailMarketing.apps.EmailmarketingConfig' \ No newline at end of file diff --git a/emailMarketing/admin.py b/emailMarketing/admin.py deleted file mode 100644 index 4c33e0ec3..000000000 --- a/emailMarketing/admin.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding: utf-8 -*- - - -from django.contrib import admin - -# Register your models here. diff --git a/emailMarketing/apps.py b/emailMarketing/apps.py deleted file mode 100644 index 6de896393..000000000 --- a/emailMarketing/apps.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- - - -from django.apps import AppConfig - - -class EmailmarketingConfig(AppConfig): - name = 'emailMarketing' - def ready(self): - from . import signals diff --git a/emailMarketing/emACL.py b/emailMarketing/emACL.py deleted file mode 100644 index e68571c8f..000000000 --- a/emailMarketing/emACL.py +++ /dev/null @@ -1,66 +0,0 @@ -from .models import EmailMarketing, EmailTemplate, SMTPHosts, EmailLists, EmailJobs -from websiteFunctions.models import Websites - -class emACL: - - @staticmethod - def checkIfEMEnabled(userName): - try: - user = EmailMarketing.objects.get(userName=userName) - return 0 - except: - return 1 - - @staticmethod - def getEmailsLists(domain): - website = Websites.objects.get(domain=domain) - emailLists = website.emaillists_set.all() - listNames = [] - - for items in emailLists: - listNames.append(items.listName) - - return listNames - - @staticmethod - def allTemplates(currentACL, admin): - if currentACL['admin'] == 1: - allTemplates = EmailTemplate.objects.all() - else: - allTemplates = admin.emailtemplate_set.all() - - templateNames = [] - for items in allTemplates: - templateNames.append(items.name) - return templateNames - - @staticmethod - def allSMTPHosts(currentACL, admin): - if currentACL['admin'] == 1: - allHosts = SMTPHosts.objects.all() - else: - allHosts = admin.smtphosts_set.all() - hostNames = [] - - for items in allHosts: - hostNames.append(items.host) - - return hostNames - - @staticmethod - def allEmailsLists(currentACL, admin): - listNames = [] - emailLists = EmailLists.objects.all() - - if currentACL['admin'] == 1: - for items in emailLists: - listNames.append(items.listName) - else: - for items in emailLists: - if items.owner.admin == admin: - listNames.append(items.listName) - - return listNames - - - diff --git a/emailMarketing/emailMarketing.py b/emailMarketing/emailMarketing.py deleted file mode 100644 index 3ac749ad6..000000000 --- a/emailMarketing/emailMarketing.py +++ /dev/null @@ -1,427 +0,0 @@ -#!/usr/local/CyberCP/bin/python - -import os -import time -import csv -import re -import plogical.CyberCPLogFileWriter as logging -from .models import EmailLists, EmailsInList, EmailTemplate, EmailJobs, SMTPHosts, ValidationLog -from plogical.backupSchedule import backupSchedule -from websiteFunctions.models import Websites -import threading as multi -import socket, smtplib -import DNS -from random import randint -from plogical.processUtilities import ProcessUtilities - -class emailMarketing(multi.Thread): - def __init__(self, function, extraArgs): - multi.Thread.__init__(self) - self.function = function - self.extraArgs = extraArgs - - def run(self): - try: - if self.function == 'createEmailList': - self.createEmailList() - elif self.function == 'verificationJob': - self.verificationJob() - elif self.function == 'startEmailJob': - self.startEmailJob() - except BaseException as msg: - logging.CyberCPLogFileWriter.writeToFile(str(msg) + ' [emailMarketing.run]') - - def createEmailList(self): - try: - website = Websites.objects.get(domain=self.extraArgs['domain']) - try: - newList = EmailLists(owner=website, listName=self.extraArgs['listName'], dateCreated=time.strftime("%I-%M-%S-%a-%b-%Y")) - newList.save() - except: - newList = EmailLists.objects.get(listName=self.extraArgs['listName']) - - counter = 0 - - if self.extraArgs['path'].endswith('.csv'): - with open(self.extraArgs['path'], 'r') as emailsList: - data = csv.reader(emailsList, delimiter=',') - for items in data: - try: - for value in items: - if re.match('^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', value) != None: - try: - getEmail = EmailsInList.objects.get(owner=newList, email=value) - except: - try: - newEmail = EmailsInList(owner=newList, email=value, - verificationStatus='NOT CHECKED', - dateCreated=time.strftime("%I-%M-%S-%a-%b-%Y")) - newEmail.save() - except: - pass - logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], str(counter) + ' emails read.') - counter = counter + 1 - except BaseException as msg: - logging.CyberCPLogFileWriter.writeToFile('%s. [createEmailList]' % (str(msg))) - continue - elif self.extraArgs['path'].endswith('.txt'): - with open(self.extraArgs['path'], 'r') as emailsList: - emails = emailsList.readline() - while emails: - email = emails.strip('\n') - if re.match('^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$', email) != None: - try: - getEmail = EmailsInList.objects.get(owner=newList, email=email) - except BaseException as msg: - newEmail = EmailsInList(owner=newList, email=email, verificationStatus='NOT CHECKED', - dateCreated=time.strftime("%I-%M-%S-%a-%b-%Y")) - newEmail.save() - logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],str(counter) + ' emails read.') - counter = counter + 1 - emails = emailsList.readline() - - logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], str(counter) + 'Successfully read all emails. [200]') - except BaseException as msg: - logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], str(msg) +'. [404]') - return 0 - - def findNextIP(self): - try: - if self.delayData['rotation'] == 'Disable': - return None - elif self.delayData['rotation'] == 'IPv4': - if self.delayData['ipv4'].find(',') == -1: - return self.delayData['ipv4'] - else: - ipv4s = self.delayData['ipv4'].split(',') - - if self.currentIP == '': - return ipv4s[0] - else: - returnCheck = 0 - - for items in ipv4s: - if returnCheck == 1: - return items - if items == self.currentIP: - returnCheck = 1 - - return ipv4s[0] - else: - if self.delayData['ipv6'].find(',') == -1: - return self.delayData['ipv6'] - else: - ipv6 = self.delayData['ipv6'].split(',') - - if self.currentIP == '': - return ipv6[0] - else: - returnCheck = 0 - - for items in ipv6: - if returnCheck == 1: - return items - if items == self.currentIP: - returnCheck = 1 - return ipv6[0] - except BaseException as msg: - logging.CyberCPLogFileWriter.writeToFile(str(msg)) - return None - - def verificationJob(self): - try: - - verificationList = EmailLists.objects.get(listName=self.extraArgs['listName']) - domain = verificationList.owner.domain - - if not os.path.exists('/home/cyberpanel/' + domain): - os.mkdir('/home/cyberpanel/' + domain) - - tempStatusPath = '/home/cyberpanel/' + domain + "/" + self.extraArgs['listName'] - logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, 'Starting verification job..') - - counter = 1 - counterGlobal = 0 - - allEmailsInList = verificationList.emailsinlist_set.all() - - configureVerifyPath = '/home/cyberpanel/configureVerify' - finalPath = '%s/%s' % (configureVerifyPath, domain) - - - import json - if os.path.exists(finalPath): - self.delayData = json.loads(open(finalPath, 'r').read()) - - self.currentIP = '' - - ValidationLog(owner=verificationList, status=backupSchedule.INFO, message='Starting email verification..').save() - - for items in allEmailsInList: - if items.verificationStatus != 'Verified': - try: - - email = items.email - self.currentEmail = email - domainName = email.split('@')[1] - records = DNS.dnslookup(domainName, 'MX', 15) - - counterGlobal = counterGlobal + 1 - - for mxRecord in records: - - # Get local server hostname - host = socket.gethostname() - - ## Only fetching smtp object - - if os.path.exists(finalPath): - try: - delay = self.delayData['delay'] - if delay == 'Enable': - if counterGlobal == int(self.delayData['delayAfter']): - ValidationLog(owner=verificationList, status=backupSchedule.INFO, - message='Sleeping for %s seconds...' % (self.delayData['delayTime'])).save() - - time.sleep(int(self.delayData['delayTime'])) - counterGlobal = 0 - self.currentIP = self.findNextIP() - - ValidationLog(owner=verificationList, status=backupSchedule.INFO, - message='IP being used for validation until next sleep: %s.' % (str(self.currentIP))).save() - - if self.currentIP == None: - server = smtplib.SMTP(timeout=10) - else: - server = smtplib.SMTP(self.currentIP, timeout=10) - else: - - if self.currentIP == '': - self.currentIP = self.findNextIP() - ValidationLog(owner=verificationList, status=backupSchedule.INFO, - message='IP being used for validation until next sleep: %s.' % ( - str(self.currentIP))).save() - - if self.currentIP == None: - server = smtplib.SMTP(timeout=10) - else: - server = smtplib.SMTP(self.currentIP, timeout=10) - else: - logging.CyberCPLogFileWriter.writeToFile( - 'Delay not configured..') - - ValidationLog(owner=verificationList, status=backupSchedule.INFO, - message='Delay not configured..').save() - - server = smtplib.SMTP(timeout=10) - except BaseException as msg: - - ValidationLog(owner=verificationList, status=backupSchedule.ERROR, - message='Delay not configured. Error message: %s' % (str(msg))).save() - - server = smtplib.SMTP(timeout=10) - else: - server = smtplib.SMTP(timeout=10) - - ### - - server.set_debuglevel(0) - - # SMTP Conversation - server.connect(mxRecord[1]) - server.helo(host) - server.mail('host' + "@" + host) - code, message = server.rcpt(str(email)) - server.quit() - - # Assume 250 as Success - if code == 250: - items.verificationStatus = 'Verified' - items.save() - break - else: - ValidationLog(owner=verificationList, status=backupSchedule.ERROR, - message='Failed to verify %s. Error message %s' % (email, message.decode())).save() - items.verificationStatus = 'Verification Failed' - items.save() - - logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, str(counter) + ' emails verified so far..') - counter = counter + 1 - except BaseException as msg: - items.verificationStatus = 'Verification Failed' - items.save() - counter = counter + 1 - ValidationLog(owner=verificationList, status=backupSchedule.ERROR, - message='Failed to verify %s. Error message %s' % ( - self.currentEmail , str(msg))).save() - - - verificationList.notVerified = verificationList.emailsinlist_set.filter(verificationStatus='Verification Failed').count() - verificationList.verified = verificationList.emailsinlist_set.filter(verificationStatus='Verified').count() - verificationList.save() - - ValidationLog(owner=verificationList, status=backupSchedule.ERROR, message=str(counter) + ' emails successfully verified. [200]').save() - - logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, str(counter) + ' emails successfully verified. [200]') - except BaseException as msg: - verificationList = EmailLists.objects.get(listName=self.extraArgs['listName']) - domain = verificationList.owner.domain - tempStatusPath = '/home/cyberpanel/' + domain + "/" + self.extraArgs['listName'] - logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, str(msg) +'. [404]') - logging.CyberCPLogFileWriter.writeToFile(str(msg)) - return 0 - - def setupSMTPConnection(self): - try: - if self.extraArgs['host'] == 'localhost': - self.smtpServer = smtplib.SMTP('127.0.0.1') - return 1 - else: - self.verifyHost = SMTPHosts.objects.get(host=self.extraArgs['host']) - self.smtpServer = smtplib.SMTP(str(self.verifyHost.host), int(self.verifyHost.port)) - - if int(self.verifyHost.port) == 587: - self.smtpServer.starttls() - - self.smtpServer.login(str(self.verifyHost.userName), str(self.verifyHost.password)) - return 1 - except smtplib.SMTPHeloError: - logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], - 'The server didnt reply properly to the HELO greeting.') - return 0 - except smtplib.SMTPAuthenticationError: - logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], - 'Username and password combination not accepted.') - return 0 - except smtplib.SMTPException: - logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], - 'No suitable authentication method was found.') - return 0 - - def startEmailJob(self): - try: - - if self.setupSMTPConnection() == 0: - logging.CyberCPLogFileWriter.writeToFile('SMTP Connection failed. [301]') - return 0 - - emailList = EmailLists.objects.get(listName=self.extraArgs['listName']) - allEmails = emailList.emailsinlist_set.all() - emailMessage = EmailTemplate.objects.get(name=self.extraArgs['selectedTemplate']) - - totalEmails = allEmails.count() - sent = 0 - failed = 0 - - ipFile = "/etc/cyberpanel/machineIP" - f = open(ipFile) - ipData = f.read() - ipAddress = ipData.split('\n', 1)[0] - - ## Compose Message - from email.mime.multipart import MIMEMultipart - from email.mime.text import MIMEText - import re - - tempPath = "/home/cyberpanel/" + str(randint(1000, 9999)) - - emailJob = EmailJobs(owner=emailMessage, date=time.strftime("%I-%M-%S-%a-%b-%Y"), - host=self.extraArgs['host'], totalEmails=totalEmails, - sent=sent, failed=failed - ) - emailJob.save() - - for items in allEmails: - try: - message = MIMEMultipart('alternative') - message['Subject'] = emailMessage.subject - message['From'] = emailMessage.fromEmail - message['reply-to'] = emailMessage.replyTo - - if (items.verificationStatus == 'Verified' or self.extraArgs[ - 'verificationCheck']) and not items.verificationStatus == 'REMOVED': - try: - port = ProcessUtilities.fetchCurrentPort() - removalLink = "https:\/\/" + ipAddress + ":%s\/emailMarketing\/remove\/" % (port) + self.extraArgs[ - 'listName'] + "\/" + items.email - messageText = emailMessage.emailMessage.encode('utf-8', 'replace') - message['To'] = items.email - - if re.search(b' - - Email Marketing - Utility - Email Marketing plugin for CyberPanel. - 1.0.1 - \ No newline at end of file diff --git a/emailMarketing/migrations/__init__.py b/emailMarketing/migrations/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/emailMarketing/models.py b/emailMarketing/models.py deleted file mode 100644 index b352f2549..000000000 --- a/emailMarketing/models.py +++ /dev/null @@ -1,56 +0,0 @@ -# -*- coding: utf-8 -*- - - -from django.db import models -from websiteFunctions.models import Websites -from loginSystem.models import Administrator - -# Create your models here. - -class EmailMarketing(models.Model): - userName = models.CharField(max_length=50, unique=True) - -class EmailLists(models.Model): - owner = models.ForeignKey(Websites, on_delete=models.PROTECT) - listName = models.CharField(max_length=50, unique=True) - dateCreated = models.CharField(max_length=200) - verified = models.IntegerField(default=0) - notVerified = models.IntegerField(default=0) - -class EmailsInList(models.Model): - owner = models.ForeignKey(EmailLists, on_delete=models.CASCADE) - email = models.CharField(max_length=50) - firstName = models.CharField(max_length=20, default='') - lastName = models.CharField(max_length=20, default='') - verificationStatus = models.CharField(max_length=100) - dateCreated = models.CharField(max_length=200) - -class SMTPHosts(models.Model): - owner = models.ForeignKey(Administrator, on_delete=models.CASCADE) - host = models.CharField(max_length=150, unique= True) - port = models.CharField(max_length=10) - userName = models.CharField(max_length=200) - password = models.CharField(max_length=200) - -class EmailTemplate(models.Model): - owner = models.ForeignKey(Administrator, on_delete=models.CASCADE) - name = models.CharField(unique=True, max_length=100) - subject = models.CharField(max_length=1000) - fromName = models.CharField(max_length=100) - fromEmail = models.CharField(max_length=150) - replyTo = models.CharField(max_length=150) - emailMessage = models.TextField(max_length=65532) - -class EmailJobs(models.Model): - owner = models.ForeignKey(EmailTemplate, on_delete=models.CASCADE) - date = models.CharField(max_length=200) - host = models.CharField(max_length=1000) - totalEmails = models.IntegerField() - sent = models.IntegerField() - failed = models.IntegerField() - -class ValidationLog(models.Model): - owner = models.ForeignKey(EmailLists, on_delete=models.CASCADE) - status = models.IntegerField() - message = models.TextField() - diff --git a/emailMarketing/signals.py b/emailMarketing/signals.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/emailMarketing/static/emailMarketing/checklist.png b/emailMarketing/static/emailMarketing/checklist.png deleted file mode 100644 index 5236aa0a87fb11b17312bd64530956d122d68d34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1755 zcmV<11|<23P)|<;2OGaYU(8jkPktPJAPRCPf`LNF zB0dz0xTP8jE$ya>1!>&zKf5!Vx#{lSeojuDlH0iZIBB|@5Kp4{Ee3qmPl3uxp307f!5e3r06bYvqVT3YxIr z^mPRXj2{35b4O_hz=%z1bY6lvxJtdm=4Ch+Q$Ws0jOC;IEOii8z|Ro^b4R+X7z%m9 zWC0xyCi3{ceaT*3uVg?&|Lo`FaJdL_>V5C@>|Md!5L_^hVR9Zr#XP;`zx?K(P8>h&G} z@!C89m`fQ1eJx<+nLXFt>+2_8?cP&lw{5PtIDD7|>c@6Z-(motbJprGyqX#qb|eog?>pbiS#Vz%yJ zOD4W^B4&d&JnbHARM`pX0X&g|J4CRAoCU0aT0mbglui-j!HFCK;_B1yhGzeJ`n8W?mz)RN?d}Jr$hSF69z+W>NF5`1VA+@7PN9MmdN(`q7^IvAT#G;Dcl_>02o$5Y4eURHYVYzH$(t5r~mS_W+ku! zE{md)07#4zR+PFRDNI0tyX`zfX;|0YEdQ3;5;zMX7Y2O&Sa{DV8b& zQsn8UZfb)yOn~x}NdQF1`<{iIyZRW4lM+)xz}{+bG(wL2^{{557g>l#=r9`j|b&_&kFw7d>L(S-JY(E7w6fBWL}14|b! zAN=q_BZd_$NGWlir^KtUHb1lRg41$S20?r?R3`BOV7Fe-a7e`%miOh-`L`=?pslSj zr{|~)LVrsv_{#Twa!J4MJo(oX72yB*QR42r;1mP1I z$0`B@OvL1_X13|aB7F&Pd0TzJa-TP1kuONTV!Ivxv)@j zD#j`UV8HLGfIw(K9B45sFvNEHpogNoPAD_tVN2KVU%b@>3z%ZoAOfg=H9Kw%$Oy4y zN9qK;{f&?Z#819`X@8HF&fEnC0Z1$yfXeK!?Fxf~(KoM*$Eg?-2?wAwF!CY^=UgmB zw*+=S|0=ZvAtIBVr$Flj<$;k0#IijMW{_QAj9(`VktKKlY{d(xVTuVHfZ~c#{ID8z zVKKyl6ZXC|^_I3mb%}&8QN>bMG-q)!}#x7yu{dX;VSswQ&Fd002ovPDHLkV1g`o6f*z- diff --git a/emailMarketing/static/emailMarketing/compose.png b/emailMarketing/static/emailMarketing/compose.png deleted file mode 100644 index 4e786da4d0d16c631885537abe0d440936ecd604..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1842 zcmV-22hI42P)3baJ5pn{ z72Lgfva1ILJ!IoQ3Svnx6v1k;R4^AcdlJ251EP4^)I*{EAsa|R)X*r#OAfmMi(c9+ zMS7DCQKBtsM$?pl$vnR|^JeFpw{Ld4voo_1=7Y(6d9yn+@Atm%_x*WGNFs?Ol1L(n zh@wPx=Swt8DAC{`#Ds&LDf}^M8@l~}Kb-f$ST79p!M##2#ts$6drfLw9X(jvdmvn* z$^!I%m<0AK+Ddj85ut-Np@<*Ck6nja9(jIih+^n77&UBKp$}dVCK(6_3DEFKu)p2NW)NT3>bw5e|0q?0BWvz)96^;B1f={T{xSxiy$-tPzC@B9$$}07$-0Q zm=&bD27(NL$CZ5D$DMOT;sDS+ckly%h!G)LcNm~+R)bFR1Bp=K$5#&3 z_yi~6gngV5U#$sGEW-6dgdjAD{ma`q_{?Mo05F}c>JTS5yuvdu!Ey_p$VZnan27mh zKv0V;^$-AH`U+p+Qi~P#<%#aN!*l!D!!x)X-smh6Tx+(%t#~4$JRzRKhyzeT05q&H ze5Qzb;^r z2gvH?`&JpPm~oZTEs~{;7y7G5zPY)WqEvGLaP|jO-U@S@ARhf|NhBx(0L5lJadBh0 z{O|4oDX_Y5l~VBLRqzg}7BA5)@kT#I2qCtx{U;ke>p&1F_oT5fw!a5#mTt zlJSIPNha;s9oj9W-ApjN=rAjZ1cnd^CS^RKaJP!r9Z)9N$CDu}4=wzY1|MHlZL;&r z1R)yG%=hC124CUf7Lj1qk0+ef@6;XI<^(4dX0p}L0;lN~0I(I)Ku_}tP6_~&1)iv& z>kT}iP_H$_0)kizh$->a(Sy~8zc30gS&f5IH&YZ5jEUX>Ls(%ZgD~+jZ;*&Qp^I+P zHFv-OqOK?mMAma;Zow>ML=p+4MUewQtkJ<+4R-Y4L0lRmJTLSJ@v`;^6CAD&j_7jhx8VOT%gPVfbUh< zcSk?aGhe-v)H6ptIar|!d(CZz;=@Ib|k5< zwkC52#q1o2wk$y`hD2dK!6)bb7=jnh;qYZ|mQtOsHg1BXQCA3Chn0GR3(SB8Fl(rN z`EEw)4hnTGA{G!Z0IJVJFOJ<)MP}Y0XOvi}NG|@c|4kAAH!z4<^j6cD-*9dIom&(f#?QNU19M8M=|u{l+A5|Y#b zh&wvqVn~$AYlrn`&;6c(>scNV>Mv_IVHEw_w~mGfg4u;+>2`i2wEX&gMziP;s)XbY zJwe<-=`b$;@7=-41Y_TpZsrbVjPBq~g}ZMFmOGd+yFfE$Nl>%^8x&rpMxQYP0Mo3jm1lyK;LQ-yLMMWS5Q*gw zQ8%d{0Qry4Wdnl{XdCJH+4Y=KpA35$#oY;#n6sZQ145Nep6R>Tg81ZZAoNZENF -1) { - $scope.verificationButton = false; - return; - } - $scope.verificationButton = true; - $scope.cyberPanelLoading = false; - $scope.verificationStatus = false; - $scope.currentStatusVerification = response.data.error_message; - - } - - } else { - - if (response.data.currentStatus.search('No such file') > -1) { - $scope.cyberPanelLoading = true; - $scope.deleteTemplateBTN = false; - $scope.sendEmailBTN = false; - $scope.sendEmailsView = true; - $scope.jobStatus = true; - $scope.goBackDisable = false; - $timeout.cancel(); - return; - } - - $scope.currentStatusVerification = response.data.currentStatus; - $timeout(listVerificationStatus, 1000); - $scope.verificationStatus = false; - } - - } - - function cantLoadInitialDatas(response) { - $scope.cyberPanelLoading = true; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page', - type: 'error' - }); - - - } - - - } - - // Delete Email from list - - $scope.deleteEmail = function (id) { - - $scope.cyberPanelLoading = false; - - url = "/emailMarketing/deleteEmail"; - - var data = { - id: id - }; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - - - function ListInitialDatas(response) { - $scope.cyberPanelLoading = true; - $scope.fetchEmails(globalPage); - - if (response.data.status === 1) { - $scope.fetchEmails(globalPage); - new PNotify({ - title: 'Success.', - text: 'Email Successfully deleted.', - type: 'success' - }); - - } else { - - new PNotify({ - title: 'Operation Failed!', - text: response.data.error_message, - type: 'error' - }); - - } - - } - - function cantLoadInitialDatas(response) { - $scope.cyberPanelLoading = true; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page', - type: 'error' - }); - - } - - }; - - - $scope.currentPageLogs = 1; - $scope.recordsToShowLogs = 10; - - $scope.fetchLogs = function () { - - $scope.cyberPanelLoading = false; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - var data = { - listName: $scope.listName, - page: $scope.currentPageLogs, - recordsToShow: $scope.recordsToShowLogs - }; - - url = "/emailMarketing/fetchVerifyLogs"; - - $http.post(url, data, config).then(ListInitialData, cantLoadInitialData); - - function ListInitialData(response) { - $scope.cyberPanelLoading = true; - if (response.data.status === 1) { - $scope.recordsLogs = JSON.parse(response.data.logs); - $scope.paginationLogs = response.data.pagination; - $scope.totalEmails = response.data.totalEmails; - $scope.verified = response.data.verified; - $scope.notVerified = response.data.notVerified; - } else { - new PNotify({ - title: 'Error!', - text: response.data.error_message, - type: 'error' - }); - } - } - function cantLoadInitialData(response) { - $scope.cyberPanelLoading = true; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page', - type: 'error' - }); - } - - - }; - - -}); - -app.controller('manageSMTPHostsCTRL', function ($scope, $http) { - - $scope.cyberPanelLoading = true; - $scope.fetchSMTPHosts = function () { - $scope.cyberPanelLoading = false; - - url = "/emailMarketing/fetchSMTPHosts"; - - var data = {}; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - - - function ListInitialDatas(response) { - $scope.cyberPanelLoading = true; - - if (response.data.status === 1) { - $scope.records = JSON.parse(response.data.data); - } else { - new PNotify({ - title: 'Operation Failed!', - text: response.data.error_message, - type: 'error' - }); - } - } - - function cantLoadInitialDatas(response) { - $scope.cyberPanelLoading = false; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page', - type: 'error' - }); - - } - - }; - $scope.fetchSMTPHosts(); - $scope.saveSMTPHost = function (status, userName) { - $scope.cyberPanelLoading = false; - - url = "/emailMarketing/saveSMTPHost"; - - var data = { - smtpHost: $scope.smtpHost, - smtpPort: $scope.smtpPort, - smtpUserName: $scope.smtpUserName, - smtpPassword: $scope.smtpPassword - }; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - - - function ListInitialDatas(response) { - $scope.cyberPanelLoading = true; - - if (response.data.status === 1) { - $scope.fetchSMTPHosts(); - new PNotify({ - title: 'Success!', - text: 'Successfully saved new SMTP host.', - type: 'success' - }); - } else { - new PNotify({ - title: 'Operation Failed!', - text: response.data.error_message, - type: 'error' - }); - } - } - - function cantLoadInitialDatas(response) { - $scope.cyberPanelLoading = false; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page', - type: 'error' - }); - - } - - }; - $scope.smtpHostOperations = function (operation, id) { - $scope.cyberPanelLoading = false; - - url = "/emailMarketing/smtpHostOperations"; - - var data = { - id: id, - operation: operation - }; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - - - function ListInitialDatas(response) { - $scope.cyberPanelLoading = true; - $scope.fetchSMTPHosts(); - - if (response.data.status === 1) { - new PNotify({ - title: 'Success!', - text: response.data.message, - type: 'success' - }); - } else { - new PNotify({ - title: 'Operation Failed!', - text: response.data.error_message, - type: 'error' - }); - } - } - - function cantLoadInitialDatas(response) { - $scope.cyberPanelLoading = false; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page', - type: 'error' - }); - - } - - }; -}); - -app.controller('composeMessageCTRL', function ($scope, $http) { - - $scope.cyberPanelLoading = true; - $scope.saveTemplate = function (status, userName) { - $scope.cyberPanelLoading = false; - - url = "/emailMarketing/saveEmailTemplate"; - - var data = { - name: $scope.name, - subject: $scope.subject, - fromName: $scope.fromName, - fromEmail: $scope.fromEmail, - replyTo: $scope.replyTo, - emailMessage: $scope.emailMessage - }; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - - - function ListInitialDatas(response) { - $scope.cyberPanelLoading = true; - - if (response.data.status === 1) { - new PNotify({ - title: 'Success!', - text: 'Template successfully saved.', - type: 'success' - }); - } else { - new PNotify({ - title: 'Operation Failed!', - text: response.data.error_message, - type: 'error' - }); - } - } - - function cantLoadInitialDatas(response) { - $scope.cyberPanelLoading = false; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page', - type: 'error' - }); - - } - - }; -}); - -app.controller('sendEmailsCTRL', function ($scope, $http, $timeout) { - - $scope.cyberPanelLoading = true; - $scope.availableFunctions = true; - $scope.sendEmailsView = true; - $scope.jobStatus = true; - - // Button - - $scope.deleteTemplateBTN = false; - $scope.sendEmailBTN = false; - - $scope.templateSelected = function () { - $scope.availableFunctions = false; - $scope.sendEmailsView = true; - $scope.previewLink = '/emailMarketing/preview/' + $scope.selectedTemplate; - $scope.jobStatus = true; - emailJobStatus(); - - }; - - $scope.sendEmails = function () { - $scope.sendEmailsView = false; - $scope.fetchJobs(); - }; - - $scope.fetchJobs = function () { - - $scope.cyberPanelLoading = false; - - url = "/emailMarketing/fetchJobs"; - - var data = { - 'selectedTemplate': $scope.selectedTemplate - }; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - - - function ListInitialDatas(response) { - $scope.cyberPanelLoading = true; - - if (response.data.status === 1) { - $scope.currentRecords = false; - $scope.records = JSON.parse(response.data.data); - } else { - new PNotify({ - title: 'Operation Failed!', - text: response.data.error_message, - type: 'error' - }); - } - } - - function cantLoadInitialDatas(response) { - $scope.cyberPanelLoading = false; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page', - type: 'error' - }); - - } - - }; - - $scope.startEmailJob = function () { - $scope.cyberPanelLoading = false; - $scope.deleteTemplateBTN = true; - $scope.sendEmailBTN = true; - $scope.sendEmailsView = true; - $scope.goBackDisable = true; - - url = "/emailMarketing/startEmailJob"; - - - var data = { - 'selectedTemplate': $scope.selectedTemplate, - 'listName': $scope.listName, - 'host': $scope.host, - 'verificationCheck': $scope.verificationCheck, - 'unsubscribeCheck': $scope.unsubscribeCheck - }; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - - - function ListInitialDatas(response) { - $scope.cyberPanelLoading = true; - - if (response.data.status === 1) { - emailJobStatus(); - } else { - $scope.cyberPanelLoading = true; - $scope.deleteTemplateBTN = false; - $scope.sendEmailBTN = false; - $scope.sendEmailsView = false; - $scope.jobStatus = true; - $scope.goBackDisable = false; - new PNotify({ - title: 'Operation Failed!', - text: response.data.error_message, - type: 'error' - }); - } - } - - function cantLoadInitialDatas(response) { - $scope.cyberPanelLoading = false; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page', - type: 'error' - }); - - } - - - }; - - function emailJobStatus() { - - $scope.cyberPanelLoading = false; - $scope.deleteTemplateBTN = true; - $scope.sendEmailBTN = true; - $scope.sendEmailsView = true; - $scope.jobStatus = false; - $scope.goBackDisable = true; - - url = "/websites/installWordpressStatus"; - - var data = { - domain: 'example.com', - statusFile: "/home/cyberpanel/" + $scope.selectedTemplate + "_pendingJob" - }; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - - $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - - - function ListInitialDatas(response) { - - - if (response.data.abort === 1) { - - if (response.data.installStatus === 1) { - $scope.cyberPanelLoading = true; - $scope.deleteTemplateBTN = false; - $scope.sendEmailBTN = false; - $scope.sendEmailsView = true; - $scope.jobStatus = false; - $scope.goBackDisable = false; - $scope.currentStatus = 'Emails successfully sent.'; - $scope.fetchJobs(); - $timeout.cancel(); - - } else { - - if (response.data.error_message.search('No such file') > -1) { - $scope.cyberPanelLoading = true; - $scope.deleteTemplateBTN = false; - $scope.sendEmailBTN = false; - $scope.sendEmailsView = true; - $scope.jobStatus = true; - $scope.goBackDisable = false; - return; - } - $scope.cyberPanelLoading = true; - $scope.deleteTemplateBTN = false; - $scope.sendEmailBTN = false; - $scope.sendEmailsView = true; - $scope.jobStatus = false; - $scope.goBackDisable = false; - $scope.currentStatus = response.data.error_message; - - } - - } else { - - if (response.data.currentStatus.search('No such file') > -1) { - $scope.cyberPanelLoading = true; - $scope.deleteTemplateBTN = false; - $scope.sendEmailBTN = false; - $scope.sendEmailsView = true; - $scope.jobStatus = true; - $scope.goBackDisable = false; - $timeout.cancel(); - return; - } - - $scope.currentStatus = response.data.currentStatus; - $timeout(emailJobStatus, 1000); - $scope.cyberPanelLoading = false; - $scope.deleteTemplateBTN = true; - $scope.sendEmailBTN = true; - $scope.sendEmailsView = true; - $scope.jobStatus = false; - $scope.goBackDisable = true; - } - - } - - function cantLoadInitialDatas(response) { - $scope.cyberPanelLoading = true; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page.', - type: 'error' - }); - - - } - - - } - - $scope.goBack = function () { - $scope.cyberPanelLoading = true; - $scope.deleteTemplateBTN = false; - $scope.sendEmailBTN = false; - $scope.sendEmailsView = false; - $scope.jobStatus = true; - - }; - - $scope.deleteTemplate = function () { - - $scope.cyberPanelLoading = false; - - url = "/emailMarketing/deleteTemplate"; - - var data = { - selectedTemplate: $scope.selectedTemplate - }; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - - - function ListInitialDatas(response) { - $scope.cyberPanelLoading = true; - - if (response.data.status === 1) { - new PNotify({ - title: 'Success.', - text: 'Template Successfully deleted.', - type: 'success' - }); - - } else { - - new PNotify({ - title: 'Operation Failed!', - text: response.data.error_message, - type: 'error' - }); - - } - - } - - function cantLoadInitialDatas(response) { - $scope.cyberPanelLoading = true; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page', - type: 'error' - }); - - } - - }; - $scope.deleteJob = function (id) { - - $scope.cyberPanelLoading = false; - - url = "/emailMarketing/deleteJob"; - - var data = { - id: id - }; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - - - function ListInitialDatas(response) { - $scope.cyberPanelLoading = true; - $scope.fetchJobs(); - - if (response.data.status === 1) { - new PNotify({ - title: 'Success.', - text: 'Template Successfully deleted.', - type: 'success' - }); - - } else { - - new PNotify({ - title: 'Operation Failed!', - text: response.data.error_message, - type: 'error' - }); - - } - - } - - function cantLoadInitialDatas(response) { - $scope.cyberPanelLoading = true; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page', - type: 'error' - }); - - } - - }; -}); - -app.controller('configureVerify', function ($scope, $http) { - - $scope.cyberPanelLoading = true; - $scope.ipv4Hidden = true; - $scope.ipv6Hidden = true; - $scope.delayHidden = true; - - $scope.delayInitial = function () { - if ($scope.delay === 'Disable') { - $scope.delayHidden = true; - } else { - $scope.delayHidden = false; - } - }; - $scope.rotateInitial = function () { - if ($scope.rotation === 'Disable') { - $scope.rotationHidden = true; - } else if ($scope.rotation === 'IPv4') { - $scope.ipv4Hidden = false; - $scope.ipv6Hidden = true; - } else { - $scope.ipv4Hidden = true; - $scope.ipv6Hidden = false; - } - }; - - $scope.saveChanges = function () { - - $scope.cyberPanelLoading = false; - - url = "/emailMarketing/saveConfigureVerify"; - - var data = { - domain: $("#domainName").text(), - rotation: $scope.rotation, - delay: $scope.delay, - delayAfter: $scope.delayAfter, - delayTime: $scope.delayTime, - ipv4: $scope.ipv4, - ipv6: $scope.ipv6 - }; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - - - function ListInitialDatas(response) { - $scope.cyberPanelLoading = true; - - if (response.data.status === 1) { - - new PNotify({ - title: 'Success!', - text: 'Successfully saved verification settings.', - type: 'success' - }); - } else { - new PNotify({ - title: 'Operation Failed!', - text: response.data.error_message, - type: 'error' - }); - } - } - - function cantLoadInitialDatas(response) { - $scope.cyberPanelLoading = false; - new PNotify({ - title: 'Operation Failed!', - text: 'Could not connect to server, please refresh this page', - type: 'error' - }); - - } - - }; -}); - - diff --git a/emailMarketing/static/emailMarketing/mailing.png b/emailMarketing/static/emailMarketing/mailing.png deleted file mode 100644 index da227aa3207373a3ed7acc26ade5ce0ecd3095d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1950 zcmV;P2VwY$P)rZhnjia)!hX%&5Fimfk#*{TIm zVn!cC=!08JN*k;lseLle_1v9%XV1Mmo6KfsX4|p{ZuZXHJG*nf`OfczkhZj?Ep2Iw zBw9neXQ)9aVS^AC2K%J&$ECsZ$}yVz*HO{|^EI%y6AnAzcm>Q;a89SxIr;E)_T>q} z4BZP#jCcx?0Ob~&69kB-^h%hla=m$qdH{5~-dv}o`0FFr=PoZ0W~d4GJe?2#q{C&O zv}ixRHW45?LhYi&L;#dQsdDvLC`zizOLGB=<^!<82Y_Gz(g45!2Y`WL-F4_M^5f1M za+eDTm;w9A7Cpb5A6ww#5{wJV+J?{nHbMDm4gg637#aYv`M`Pd{nIzb3WOeNmy1mx zrW>I?0|Wp>XAE(vbx-lnLhC`0XiZ}T!3UrO02Bon8l~3I$Mc02gP=IO7$oJ&3}7Yz z^P(mg;u7oL56%@@Xby_EkBJEa0FATlJF6?lq67d?ImZ~WZQt2K>&(H8*BmNO-17ky zRtP!%OgAusaz<1@vhI8TOr$_`G;9uW`2=JRps-aR7j{#|UCQ@a`Nr zw!0^n90#AptnXjv!?CSbsPjGF)liE@+h=5Qa@_KCUUM~8cgSB*KG$aVn;beuau z;RA#Tr~vqkxvI>8$+x+iM!^jBgL0XQ!ae}L((E3FU~cLWMyUosh%Y>1DLvcGD#*H3 z6t~0z8X^|U@^tFu{kpJmKNa?#9`*;4Z*cL`WyhMh#y;}WtyA^QA;CNWcZE|_ z1;7~qr3+O*AbbE;nkYViB5GIXUM8qXl;838AA^TqUT4=ZAwqKq1ws{oS`e@!Y$6Ky zsW4_mP#DAjBy0|HR~XALkEQK9KfN#rH=eE*I;cG6%8AFOqfAe$naj?PRgQ;WS!b)} zAbuxNCamB;-09Xbfyqx#thJMNj3jBFz~2n{iBPN4W*>kg^8^fluKe)k1Lv6;6jEMx z7w7|0XugyWz>W{XAWNHbpS{}asOF%#2{S?X0WTGWSfZ*i; zEf*?hjmbp^SAH*`%GM9hvBszoE)}Mz9HvrfteOUU@%u^swsO6+Iq~SAz8Fye_&t0o zj1>v)6yY$q^R<(`hhFb%eNzR$7*V4GV?absu$l_X3<+$iMClj8F+qMYBCUP>+|8wJ z`_7K)ex86CK9Mdj6L2xcnejegwuajC6PU8@z1t;lMtYPmC`IjL_zQTVhEGC^i5evoOXO z0BA{7G|l(S@@t}Jg6Ie6Zg5z-|GhIKa6Y}K16 zB*OtP_?U+CTVanKn>naV002xlzqgqvfV_S`On30FE+7DkFh*6X^JBJF1jX5Yi(kX$ zgOM`P)_MyP)tGvi(uDVB=;|NmHca%G;aaY{m3xh2TC?=+)!F|jaL`2C$Bth2R&g&i7X}$kpyR!OFrZNf zJ^+V8Db0=)gjNYplEy-A-xIc8xS~MdKp4EKk_kwF7(3YiFiZdd%Szp^2oM4~O*K_y kTiVi=wzMTe`Cotm0FRy#x^sZB+yDRo07*qoM6N<$g8R^R(EtDd diff --git a/emailMarketing/static/emailMarketing/paper-plane.png b/emailMarketing/static/emailMarketing/paper-plane.png deleted file mode 100644 index 79998aa8d4b1ba6629441766235a55a4add4c947..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2226 zcmV;j2u=5iP)jV922@snhoAV_?>GpGngTA~IuW?dBIgWA>j787OrprWXqMq^@t76~FKY>OIW z5GWti7|>lq%*V}fbO}r<0a@Vc9>-jzB{LgvL9b>M!=9+7+ zx#pT{t`#(;8aMsqW40F;KUM-OwDduis%HqED&5yFt{T=LpalPq5Ter8KCBo(^kJ#h zcIcY;3GLdAC-&a3{_nwApQQpdO9zn>6b);z z%7H*pvKRM?RuUD{KR-#IB?f2JJOEfjnmdB*E#q%TazeZkqkEMMp?UKuUn8X&=fQEp z`8)ua!r8uR3FD?Q%$7u{zc6Xb=`a8cdW!&Pu)a>#R2Xy8XN^=g?ew5j=yrM^@0Qd4 z@wg8h4>WPkiUIIoeG|G|sa85Tb>1h!J)CFvoi|WhhkXe9FykyjjynZ_D$(y4aFqaP zV)x~~K*#EY^UhOX>#zpr*LXQoFLeeW1pq#Jt#F>KDFj$N=XJLTe`mYDZCJ(bL-?46 z+-D8}Bmp3WYrtbT7sYBquuEc6?7rjBWZQ?kn87+2SA6880FVNJ1f18feECuUPKR*q z^B9@eHIIZAN`;b~|LWfWg+4R5A6F&;NC3cxa6VQT0FO4F=P6u$wkB+QY+7w0z}x;-(C$hAIsqUc0Z0xkpOR_0@jbrBn<#l>wOTE&%u>=TrE=J?yro5vRvO04AI@ zsKXqT0Q3XEh%*N?0I9%)D6)b27_WVo_Oox(eWLDX0hpzWx3C4y0PKF?vR;}O*sU;i zgo>yJBb*ST=&}ArjU(ZEgB*^)`EX9?)9#1ZtrIRdH;e}0=H9xA*I2NN2ls} zAjqOvG6ZD|0cd8wZ?GKUQPwuD;J~CnAJDsNi3OnbgX3lzNQa@&_7zj}mOat~I~B?i#quHS;@QKF={U1@ zA34uE0YEPUK*$1c%%_Yjhl%YgrWKq);OBlNBZ?Oz5`M&vlk=Pfvw6=%%}40BHjdh< z6$4;7#o}@`D3k_LI#~0AGDWep61kfPNvJLWK%q}%uLuCL26Au|0DzZpwYL>5w9v{p&ZJFrN+;0?_u}F%^zP zq;i<}^6}}3B2kbnjYjzoa-2cntThJ!maz#}y#xTkLI6Z=XR3jdG!UXVn^~tu`u%}& zAvjA1qC8Rq=t{yk#J)ZgXWNIhN&wul?r7Ma4VnT609&7!UVI*DiXs!`kteGQ;U=XM zPKU4(Ih`Oa9E@0;eK9;VY0K%@l+CC7r2v@w?ok!rk9e|a&PiDLN>O79p4 z&Z(y3X|q32b0$LeR9K&o=1Bn1Mgu^0>pMqiI4UN@T!$F8Yl63*Wwx1VGrg>qvG!|EJBJ__4ptlbP<>N1U z{(kRyqckx?8rcvSuQLc_dlom-SUe#OMVHw>yX~z*)C)u;0Q8<9UJu>#+8^;nujpE_ z`v+J4BI`ja_Qs8R-9a#0WP@+=WK%+u&IVz8a8&|e*Lk{X_*wk^7k?jG{K9XsC6NRE z!u^3rr8KYjUw*1KV}wH#3HE7Foxk?5M*lv8*B#lRDA#fAfkVs8^vD9C$uT{c2|oDj zeqAvPyoV)F2K9_6A`6ss<)S#YlchX{PB7je<^tF?dT>I!7_=h*jm!)`wUfihzbbrTx9PW+mzt0{Q?FK)VX06!UD5nF=T3PtR!2_j^m8 zKS1E_rf5)dL0Bok1ONg#bKTps^ty#09*hi04@Ow#fP~I4zVfP3Km0?hf29G72B$kR zCq@|n(rMk=*)!`_6J%|WQ$WlDdp54Rs_5=P1E_nXkz4Qb&Yx5OpvYK8?Yd%)-+6Q_ zK4aA*;f|g^O~se0fWC3n)fMgDBP;f)hyZ=8K4aA(klp>p!6A>O_>{x#8=kp3!Rp8^ z$^%)XLJLwLNHf5C1K^r#uDRx#Yp%IAn*Arh0CI>x*Sney$N&HU07*qoM6N<$f~>6$ Ag8%>k diff --git a/emailMarketing/static/emailMarketing/post-office.png b/emailMarketing/static/emailMarketing/post-office.png deleted file mode 100644 index 7419b2b29a3cb2be16afcda16e8238900471bf83..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1548 zcmV+n2J`ueP)KD?R1`j$nccOlU|6V> zwb0Z@@kh4clR{^p(8`KTQ505TGJ>EM-1;i0>mN{dTd_V)7TTh=&$%CjnVY+rnRF((X(0zLNzTn=bH4kX@0^T?j!`~<68fg_N7M8ieUo@S!A1eEOX#P^B3>7}1T^m) z*b(n>Lp}$u?JLJ-ouoi0#RR~@7#d#i8~_?1zb2%Q&p%G#VNw8~Nc>SCz=j_z4OC-3 zt&fiZQo~2iB?Uqu)?EZ@e((@;^?T>j1iZj^2>?(A@YSa*;lUQWzONwo3U1HG8KJpg zzIbxeRLcZ01qj$UHu|qV_i4EDJplaG2LzzE`XzCt#bB9FBR!vgAE_Y#hCfGiwIGC3 zU=^M#HiNlq+a~%PI5gFfe|8tgEjE&{`BR$*5dgynB{^Y?mkuJ`UE!}^+ooF4!nqcF zcSlcK#XYtNX`z@2LcWWCoKn(fiLRuS38?|->xRq2LzM{?_3iZU})@~jM5>{1xrC6;L%+pApjr%AR}R1 zSKJ4%ve^#+(mwxz(NxQX%H$GOf({04q}vBT&oB6ZgaDwvl_a&M6#LGuiy(mE?*#x; zz=hN`Kwt~>!0KpjvVt2AgsXR|2*5?<8o*cqJ9S|(i@n2QmKqS@GZ#MkHH*DN0Dz4E zY$(!g^zzb=z)+$$0(-2 zlpsn^o_8!fw2%R4fS_XRtPTMHB!j&J0h}&9 zY%OCA@aMYBhkJ*&-np)J?;rtS<8ec!1_%Jupw~95-8+a3K-#aazximO%tub&FzNpX zuN<2lx_3Bx#(QyV)XmSIf4u_T|7H*X7iMNI)XHa|JmB{B>u7m1BmzuTxWT#58Kw^3mM}8 zFrqCc&IB%k+%N@J=0Dx+VBU7VS=>8}1;&6mx>`St8LXbVFbY+m_QGdd<)9Dfdh=%W z#2?i`eZbE*&+U6^_lNwEj`Y%$AzveP?RyOX8P<@V<=iVEu|SZ@pfyS#aC`glkZ9rf zglUA%Mgs$axIi$GU6!;#d~V`>!ur^KfVBU|U}=S^u$ALRfjAx$fHet#OA*gYjtN)a z-m`S%^cKy1W7IxidgAwevZ5mpZ49WwR*q}NGWwpux%vs2DewkH=2O9)og~b5H4<@EiMR*BpN{nf7#yoH!^jYCLQk;rq)Q1xa zK!wfQ5>RWS0#V2i04rjJE4)v@ - - -
-
-

{% trans "Compose Email Message" %}

-

{% trans "On this page you can compose email message to be sent out later." %}

-
-
-
-

- {% trans "Compose Email Message" %} -

-
- - -
- - - -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- - -
-
- -
-
- -
- -
- -
-
- - - -
- - - - -
-
-
-
- - -{% endblock %} \ No newline at end of file diff --git a/emailMarketing/templates/emailMarketing/configureVerify.html b/emailMarketing/templates/emailMarketing/configureVerify.html deleted file mode 100644 index 3c33bc0d3..000000000 --- a/emailMarketing/templates/emailMarketing/configureVerify.html +++ /dev/null @@ -1,99 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% block title %}{% trans "Configure Email Verification - CyberPanel" %}{% endblock %} -{% block content %} - - {% load static %} - {% get_current_language as LANGUAGE_CODE %} - - - -
-
-

{% trans "Configure Email Verification" %}

-

{% trans "On this page you can configure parameters regarding how email verification is performed for " %}{{ domain }}

-
-
-
-

- {% trans "Compose Email Message" %} -

-
- - -
- - - -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- - - -
- -
- -
-
- - - -
- - -
-
-
-
- - -{% endblock %} \ No newline at end of file diff --git a/emailMarketing/templates/emailMarketing/createEmailList.html b/emailMarketing/templates/emailMarketing/createEmailList.html deleted file mode 100644 index 17e6f6d61..000000000 --- a/emailMarketing/templates/emailMarketing/createEmailList.html +++ /dev/null @@ -1,75 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% block title %}{% trans "Create Email List - CyberPanel" %}{% endblock %} -{% block content %} - -{% load static %} -{% get_current_language as LANGUAGE_CODE %} - - - -
-
-

{% trans "Create Email List" %} - {{ domain }}

-

{% trans "Create email list, to send out news letters and marketing emails." %}

-
-
-
-

- {% trans "Create Email List" %} -

-
- - -
-
- -
- -
-
- -
- -
- -
-
- -
- -
- - -
-
- -
- -
-
-

{$ currentStatus $}

-
-
-
- -
- -
- -
-
- -
- - - - -
-
-
- - -
-{% endblock %} - diff --git a/emailMarketing/templates/emailMarketing/emailMarketing.html b/emailMarketing/templates/emailMarketing/emailMarketing.html deleted file mode 100644 index e2ba1970b..000000000 --- a/emailMarketing/templates/emailMarketing/emailMarketing.html +++ /dev/null @@ -1,72 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% block title %}{% trans "Email Marketing - CyberPanel" %}{% endblock %} -{% block content %} - -{% load static %} -{% get_current_language as LANGUAGE_CODE %} - - - -
- -
-

{% trans "Email Marketing" %}

-

{% trans "Select users to Enable/Disable Email Marketing feature!" %}

-
- -
-
- -

- {% trans "Email Marketing" %} -

- - {% if installCheck == 0 %} - -
-
-

{% trans "Email Policy Server is not enabled " %} - -

-
-
- {% else %} -
- - - - - - - - - - - - - - - - - - -
{% trans 'ID' %}{% trans 'Username' %}{% trans 'Status' %}
- - - - -
- -
- - {% endif %} -
-
- - - -{% endblock %} diff --git a/emailMarketing/templates/emailMarketing/manageLists.html b/emailMarketing/templates/emailMarketing/manageLists.html deleted file mode 100644 index 541e0e301..000000000 --- a/emailMarketing/templates/emailMarketing/manageLists.html +++ /dev/null @@ -1,315 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% block title %}{% trans "Manage Email Lists - CyberPanel" %}{% endblock %} -{% block content %} - - {% load static %} - {% get_current_language as LANGUAGE_CODE %} - - - -
-
-

{% trans "Manage Email Lists" %} - {{ domain }}

-

{% trans "On this page you can manage your email lists (Delete, Verify, Add More Emails)." %}

-
-
-
-

- {% trans "Manage Email Lists" %} -

-
- - -
- - -
- -
- -
-
- -
-
-
- - - - -
-
- -
-
- -
-
- - - - -
-
- -
-
-
- - - - -
- -
- -
-
- -
- -
- - -
-
- -
- -
-
-

{$ currentStatus $}

-
-
-
- -
- -
- -
-
- - - - - -
- -
-
-

{$ currentStatusVerification $}

-
-
-
- - - - - - -
- -
- -
- -
- -
- -
- - - - - - - - - - - - - - - - - - - - - -
{% trans "ID" %}{% trans "email" %}{% trans "Verification Status" %}{% trans "Date Created" %}{% trans "Actions" %}
- -
- -
-
- - -
-
-
-
- - - -
- - -
-
-
- - -
- - -{% endblock %} \ No newline at end of file diff --git a/emailMarketing/templates/emailMarketing/manageSMTPHosts.html b/emailMarketing/templates/emailMarketing/manageSMTPHosts.html deleted file mode 100644 index 2b94ddf05..000000000 --- a/emailMarketing/templates/emailMarketing/manageSMTPHosts.html +++ /dev/null @@ -1,126 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% block title %}{% trans "Manage SMTP Hosts - CyberPanel" %}{% endblock %} -{% block content %} - -{% load static %} -{% get_current_language as LANGUAGE_CODE %} - - - -
-
-

{% trans "Manage SMTP Hosts" %}

-

{% trans "On this page you can manage STMP Host. (SMTP hosts are used to send emails)" %}

-
-
-
-

- {% trans "Manage SMTP Hosts" %} -

-
- - -
- - - -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - -
{% trans "ID" %}{% trans "Owner" %}{% trans "Host" %}{% trans "Port" %}{% trans "Username" %}{% trans "Actions" %}
- - -
- -
-
- - -
-
-
-
- - - -
- - - - -
-
-
- - -
- - -{% endblock %} \ No newline at end of file diff --git a/emailMarketing/templates/emailMarketing/sendEmails.html b/emailMarketing/templates/emailMarketing/sendEmails.html deleted file mode 100644 index dee7c06dc..000000000 --- a/emailMarketing/templates/emailMarketing/sendEmails.html +++ /dev/null @@ -1,204 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% block title %}{% trans "Send Emails - CyberPanel" %}{% endblock %} -{% block content %} - -{% load static %} -{% get_current_language as LANGUAGE_CODE %} - - - -
-
-

{% trans "Send Emails" %}

-

{% trans "On this page you can send emails to the lists you created using SMTP Hosts." %}

-
-
-
-

- {% trans "Send Emails" %} -

-
- - -
- - -
- -
- -
-
- -
- -
- - - - -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
-
- -
-
- -
-
- -
-
-
- -
- -
- - -
-
- - - -
- -
-
-

{$ currentStatus $}

-
-
-
- -
- -
- -
-
- - - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - -
{% trans "Job ID" %}{% trans "Date" %}{% trans "SMTP Host" %}{% trans "Total Emails" %}{% trans "Sent" %}{% trans "Failed" %}{% trans "Actions" %}
- -
- -
-
- - -
-
-
-
- - - -
- - - - -
-
-
- - -
- - -{% endblock %} \ No newline at end of file diff --git a/emailMarketing/templates/emailMarketing/website.html b/emailMarketing/templates/emailMarketing/website.html deleted file mode 100644 index 052fea0d3..000000000 --- a/emailMarketing/templates/emailMarketing/website.html +++ /dev/null @@ -1,1134 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% block title %}{{ domain }} - CyberPanel{% endblock %} -{% block content %} - - {% load static %} - {% get_current_language as LANGUAGE_CODE %} - - -
- -
-

{{ domain }} - {% trans "Preview" %}

-

{% trans "All functions related to a particular site." %}

-
- - {% if not error %} - - -
- -
- -

- {% trans "Resource Usage" %} -

- - -
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{% trans "Resource" %}{% trans "Usage" %}{% trans "Allowed" %}
{% trans "FTP" %}{{ ftpUsed }}{{ ftpTotal }}
{% trans "Databases" %}{{ databasesUsed }}{{ databasesTotal }}
{% trans "Disk Usage" %}{{ diskInMB }} (MB){{ diskInMBTotal }} (MB)
{% trans "Bandwidth Usage" %}{{ bwInMB }} (MB){{ bwInMBTotal }} (MB)
-
- -
-
-
-
-

- {% trans "Disk Usage" %} -

-
-
-
-
{{ diskUsage }}%
-
-
- - -

- {% trans "Bandwidth Usage" %} -

-
-
-
-
{{ bwUsage }}%
-
-
- - -
- -
-
-
- -
-
- - -
-
- - -
- -
-

- {% trans "Logs" %} -

- -
-
- - - - - - - -
- -
- -
-

{% trans "Logs Fetched" %}

-
- - -
-

{% trans "Could not fetch logs, see the logs file through command line. Error message:" %} - {$ errorMessage $}

-
- - -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
- - -
- -
- -
- -
- -
- -
- - -
- -
- -
-
- - - - - - - - - - - - - - - - - - - -
DomainIP AddressTimeResourceSize
-
-
- - -
- -
- -
- -
- - -
- -
- -
- -
- -
-
- - -
- - -
- - -
-
-
-
- - -
-
- -

- {% trans "Domains" %} -

- -
- -
- - - - - - - - - - - - - -
-
- - -
- -
- -
-
- -
-
- -
- -
- -
-
{% trans "Invalid Domain (Note: You don't need to add 'http' or 'https')" %}
-
- - -
- -
- -
-
- - -
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
- - -
- -
- - -
-
- - -
- -
- -
-

{$ currentStatus $}

-
- -
-
- 70% Complete -
-
- -
-

{% trans "Error message:" %} {$ errorMessage $}

-
- -
-

{% trans "Website succesfully created." %}

-
- - -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
- - -
-
- -
- -
- -
-
- - -
-
- - - - - -
- -
- - -
-

{% trans "PHP Version Changed to:" %} {$ changedPHPVersion $}

-
- -
-

{% trans "Deleted:" %} {$ deletedDomain $}

-
- -
-

{% trans "SSL Issued:" %} {$ sslDomainIssued $}

-
- -
-

{% trans "Changes applied successfully." %}

-
- - -
-

{$ errorMessage $}

-
- - -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
- - -
- -
- -
- -
- -
- - -
- - - - - - - - - - - - - - - - - - - - - - - -
DomainLaunchPathopen_basedirPHPSSLDelete
- - - - - - - - -
-
-
- - -
- -
- - -
- -
-
-
- - -
- -
-

- {% trans "Configurations" %} -

- - -
-
- - - - - - - - - - - - - - -
- -
- -
-

{% trans "SSL Saved" %}

-
- - -
-

{% trans "Could not save SSL. Error message:" %} {$ errorMessage $}

-
- - -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
- - -
-
- -
-
- -
-
- -
-
- -
- -
- - -
-
- - -
- - -
- - - - - - - -
- -
- -
-

{% trans "Current configuration in the file fetched." %}

-
- - -
-

{% trans "Could not fetch current configuration. Error message:" %} {$ - errorMessage $}

-
- - -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
- -
-

{% trans "Configurations saved." %}

-
- -
-

{% trans "Could not fetch current configuration. Error message:" %} {$ - errorMessage $}

-
- - -
-
- -
-
- -
-
- -
- -
- - -
-
- - -
- -
- - - -
- -
- - -
-

{% trans "Current rewrite rules in the file fetched." %} Click - to read more about whats changed in rewrite - rules from v1.7 onwards.

-
- - -
-

{% trans "Could not fetch current rewrite rules. Error message:" %} {$ - errorMessage $}

-
- - -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
- -
-

{% trans "Configurations saved." %}

-
- -
-

{% trans "Could not save rewrite rules. Error message:" %} {$ errorMessage - $}

-
- - -
-
- -
-
- -
-
- -
- -
- - -
-
- - -
- -
- - - -
- -
- - -
- -
- -
- -
- -
- -
- - -
- -
- -
-
- - -
- - -
-
-

{% trans "Failed to change PHP version. Error message:" %} {$ - errorMessage $}

-
- -
-

{% trans "PHP successfully changed for: " %} {$ websiteDomain - $}

-
- -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
-
- - -
- - -
-
- -
-
-
-
- - -
-
-

- {% trans "Files" %} -

- -
-
- - - - - - - - - - - - - - -
- -
- -
- -
- -
- -
- -
- -
- -
- -
- - -
- -
- -
-
-
- - -
-
-

{% trans "Error message:" %} {$ errorMessage $}

-
- -
-

{% trans "Changes successfully saved." %}

-
- -
-

{% trans "Could not connect to server. Please refresh this page." %}

-
-
- -
- - -
-
- - - - -
-
-
-
- - {% if marketingStatus %} - - - - {% endif %} - -
- -
-

- {% trans "Application Installer" %} -

- - - -
-
- - {% else %} - -
-

{{ domain }}

-
- - - {% endif %} - - -
- - - -{% endblock %} \ No newline at end of file diff --git a/emailMarketing/tests.py b/emailMarketing/tests.py deleted file mode 100644 index f067dcaac..000000000 --- a/emailMarketing/tests.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- coding: utf-8 -*- - - -from django.test import TestCase - -# Create your tests here. diff --git a/emailMarketing/urls.py b/emailMarketing/urls.py deleted file mode 100644 index fd54fe972..000000000 --- a/emailMarketing/urls.py +++ /dev/null @@ -1,31 +0,0 @@ -from django.urls import path, re_path -from . import views - -urlpatterns = [ - path('', views.emailMarketing, name='emailMarketing'), - path('fetchUsers', views.fetchUsers, name='fetchUsers'), - path('enableDisableMarketing', views.enableDisableMarketing, name='enableDisableMarketing'), - path('saveConfigureVerify', views.saveConfigureVerify, name='saveConfigureVerify'), - path('fetchVerifyLogs', views.fetchVerifyLogs, name='fetchVerifyLogs'), - re_path(r'^(?P.+)/emailLists$', views.createEmailList, name='createEmailList'), - path('submitEmailList', views.submitEmailList, name='submitEmailList'), - re_path(r'^(?P.+)/manageLists$', views.manageLists, name='manageLists'), - re_path(r'^(?P.+)/manageSMTP$', views.manageSMTP, name='manageSMTP'), - re_path(r'^(?P.+)/configureVerify$', views.configureVerify, name='configureVerify'), - path('fetchEmails', views.fetchEmails, name='fetchEmails'), - path('deleteList', views.deleteList, name='deleteList'), - path('emailVerificationJob', views.emailVerificationJob, name='emailVerificationJob'), - path('deleteEmail', views.deleteEmail, name='deleteEmail'), - path('saveSMTPHost', views.saveSMTPHost, name='saveSMTPHost'), - path('fetchSMTPHosts', views.fetchSMTPHosts, name='fetchSMTPHosts'), - path('smtpHostOperations', views.smtpHostOperations, name='smtpHostOperations'), - path('composeEmailMessage', views.composeEmailMessage, name='composeEmailMessage'), - path('saveEmailTemplate', views.saveEmailTemplate, name='saveEmailTemplate'), - path('sendEmails', views.sendEmails, name='sendEmails'), - re_path(r'^preview/(?P[-\w]+)/$', views.templatePreview, name='templatePreview'), - path('fetchJobs', views.fetchJobs, name='fetchJobs'), - path('startEmailJob', views.startEmailJob, name='startEmailJob'), - path('deleteTemplate', views.deleteTemplate, name='deleteTemplate'), - path('deleteJob', views.deleteJob, name='deleteJob'), - re_path(r'^remove/(?P[-\w]+)/(?P\w+@.+)$', views.remove, name='remove'), -] diff --git a/emailMarketing/views.py b/emailMarketing/views.py deleted file mode 100644 index 9b1e6b0ee..000000000 --- a/emailMarketing/views.py +++ /dev/null @@ -1,215 +0,0 @@ -# -*- coding: utf-8 -*- - -from django.shortcuts import redirect -from loginSystem.views import loadLoginPage -from .emailMarketingManager import EmailMarketingManager -# Create your views here. - - -def emailMarketing(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.emailMarketing() - except KeyError: - return redirect(loadLoginPage) - -def fetchUsers(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.fetchUsers() - except KeyError: - return redirect(loadLoginPage) - -def enableDisableMarketing(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.enableDisableMarketing() - except KeyError: - return redirect(loadLoginPage) - -def createEmailList(request, domain): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request, domain) - return emm.createEmailList() - except KeyError: - return redirect(loadLoginPage) - -def submitEmailList(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.submitEmailList() - except KeyError: - return redirect(loadLoginPage) - -def manageLists(request, domain): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request, domain) - return emm.manageLists() - except KeyError: - return redirect(loadLoginPage) - -def configureVerify(request, domain): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request, domain) - return emm.configureVerify() - except KeyError: - return redirect(loadLoginPage) - -def saveConfigureVerify(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.saveConfigureVerify() - except KeyError: - return redirect(loadLoginPage) - -def fetchVerifyLogs(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.fetchVerifyLogs() - except KeyError: - return redirect(loadLoginPage) - -def fetchEmails(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.fetchEmails() - except KeyError: - return redirect(loadLoginPage) - -def deleteList(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.deleteList() - except KeyError: - return redirect(loadLoginPage) - -def emailVerificationJob(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.emailVerificationJob() - except KeyError: - return redirect(loadLoginPage) - -def deleteEmail(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.deleteEmail() - except KeyError: - return redirect(loadLoginPage) - -def manageSMTP(request, domain): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request, domain) - return emm.manageSMTP() - except KeyError: - return redirect(loadLoginPage) - -def saveSMTPHost(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.saveSMTPHost() - except KeyError: - return redirect(loadLoginPage) - -def fetchSMTPHosts(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.fetchSMTPHosts() - except KeyError: - return redirect(loadLoginPage) - -def smtpHostOperations(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.smtpHostOperations() - except KeyError: - return redirect(loadLoginPage) - -def composeEmailMessage(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.composeEmailMessage() - except KeyError: - return redirect(loadLoginPage) - -def saveEmailTemplate(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.saveEmailTemplate() - except KeyError: - return redirect(loadLoginPage) - -def sendEmails(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.sendEmails() - except KeyError: - return redirect(loadLoginPage) - -def templatePreview(request, templateName): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request, templateName) - return emm.templatePreview() - except KeyError: - return redirect(loadLoginPage) - -def fetchJobs(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.fetchJobs() - except KeyError: - return redirect(loadLoginPage) - -def startEmailJob(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.startEmailJob() - except KeyError: - return redirect(loadLoginPage) - -def deleteTemplate(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.deleteTemplate() - except KeyError: - return redirect(loadLoginPage) - -def deleteJob(request): - try: - userID = request.session['userID'] - emm = EmailMarketingManager(request) - return emm.deleteJob() - except KeyError: - return redirect(loadLoginPage) - - -def remove(request, listName, emailAddress): - try: - emm = EmailMarketingManager(request) - return emm.remove(listName, emailAddress) - except KeyError: - return redirect(loadLoginPage) \ No newline at end of file diff --git a/examplePlugin/__init__.py b/examplePlugin/__init__.py deleted file mode 100644 index b3f015833..000000000 --- a/examplePlugin/__init__.py +++ /dev/null @@ -1 +0,0 @@ -default_app_config = 'examplePlugin.apps.ExamplepluginConfig' diff --git a/examplePlugin/admin.py b/examplePlugin/admin.py deleted file mode 100644 index 8c38f3f3d..000000000 --- a/examplePlugin/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/examplePlugin/apps.py b/examplePlugin/apps.py deleted file mode 100644 index 6f64e3571..000000000 --- a/examplePlugin/apps.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.apps import AppConfig - - -class ExamplepluginConfig(AppConfig): - name = 'examplePlugin' - - def ready(self): - from . import signals diff --git a/examplePlugin/enable_migrations b/examplePlugin/enable_migrations deleted file mode 100644 index e69de29bb..000000000 diff --git a/examplePlugin/meta.xml b/examplePlugin/meta.xml deleted file mode 100644 index 9e7e58b4d..000000000 --- a/examplePlugin/meta.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - examplePlugin - Utility - This is an example plugin - 1.0.1 - usmannasir - \ No newline at end of file diff --git a/examplePlugin/migrations/__init__.py b/examplePlugin/migrations/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/examplePlugin/models.py b/examplePlugin/models.py deleted file mode 100644 index c2f360a3c..000000000 --- a/examplePlugin/models.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.db import models - - -class ExamplePlugin(models.Model): - name = models.CharField(unique=True, max_length=255) - - class Meta: - # db_table = "ExamplePlugin" - pass diff --git a/examplePlugin/post_install b/examplePlugin/post_install deleted file mode 100644 index 01ec2cce3..000000000 --- a/examplePlugin/post_install +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/local/CyberCP/bin/python -RESET = '\033[0;0m' -BLUE = "\033[0;34m" -print(BLUE + "Running Post-Install Script..." + RESET) diff --git a/examplePlugin/pre_install b/examplePlugin/pre_install deleted file mode 100644 index c14bef694..000000000 --- a/examplePlugin/pre_install +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/local/CyberCP/bin/python -RESET = '\033[0;0m' -GREEN = '\033[0;32m' -print(GREEN + "Running Pre-Install Script..." + RESET) diff --git a/examplePlugin/pre_remove b/examplePlugin/pre_remove deleted file mode 100644 index eb54102ec..000000000 --- a/examplePlugin/pre_remove +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/local/CyberCP/bin/python -RESET = '\033[0;0m' -GREEN = '\033[0;32m' -print(GREEN + "Running Pre-Remove Script..." + RESET) diff --git a/examplePlugin/signals.py b/examplePlugin/signals.py deleted file mode 100644 index 0c4d14f7c..000000000 --- a/examplePlugin/signals.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.dispatch import receiver -from django.http import HttpResponse -from websiteFunctions.signals import postWebsiteDeletion -from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging - - -# This plugin respond to an event after CyberPanel core finished deleting a website. -# Original request object is passed, body can be accessed with request.body. - -# If any Event handler returns a response object, CyberPanel will stop further processing and returns your response to browser. -# To continue processing just return 200 from your events handlers. - -@receiver(postWebsiteDeletion) -def rcvr(sender, **kwargs): - request = kwargs['request'] - logging.writeToFile('Hello World from Example Plugin.') - return HttpResponse('Hello World from Example Plugin.') diff --git a/examplePlugin/static/examplePlugin/examplePlugin.js b/examplePlugin/static/examplePlugin/examplePlugin.js deleted file mode 100644 index c10ce8398..000000000 --- a/examplePlugin/static/examplePlugin/examplePlugin.js +++ /dev/null @@ -1,3 +0,0 @@ -$(document).ready(function () { - console.log("using JS in static file...!"); -}); \ No newline at end of file diff --git a/examplePlugin/templates/examplePlugin/examplePlugin.html b/examplePlugin/templates/examplePlugin/examplePlugin.html deleted file mode 100644 index 428ac6c05..000000000 --- a/examplePlugin/templates/examplePlugin/examplePlugin.html +++ /dev/null @@ -1,52 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% block styles %} - -{% endblock %} -{% block title %}Example plugin - CyberPanel{% endblock %} -{% block content %} - {% load static %} - {% get_current_language as LANGUAGE_CODE %} - -
- -
-

{% trans "Example Plugin Page" %}

-

{% trans "Example Plugin Info" %}

-
- -
-
-

{% trans "examplePlugin" %}

-
-
-
-

[[ pluginBody ]]

-
-
-
- -
-{% endblock %} - -{% block footer_scripts %} - - {# #} - - -{% endblock %} diff --git a/examplePlugin/tests.py b/examplePlugin/tests.py deleted file mode 100644 index 7ce503c2d..000000000 --- a/examplePlugin/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/examplePlugin/urls.py b/examplePlugin/urls.py deleted file mode 100644 index 421972e1a..000000000 --- a/examplePlugin/urls.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.urls import path -from . import views - -urlpatterns = [ - path('', views.examplePlugin, name='examplePlugin'), -] - diff --git a/examplePlugin/views.py b/examplePlugin/views.py deleted file mode 100644 index 2845a8f61..000000000 --- a/examplePlugin/views.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.shortcuts import render, HttpResponse - - -# Create your views here. - -def examplePlugin(request): - return render(request, 'examplePlugin/examplePlugin.html') diff --git a/install/install.py b/install/install.py index 51d98ef71..53c5ab69e 100644 --- a/install/install.py +++ b/install/install.py @@ -3235,7 +3235,7 @@ password="%s" apps_with_migrations = [ 'loginSystem', 'packages', 'websiteFunctions', 'baseTemplate', 'userManagment', 'dns', 'databases', 'ftp', 'filemanager', 'mailServer', 'emailPremium', - 'emailMarketing', 'cloudAPI', 'containerization', 'IncBackups', 'CLManager', + 'cloudAPI', 'containerization', 'IncBackups', 'CLManager', 's3Backups', 'dockerManager', 'aiScanner', 'firewall', 'tuning', 'serverStatus', 'serverLogs', 'backup', 'managePHP', 'manageSSL', 'api', 'manageServices', 'pluginHolder', 'highAvailability', 'WebTerminal' diff --git a/paypalPremiumPlugin/README.md b/paypalPremiumPlugin/README.md deleted file mode 100644 index 922bffe2e..000000000 --- a/paypalPremiumPlugin/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# Premium Plugin Example - -An example paid plugin for CyberPanel that demonstrates how to implement Patreon subscription-based plugin access. - -## Features - -- Requires Patreon subscription to "CyberPanel Paid Plugin" tier -- Users can install the plugin without subscription -- Plugin functionality is locked until subscription is verified -- Shows subscription required page when accessed without subscription - -## Installation - -1. Upload the plugin ZIP file to CyberPanel -2. Install the plugin from the plugin manager -3. The plugin will appear in the installed plugins list - -## Usage - -### For Users Without Subscription - -- Plugin can be installed -- When accessing the plugin, a subscription required page is shown -- Link to Patreon subscription page is provided - -### For Users With Subscription - -- Plugin works normally -- All features are accessible -- Settings page is available - -## Configuration - -The plugin checks for Patreon membership via the Patreon API. Make sure to configure: - -1. Patreon Client ID -2. Patreon Client Secret -3. Patreon Creator ID - -These should be set in CyberPanel environment variables or settings. - -## Meta.xml Structure - -The plugin uses the following meta.xml structure for paid plugins: - -```xml -true -CyberPanel Paid Plugin -https://www.patreon.com/c/newstargeted/membership -``` - -## Author - -master3395 - -## License - -MIT diff --git a/paypalPremiumPlugin/__init__.py b/paypalPremiumPlugin/__init__.py deleted file mode 100644 index f80c90067..000000000 --- a/paypalPremiumPlugin/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# PayPal Premium Plugin Example -# This is a paid plugin that requires PayPal payment - -default_app_config = 'paypalPremiumPlugin.apps.PaypalpremiumpluginConfig' diff --git a/paypalPremiumPlugin/api_encryption.py b/paypalPremiumPlugin/api_encryption.py deleted file mode 100644 index 8f2820ab2..000000000 --- a/paypalPremiumPlugin/api_encryption.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- coding: utf-8 -*- -""" -AES-256-CBC encryption for plugin <-> api.newstargeted.com communication. -Key must match PLUGIN_VERIFICATION_CIPHER_KEY in config.php on the API server. -""" -import json -import base64 -import os - -CIPHER_KEY_B64 = '1VLPEKTmLGUbIxHUFEtsuVM2MPN1tl8HPFtyJc4dr58=' -ENCRYPTION_ENABLED = True - -_ENCRYPTION_CIPHER_KEY = None - - -def _get_key(): - global _ENCRYPTION_CIPHER_KEY - if _ENCRYPTION_CIPHER_KEY is not None: - return _ENCRYPTION_CIPHER_KEY - try: - key = base64.b64decode(CIPHER_KEY_B64) - if len(key) == 32: - _ENCRYPTION_CIPHER_KEY = key - return key - except Exception: - pass - return None - - -def encrypt_payload(data): - if not ENCRYPTION_ENABLED or not _get_key(): - body = json.dumps(data, separators=(',', ':')).encode('utf-8') - return body, {'Content-Type': 'application/json'} - try: - from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - from cryptography.hazmat.primitives import padding - from cryptography.hazmat.backends import default_backend - key = _get_key() - plain = json.dumps(data, separators=(',', ':')).encode('utf-8') - padder = padding.PKCS7(128).padder() - padded = padder.update(plain) + padder.finalize() - iv = os.urandom(16) - cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) - encryptor = cipher.encryptor() - ciphertext = encryptor.update(padded) + encryptor.finalize() - payload = base64.b64encode(iv).decode('ascii') + '.' + base64.b64encode(ciphertext).decode('ascii') - return payload.encode('utf-8'), {'Content-Type': 'text/plain', 'X-Encrypted': '1'} - except Exception: - body = json.dumps(data, separators=(',', ':')).encode('utf-8') - return body, {'Content-Type': 'application/json'} - - -def decrypt_response(body_bytes, content_type='', expect_encrypted=False): - try: - body_str = body_bytes.decode('utf-8') if isinstance(body_bytes, bytes) else str(body_bytes) - is_encrypted = ( - expect_encrypted or - ('text/plain' in content_type and '.' in body_str) or - ('.' in body_str and body_str.strip() and body_str.strip()[0] not in '{[') - ) - parts = body_str.strip().split('.', 1) - if is_encrypted and len(parts) == 2 and ENCRYPTION_ENABLED and _get_key(): - from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - from cryptography.hazmat.primitives import padding - from cryptography.hazmat.backends import default_backend - iv = base64.b64decode(parts[0]) - ciphertext = base64.b64decode(parts[1]) - key = _get_key() - cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) - decryptor = cipher.decryptor() - padded = decryptor.update(ciphertext) + decryptor.finalize() - unpadder = padding.PKCS7(128).unpadder() - plain = unpadder.update(padded) + unpadder.finalize() - return json.loads(plain.decode('utf-8')) - return json.loads(body_str) - except Exception: - try: - return json.loads(body_bytes.decode('utf-8') if isinstance(body_bytes, bytes) else body_bytes) - except Exception: - return {} diff --git a/paypalPremiumPlugin/apps.py b/paypalPremiumPlugin/apps.py deleted file mode 100644 index 0f2389e23..000000000 --- a/paypalPremiumPlugin/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - -class PaypalpremiumpluginConfig(AppConfig): - name = 'paypalPremiumPlugin' - verbose_name = 'PayPal Premium Plugin Example' diff --git a/paypalPremiumPlugin/meta.xml b/paypalPremiumPlugin/meta.xml deleted file mode 100644 index 6535e1409..000000000 --- a/paypalPremiumPlugin/meta.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - PayPal Premium Plugin Example - Utility - 1.0.2 - An example paid plugin that requires PayPal payment. Users can install it but cannot run it without payment. Supports PayPal.me links and PayPal Payment Links/Buttons. - master3395 - https://github.com/master3395/cyberpanel-plugins - MIT - - 3.6+ - 2.2+ - 2.5.5+ - - - 2.5.5 - 3.0.0 - - - true - false - - true - CyberPanel Paid Plugin - https://www.patreon.com/membership/27789984 - https://paypal.me/KimBS?locale.x=en_US&country.x=NO - - /plugins/paypalPremiumPlugin/ - /plugins/paypalPremiumPlugin/settings/ - diff --git a/paypalPremiumPlugin/migrations/0001_initial.py b/paypalPremiumPlugin/migrations/0001_initial.py deleted file mode 100644 index 97b0f3fa8..000000000 --- a/paypalPremiumPlugin/migrations/0001_initial.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated migration for PaypalPremiumPluginConfig - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [] - - operations = [ - migrations.CreateModel( - name='PaypalPremiumPluginConfig', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('payment_method', models.CharField(choices=[('patreon', 'Patreon Subscription'), ('paypal', 'PayPal Payment'), ('both', 'Check Both (Patreon or PayPal)')], default='both', help_text='Choose which payment method to use for verification.', max_length=10)), - ('activation_key', models.CharField(blank=True, default='', help_text='Validated activation key - grants access without re-entering.', max_length=64)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ], - options={ - 'verbose_name': 'PayPal Premium Plugin Configuration', - 'verbose_name_plural': 'PayPal Premium Plugin Configurations', - }, - ), - ] diff --git a/paypalPremiumPlugin/migrations/__init__.py b/paypalPremiumPlugin/migrations/__init__.py deleted file mode 100644 index 2a0ee1c3e..000000000 --- a/paypalPremiumPlugin/migrations/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# PayPal Premium Plugin migrations diff --git a/paypalPremiumPlugin/models.py b/paypalPremiumPlugin/models.py deleted file mode 100644 index b56e0c6e4..000000000 --- a/paypalPremiumPlugin/models.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- -from django.db import models - - -class PaypalPremiumPluginConfig(models.Model): - PAYMENT_METHOD_CHOICES = [ - ('patreon', 'Patreon Subscription'), - ('paypal', 'PayPal Payment'), - ('both', 'Check Both (Patreon or PayPal)'), - ] - payment_method = models.CharField( - max_length=10, - choices=PAYMENT_METHOD_CHOICES, - default='both', - help_text="Choose which payment method to use for verification." - ) - activation_key = models.CharField( - max_length=64, - blank=True, - default='', - help_text="Validated activation key - grants access without re-entering." - ) - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) - - class Meta: - verbose_name = "PayPal Premium Plugin Configuration" - verbose_name_plural = "PayPal Premium Plugin Configurations" - - def __str__(self): - return "PayPal Premium Plugin Configuration" - - @classmethod - def get_config(cls): - config, _ = cls.objects.get_or_create(pk=1) - return config - - def save(self, *args, **kwargs): - self.pk = 1 - super().save(*args, **kwargs) diff --git a/paypalPremiumPlugin/templates/paypalPremiumPlugin/index.html b/paypalPremiumPlugin/templates/paypalPremiumPlugin/index.html deleted file mode 100644 index ac5f39dbc..000000000 --- a/paypalPremiumPlugin/templates/paypalPremiumPlugin/index.html +++ /dev/null @@ -1,96 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} - -{% block title %}{% trans "PayPal Premium Plugin Example - CyberPanel" %}{% endblock %} - -{% block header_scripts %} - -{% endblock %} - -{% block content %} -
-
- {% trans "Premium Plugin" %} -

{{ plugin_name }}

-

{{ description }}

-

{% trans "Version:" %} {{ version }}

-
- -
-

{% trans "Premium Features" %}

-
    - {% for feature in features %} -
  • {{ feature }}
  • - {% endfor %} -
-
-
-{% endblock %} diff --git a/paypalPremiumPlugin/templates/paypalPremiumPlugin/settings.html b/paypalPremiumPlugin/templates/paypalPremiumPlugin/settings.html deleted file mode 100644 index f7c9c39c6..000000000 --- a/paypalPremiumPlugin/templates/paypalPremiumPlugin/settings.html +++ /dev/null @@ -1,331 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} - -{% block title %}{% trans "PayPal Premium Plugin Settings - CyberPanel" %}{% endblock %} - -{% block header_scripts %} - -{% endblock %} - -{% block content %} -
-
- {% trans "Premium Plugin" %} -

{% trans "PayPal Premium Plugin Settings" %}

- - {% if show_payment_ui %} - -
-

{% trans "Activate Premium Access" %}

-

{% trans "If you have an activation key, enter it below." %}

- -
- {% csrf_token %} - - -
-
- -
- -
- {% csrf_token %} - -
-
- {% else %} -
- {% trans "Premium Access Active" %} — {% trans "Access granted via Plugin Grants or activation key." %} -
- {% endif %} - - -
- - {% trans "Plugin Information" %} -
    -
  • {% trans "Name" %}: {{ plugin_name|default:"PayPal Premium Plugin Example" }}
  • -
  • {% trans "Version" %}: {{ version|default:"1.0.0" }}
  • -
  • - {% trans "Status" %}: - - {{ plugin_status|default:status|default:"Active" }} - -
  • -
-
- -

{{ description }}

- -
- {% csrf_token %} -
- - -
- -
- - -
- -
- - -
- -
- -
- - -
- - {% if show_payment_ui %} - - {% endif %} -
-
-{% endblock %} diff --git a/paypalPremiumPlugin/templates/paypalPremiumPlugin/subscription_required.html b/paypalPremiumPlugin/templates/paypalPremiumPlugin/subscription_required.html deleted file mode 100644 index cf67af087..000000000 --- a/paypalPremiumPlugin/templates/paypalPremiumPlugin/subscription_required.html +++ /dev/null @@ -1,139 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} - -{% block title %}{% trans "Payment Required - PayPal Premium Plugin" %}{% endblock %} - -{% block header_scripts %} - -{% endblock %} - -{% block content %} -
-
-
-

{% trans "Premium Plugin Access Required" %}

-

{% trans "This plugin requires payment or subscription to access premium features." %}

- - -
-

{% trans "Activate Premium Access" %}

-

{% trans "If you received an activation key, enter it below." %}

- -
- {% csrf_token %} -
- - -
- -
-
- - {% if payment_method == 'both' %} -
- {% trans "Current Payment Method:" %} {% trans "Check Both (Patreon or PayPal)" %} -
- {% elif payment_method == 'patreon' %} -
- {% trans "Current Payment Method:" %} {% trans "Patreon Subscription Only" %} -
- {% elif payment_method == 'paypal' %} -
- {% trans "Current Payment Method:" %} {% trans "PayPal Payment Only" %} -
- {% endif %} - -
-
-

{% trans "Patreon Subscription" %}

-

{% trans "Subscribe to" %} "{{ patreon_tier }}"

- - {% trans "Subscribe on Patreon" %} - -
-
-

{% trans "PayPal Payment" %}

-

{% trans "Complete one-time payment via PayPal" %}

- {% if paypal_me_url %} - - {% trans "Pay with PayPal.me" %} - - {% endif %} -
-
- -
-

{% trans "How it works:" %}

-
    -
  • {% trans "Install the plugin (already done)" %}
  • -
  • {% trans "Enter activation key, subscribe on Patreon, or pay via PayPal" %}
  • -
  • {% trans "The plugin will automatically unlock" %}
  • -
-
- - {% if error %} -
- {% trans "Error:" %} {{ error }} -
- {% endif %} -
-
- - -{% endblock %} diff --git a/paypalPremiumPlugin/urls.py b/paypalPremiumPlugin/urls.py deleted file mode 100644 index 997fe20f5..000000000 --- a/paypalPremiumPlugin/urls.py +++ /dev/null @@ -1,12 +0,0 @@ -from django.urls import path, re_path -from . import views - -app_name = 'paypalPremiumPlugin' - -urlpatterns = [ - path('', views.main_view, name='main'), - path('settings/', views.settings_view, name='settings'), - re_path(r'^activate-key/$', views.activate_key, name='activate_key'), - path('save-payment-method/', views.save_payment_method, name='save_payment_method'), - path('api/status/', views.api_status_view, name='api_status'), -] diff --git a/paypalPremiumPlugin/views.py b/paypalPremiumPlugin/views.py deleted file mode 100644 index c1f96f129..000000000 --- a/paypalPremiumPlugin/views.py +++ /dev/null @@ -1,387 +0,0 @@ -# -*- coding: utf-8 -*- -""" -PayPal Premium Plugin Views - Unified Verification (same as contaboAutoSnapshot) -Supports: Plugin Grants, Activation Key, Patreon, PayPal, AES encryption -""" - -from django.shortcuts import render, redirect -from django.http import JsonResponse, HttpResponse -from django.views.decorators.http import require_http_methods -from plogical.mailUtilities import mailUtilities -from plogical.httpProc import httpProc -from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging -from functools import wraps -import urllib.request -import urllib.error -import json -import time - -from .models import PaypalPremiumPluginConfig -from . import api_encryption - -PLUGIN_NAME = 'paypalPremiumPlugin' -PLUGIN_VERSION = '1.0.2' - -REMOTE_VERIFICATION_PATREON_URL = 'https://api.newstargeted.com/api/verify-patreon-membership.php' -REMOTE_VERIFICATION_PAYPAL_URL = 'https://api.newstargeted.com/api/verify-paypal-payment.php' -REMOTE_VERIFICATION_PLUGIN_GRANT_URL = 'https://api.newstargeted.com/api/verify-plugin-grant.php' -REMOTE_ACTIVATION_KEY_URL = 'https://api.newstargeted.com/api/activate-plugin-key.php' - -PATREON_TIER = 'CyberPanel Paid Plugin' -PATREON_URL = 'https://www.patreon.com/membership/27789984' -PAYPAL_ME_URL = 'https://paypal.me/KimBS?locale.x=en_US&country.x=NO' -PAYPAL_PAYMENT_LINK = '' - - -def cyberpanel_login_required(view_func): - @wraps(view_func) - def _wrapped_view(request, *args, **kwargs): - try: - if not request.session.get('userID'): - from loginSystem.views import loadLoginPage - return redirect(loadLoginPage) - return view_func(request, *args, **kwargs) - except KeyError: - from loginSystem.views import loadLoginPage - return redirect(loadLoginPage) - return _wrapped_view - - -def _api_request(url, data, timeout=10): - try: - body, extra_headers = api_encryption.encrypt_payload(data) - headers = { - 'User-Agent': f'CyberPanel-Plugin/{PLUGIN_VERSION}', - 'X-Plugin-Name': PLUGIN_NAME - } - headers.update(extra_headers) - req = urllib.request.Request(url, data=body, headers=headers) - with urllib.request.urlopen(req, timeout=timeout) as response: - raw = response.read() - ct = response.headers.get('Content-Type', '') - expect_enc = extra_headers.get('X-Encrypted') == '1' - return api_encryption.decrypt_response(raw, ct, expect_encrypted=expect_enc) - except Exception as e: - logging.writeToFile(f"PayPal Premium Plugin: API request error to {url}: {str(e)}") - return {} - - -def check_plugin_grant(user_email, user_ip='', domain=''): - try: - request_data = { - 'user_email': user_email or '', - 'plugin_name': PLUGIN_NAME, - 'user_ip': user_ip, - 'domain': domain, - } - data = _api_request(REMOTE_VERIFICATION_PLUGIN_GRANT_URL, request_data) - if data.get('success') and data.get('has_access'): - return {'has_access': True, 'message': data.get('message', 'Access granted via Plugin Grants')} - return {'has_access': False, 'message': data.get('message', '')} - except Exception as e: - logging.writeToFile(f"PayPal Premium Plugin: Plugin grant check error: {str(e)}") - return {'has_access': False, 'message': ''} - - -def check_patreon_membership(user_email, user_ip='', domain=''): - try: - request_data = { - 'user_email': user_email, - 'plugin_name': PLUGIN_NAME, - 'plugin_version': PLUGIN_VERSION, - 'user_ip': user_ip, - 'domain': domain, - 'tier_id': '27789984' - } - response_data = _api_request(REMOTE_VERIFICATION_PATREON_URL, request_data) - if response_data.get('success', False): - return { - 'has_access': response_data.get('has_access', False), - 'patreon_tier': response_data.get('patreon_tier', PATREON_TIER), - 'patreon_url': response_data.get('patreon_url', PATREON_URL), - 'message': response_data.get('message', 'Access granted'), - 'error': None - } - return { - 'has_access': False, - 'patreon_tier': PATREON_TIER, - 'patreon_url': PATREON_URL, - 'message': response_data.get('message', 'Patreon subscription required'), - 'error': response_data.get('error') - } - except Exception as e: - logging.writeToFile(f"PayPal Premium Plugin: Patreon check error: {str(e)}") - return {'has_access': False, 'patreon_tier': PATREON_TIER, 'patreon_url': PATREON_URL, 'message': 'Unable to verify Patreon.', 'error': str(e)} - - -def check_paypal_payment(user_email, user_ip='', domain=''): - try: - request_data = { - 'user_email': user_email, - 'plugin_name': PLUGIN_NAME, - 'plugin_version': PLUGIN_VERSION, - 'user_ip': user_ip, - 'domain': domain, - 'timestamp': int(time.time()), - } - response_data = _api_request(REMOTE_VERIFICATION_PAYPAL_URL, request_data) - if response_data.get('success', False): - return { - 'has_access': response_data.get('has_access', False), - 'paypal_me_url': response_data.get('paypal_me_url', PAYPAL_ME_URL), - 'paypal_payment_link': response_data.get('paypal_payment_link', PAYPAL_PAYMENT_LINK), - 'message': response_data.get('message', 'Access granted'), - 'error': None - } - return { - 'has_access': False, - 'paypal_me_url': PAYPAL_ME_URL, - 'paypal_payment_link': PAYPAL_PAYMENT_LINK, - 'message': response_data.get('message', 'PayPal payment required'), - 'error': response_data.get('error') - } - except Exception as e: - logging.writeToFile(f"PayPal Premium Plugin: PayPal check error: {str(e)}") - return {'has_access': False, 'paypal_me_url': PAYPAL_ME_URL, 'paypal_payment_link': PAYPAL_PAYMENT_LINK, 'message': 'Unable to verify PayPal.', 'error': str(e)} - - -def unified_verification_required(view_func): - @wraps(view_func) - def _wrapped_view(request, *args, **kwargs): - try: - if not request.session.get('userID'): - from loginSystem.views import loadLoginPage - return redirect(loadLoginPage) - - user_email = request.session.get('email', '') or (getattr(request.user, 'email', '') if hasattr(request, 'user') and request.user else '') or getattr(request.user, 'username', '') - - try: - config = PaypalPremiumPluginConfig.get_config() - payment_method = config.payment_method - except Exception: - payment_method = 'both' - - has_access = False - verification_result = {} - - activation_key = request.GET.get('activation_key') or request.POST.get('activation_key') - if not activation_key: - try: - config = PaypalPremiumPluginConfig.get_config() - activation_key = getattr(config, 'activation_key', '') or '' - except Exception: - activation_key = '' - - if activation_key: - try: - request_data = {'activation_key': activation_key.strip(), 'plugin_name': PLUGIN_NAME, 'user_email': user_email} - response_data = _api_request(REMOTE_ACTIVATION_KEY_URL, request_data) - if response_data.get('success', False) and response_data.get('has_access', False): - has_access = True - verification_result = {'method': 'activation_key', 'has_access': True, 'message': response_data.get('message', 'Access activated via key')} - try: - config = PaypalPremiumPluginConfig.get_config() - config.activation_key = activation_key.strip() - config.save(update_fields=['activation_key', 'updated_at']) - except Exception as e: - logging.writeToFile(f"PayPal Premium Plugin: Could not persist activation key: {str(e)}") - elif not response_data.get('success') and activation_key: - try: - config = PaypalPremiumPluginConfig.get_config() - if getattr(config, 'activation_key', '') == activation_key.strip(): - config.activation_key = '' - config.save(update_fields=['activation_key', 'updated_at']) - except Exception: - pass - except Exception as e: - logging.writeToFile(f"PayPal Premium Plugin: Activation key check error: {str(e)}") - - if not has_access: - grant_result = check_plugin_grant(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host()) - if grant_result.get('has_access'): - has_access = True - verification_result = {'method': 'plugin_grant', 'has_access': True, 'message': grant_result.get('message', 'Access granted via Plugin Grants')} - - if not has_access: - try: - if payment_method == 'patreon': - result = check_patreon_membership(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host()) - has_access = result.get('has_access', False) - verification_result = { - 'method': 'patreon', 'has_access': has_access, - 'patreon_tier': result.get('patreon_tier', PATREON_TIER), - 'patreon_url': result.get('patreon_url', PATREON_URL), - 'paypal_me_url': PAYPAL_ME_URL, 'paypal_payment_link': PAYPAL_PAYMENT_LINK, - 'message': result.get('message', 'Patreon subscription required'), - 'error': result.get('error') - } - elif payment_method == 'paypal': - result = check_paypal_payment(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host()) - has_access = result.get('has_access', False) - verification_result = { - 'method': 'paypal', 'has_access': has_access, - 'patreon_tier': PATREON_TIER, 'patreon_url': PATREON_URL, - 'paypal_me_url': result.get('paypal_me_url', PAYPAL_ME_URL), - 'paypal_payment_link': result.get('paypal_payment_link', PAYPAL_PAYMENT_LINK), - 'message': result.get('message', 'PayPal payment required'), - 'error': result.get('error') - } - else: - patreon_result = check_patreon_membership(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host()) - paypal_result = check_paypal_payment(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host()) - has_access = patreon_result.get('has_access', False) or paypal_result.get('has_access', False) - verification_result = { - 'method': 'both', 'has_access': has_access, - 'patreon_tier': patreon_result.get('patreon_tier', PATREON_TIER), - 'patreon_url': patreon_result.get('patreon_url', PATREON_URL), - 'paypal_me_url': paypal_result.get('paypal_me_url', PAYPAL_ME_URL), - 'paypal_payment_link': paypal_result.get('paypal_payment_link', PAYPAL_PAYMENT_LINK), - 'message': 'Payment or subscription required' if not has_access else 'Access granted' - } - except Exception as e: - logging.writeToFile(f"PayPal Premium Plugin: Verification error: {str(e)}") - has_access = False - verification_result = { - 'method': payment_method, 'has_access': False, - 'patreon_tier': PATREON_TIER, 'patreon_url': PATREON_URL, - 'paypal_me_url': PAYPAL_ME_URL, 'paypal_payment_link': PAYPAL_PAYMENT_LINK, - 'message': 'Unable to verify access.', 'error': str(e) - } - - if not has_access: - context = { - 'plugin_name': 'PayPal Premium Plugin Example', - 'is_paid': True, - 'payment_method': payment_method, - 'verification_result': verification_result, - 'patreon_tier': verification_result.get('patreon_tier', PATREON_TIER), - 'patreon_url': verification_result.get('patreon_url', PATREON_URL), - 'paypal_me_url': verification_result.get('paypal_me_url', PAYPAL_ME_URL), - 'paypal_payment_link': verification_result.get('paypal_payment_link', PAYPAL_PAYMENT_LINK), - 'message': verification_result.get('message', 'Payment or subscription required'), - 'error': verification_result.get('error') - } - proc = httpProc(request, 'paypalPremiumPlugin/subscription_required.html', context, 'admin') - return proc.render() - - if has_access and verification_result: - request.session['paypal_premium_access_via'] = verification_result.get('method', '') - - return view_func(request, *args, **kwargs) - except Exception as e: - logging.writeToFile(f"PayPal Premium Plugin: Decorator error: {str(e)}") - return HttpResponse(f"

Plugin Error

{str(e)}

") - return _wrapped_view - - -@cyberpanel_login_required -def main_view(request): - mailUtilities.checkHome() - return redirect('paypalPremiumPlugin:settings') - - -@cyberpanel_login_required -@unified_verification_required -def settings_view(request): - mailUtilities.checkHome() - try: - config = PaypalPremiumPluginConfig.get_config() - except Exception: - from django.core.management import call_command - try: - call_command('migrate', 'paypalPremiumPlugin', verbosity=0, interactive=False) - config = PaypalPremiumPluginConfig.get_config() - except Exception as e: - return HttpResponse(f"

Database Error

{str(e)}

") - - access_via = request.session.get('paypal_premium_access_via', '') - show_payment_ui = access_via not in ('plugin_grant', 'activation_key') - - context = { - 'plugin_name': 'PayPal Premium Plugin Example', - 'version': PLUGIN_VERSION, - 'status': 'Active', - 'config': config, - 'has_access': True, - 'show_payment_ui': show_payment_ui, - 'access_via_grant_or_key': not show_payment_ui, - 'patreon_tier': PATREON_TIER, - 'patreon_url': PATREON_URL, - 'paypal_me_url': PAYPAL_ME_URL, - 'paypal_payment_link': PAYPAL_PAYMENT_LINK, - 'description': 'Configure your PayPal premium plugin settings.', - } - proc = httpProc(request, 'paypalPremiumPlugin/settings.html', context, 'admin') - return proc.render() - - -@cyberpanel_login_required -@require_http_methods(["POST"]) -def activate_key(request): - try: - if request.content_type == 'application/json': - data = json.loads(request.body) - else: - data = request.POST - - activation_key = data.get('activation_key', '').strip() - user_email = data.get('user_email', '').strip() - if not user_email: - user_email = request.session.get('email', '') or (getattr(request.user, 'email', '') if hasattr(request, 'user') and request.user else '') - - if not activation_key: - return JsonResponse({'success': False, 'message': 'Activation key is required'}, status=400) - - request_data = {'activation_key': activation_key, 'plugin_name': PLUGIN_NAME, 'user_email': user_email} - response_data = _api_request(REMOTE_ACTIVATION_KEY_URL, request_data) - - if response_data.get('success', False) and response_data.get('has_access', False): - try: - config = PaypalPremiumPluginConfig.get_config() - config.activation_key = activation_key - config.save(update_fields=['activation_key', 'updated_at']) - except Exception as e: - logging.writeToFile(f"PayPal Premium Plugin: Could not persist activation key: {str(e)}") - - return JsonResponse({ - 'success': True, - 'has_access': True, - 'message': response_data.get('message', 'Access activated successfully') - }) - - return JsonResponse({ - 'success': False, - 'has_access': False, - 'message': response_data.get('message', 'Invalid activation key') - }) - - except Exception as e: - logging.writeToFile(f"PayPal Premium Plugin: activate_key error: {str(e)}") - return JsonResponse({'success': False, 'message': str(e)}, status=500) - - -@cyberpanel_login_required -@require_http_methods(["POST"]) -def save_payment_method(request): - try: - payment_method = request.POST.get('payment_method', 'both') - if payment_method not in ('patreon', 'paypal', 'both'): - payment_method = 'both' - config = PaypalPremiumPluginConfig.get_config() - config.payment_method = payment_method - config.save(update_fields=['payment_method', 'updated_at']) - return JsonResponse({'success': True, 'message': 'Payment method saved'}) - except Exception as e: - return JsonResponse({'success': False, 'message': str(e)}, status=500) - - -@cyberpanel_login_required -@unified_verification_required -def api_status_view(request): - return JsonResponse({ - 'plugin_name': 'PayPal Premium Plugin Example', - 'version': PLUGIN_VERSION, - 'status': 'active', - 'payment': 'verified', - 'verification_method': 'unified' - }) diff --git a/premiumPlugin/.gitignore b/premiumPlugin/.gitignore deleted file mode 100644 index 2ef72c88d..000000000 --- a/premiumPlugin/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Security - Never commit secrets -*.secret -*_secret* -patreon_config.py -.env.patreon -patreon_secrets.env diff --git a/premiumPlugin/README-REMOTE-VERIFICATION.md b/premiumPlugin/README-REMOTE-VERIFICATION.md deleted file mode 100644 index 09decfcd6..000000000 --- a/premiumPlugin/README-REMOTE-VERIFICATION.md +++ /dev/null @@ -1,81 +0,0 @@ -# Remote Verification Setup - -## Overview - -This version of the plugin uses **remote verification** - all Patreon API calls happen on YOUR server, not the user's server. - -## Benefits - -āœ… **No secrets in plugin** - Users can see all plugin code, but no credentials -āœ… **Secure** - All Patreon API credentials stay on your server -āœ… **Centralized** - You control access, can revoke, update logic, etc. -āœ… **Public code** - Plugin code can be open source - -## Architecture - -``` -User's Server Your Server Patreon API - | | | - |-- Verify Request ------------> | | - | |-- Check Membership --> | - | |<-- Membership Status - | - |<-- Access Granted/Denied ----- | | -``` - -## Setup - -### 1. Deploy Verification API - -Deploy the verification endpoint to your server: -- File: `/home/newstargeted.com/api.newstargeted.com/modules/patreon/verify-membership.php` -- URL: `https://api.newstargeted.com/api/verify-patreon-membership` - -### 2. Configure Your Server - -Add Patreon credentials to your server's `config.php`: - -```php -define('PATREON_CLIENT_ID', 'your_client_id'); -define('PATREON_CLIENT_SECRET', 'your_client_secret'); -define('PATREON_CREATOR_ACCESS_TOKEN', 'your_access_token'); -``` - -### 3. Update Plugin - -Replace `views.py` with `views_remote.py`: - -```bash -mv views.py views_local.py # Backup local version -mv views_remote.py views.py # Use remote version -``` - -### 4. Configure Plugin URL - -Update `REMOTE_VERIFICATION_URL` in `views.py` to point to your server: - -```python -REMOTE_VERIFICATION_URL = 'https://api.newstargeted.com/api/verify-patreon-membership' -``` - -## Security Features - -- **Rate limiting** - Prevents abuse (60 requests/hour per IP) -- **HTTPS only** - All communication encrypted -- **No secrets** - Plugin only makes API calls -- **Caching** - Reduces Patreon API calls (5 min cache) - -## Testing - -1. Install plugin on user's server -2. Try accessing plugin (should show subscription required) -3. Subscribe to Patreon tier -4. Access plugin again (should work) - -## Migration from Local Verification - -If you were using local verification: - -1. Keep `views_local.py` as backup -2. Use `views_remote.py` as `views.py` -3. Deploy verification API to your server -4. Update plugin URL in code diff --git a/premiumPlugin/README.md b/premiumPlugin/README.md deleted file mode 100644 index 922bffe2e..000000000 --- a/premiumPlugin/README.md +++ /dev/null @@ -1,58 +0,0 @@ -# Premium Plugin Example - -An example paid plugin for CyberPanel that demonstrates how to implement Patreon subscription-based plugin access. - -## Features - -- Requires Patreon subscription to "CyberPanel Paid Plugin" tier -- Users can install the plugin without subscription -- Plugin functionality is locked until subscription is verified -- Shows subscription required page when accessed without subscription - -## Installation - -1. Upload the plugin ZIP file to CyberPanel -2. Install the plugin from the plugin manager -3. The plugin will appear in the installed plugins list - -## Usage - -### For Users Without Subscription - -- Plugin can be installed -- When accessing the plugin, a subscription required page is shown -- Link to Patreon subscription page is provided - -### For Users With Subscription - -- Plugin works normally -- All features are accessible -- Settings page is available - -## Configuration - -The plugin checks for Patreon membership via the Patreon API. Make sure to configure: - -1. Patreon Client ID -2. Patreon Client Secret -3. Patreon Creator ID - -These should be set in CyberPanel environment variables or settings. - -## Meta.xml Structure - -The plugin uses the following meta.xml structure for paid plugins: - -```xml -true -CyberPanel Paid Plugin -https://www.patreon.com/c/newstargeted/membership -``` - -## Author - -master3395 - -## License - -MIT diff --git a/premiumPlugin/SECURITY.md b/premiumPlugin/SECURITY.md deleted file mode 100644 index b2df3648e..000000000 --- a/premiumPlugin/SECURITY.md +++ /dev/null @@ -1,57 +0,0 @@ -# Security Guidelines for Premium Plugin - -## āš ļø IMPORTANT: Never Expose Secrets - -This plugin is designed to be **publicly shareable**. It contains **NO secrets** and is safe to publish. - -## What's Safe to Share - -āœ… **Safe to commit:** -- Plugin code (views.py, urls.py, etc.) -- Templates (HTML files) -- meta.xml (no secrets, only tier name and URL) -- README.md -- Documentation - -āŒ **Never commit:** -- Patreon Client Secret -- Patreon Access Tokens -- Patreon Refresh Tokens -- Any hardcoded credentials - -## Configuration - -All Patreon credentials are configured on the **server side** via: -- Environment variables -- Django settings (from environment) -- Secure config files (not in repository) - -## For Your Own Setup - -When setting up this plugin on your server: - -1. **Do NOT** modify plugin files with your secrets -2. **Do** configure environment variables on the server -3. **Do** use Django settings.py (with environment variable fallbacks) -4. **Do** add any secret config files to .gitignore - -## Example Secure Configuration - -```python -# In settings.py (safe to commit) -PATREON_CLIENT_ID = os.environ.get('PATREON_CLIENT_ID', '') -PATREON_CLIENT_SECRET = os.environ.get('PATREON_CLIENT_SECRET', '') - -# On server (NOT in repo) -export PATREON_CLIENT_ID="your_actual_secret" -export PATREON_CLIENT_SECRET="your_actual_secret" -``` - -## Verification - -Before publishing, verify: -- [ ] No secrets in plugin files -- [ ] No secrets in meta.xml -- [ ] No secrets in README -- [ ] All credentials use environment variables -- [ ] .gitignore excludes secret files diff --git a/premiumPlugin/__init__.py b/premiumPlugin/__init__.py deleted file mode 100644 index deac71067..000000000 --- a/premiumPlugin/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# Premium Plugin Example -# This is a paid plugin that requires Patreon subscription - -default_app_config = 'premiumPlugin.apps.PremiumPluginConfig' diff --git a/premiumPlugin/api_encryption.py b/premiumPlugin/api_encryption.py deleted file mode 100644 index 50f8b3d10..000000000 --- a/premiumPlugin/api_encryption.py +++ /dev/null @@ -1,83 +0,0 @@ -# -*- coding: utf-8 -*- -""" -AES-256-CBC encryption for plugin <-> api.newstargeted.com communication. -Key must match PLUGIN_VERIFICATION_CIPHER_KEY in config.php on the API server. -""" -import json -import base64 -import os - -CIPHER_KEY_B64 = '1VLPEKTmLGUbIxHUFEtsuVM2MPN1tl8HPFtyJc4dr58=' -ENCRYPTION_ENABLED = True - -_ENCRYPTION_CIPHER_KEY = None - - -def _get_key(): - """Get 32-byte AES key from base64.""" - global _ENCRYPTION_CIPHER_KEY - if _ENCRYPTION_CIPHER_KEY is not None: - return _ENCRYPTION_CIPHER_KEY - try: - key = base64.b64decode(CIPHER_KEY_B64) - if len(key) == 32: - _ENCRYPTION_CIPHER_KEY = key - return key - except Exception: - pass - return None - - -def encrypt_payload(data): - """Encrypt JSON payload for API request. Returns (body_bytes, headers_dict).""" - if not ENCRYPTION_ENABLED or not _get_key(): - body = json.dumps(data, separators=(',', ':')).encode('utf-8') - return body, {'Content-Type': 'application/json'} - try: - from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - from cryptography.hazmat.primitives import padding - from cryptography.hazmat.backends import default_backend - key = _get_key() - plain = json.dumps(data, separators=(',', ':')).encode('utf-8') - padder = padding.PKCS7(128).padder() - padded = padder.update(plain) + padder.finalize() - iv = os.urandom(16) - cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) - encryptor = cipher.encryptor() - ciphertext = encryptor.update(padded) + encryptor.finalize() - payload = base64.b64encode(iv).decode('ascii') + '.' + base64.b64encode(ciphertext).decode('ascii') - return payload.encode('utf-8'), {'Content-Type': 'text/plain', 'X-Encrypted': '1'} - except Exception: - body = json.dumps(data, separators=(',', ':')).encode('utf-8') - return body, {'Content-Type': 'application/json'} - - -def decrypt_response(body_bytes, content_type='', expect_encrypted=False): - """Decrypt API response. Handles both encrypted and plain JSON.""" - try: - body_str = body_bytes.decode('utf-8') if isinstance(body_bytes, bytes) else str(body_bytes) - is_encrypted = ( - expect_encrypted or - ('text/plain' in content_type and '.' in body_str) or - ('.' in body_str and body_str.strip() and body_str.strip()[0] not in '{[') - ) - parts = body_str.strip().split('.', 1) - if is_encrypted and len(parts) == 2 and ENCRYPTION_ENABLED and _get_key(): - from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes - from cryptography.hazmat.primitives import padding - from cryptography.hazmat.backends import default_backend - iv = base64.b64decode(parts[0]) - ciphertext = base64.b64decode(parts[1]) - key = _get_key() - cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) - decryptor = cipher.decryptor() - padded = decryptor.update(ciphertext) + decryptor.finalize() - unpadder = padding.PKCS7(128).unpadder() - plain = unpadder.update(padded) + unpadder.finalize() - return json.loads(plain.decode('utf-8')) - return json.loads(body_str) - except Exception: - try: - return json.loads(body_bytes.decode('utf-8') if isinstance(body_bytes, bytes) else body_bytes) - except Exception: - return {} diff --git a/premiumPlugin/apps.py b/premiumPlugin/apps.py deleted file mode 100644 index 261eb7905..000000000 --- a/premiumPlugin/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - -class PremiumPluginConfig(AppConfig): - name = 'premiumPlugin' - verbose_name = 'Premium Plugin Example' diff --git a/premiumPlugin/meta.xml b/premiumPlugin/meta.xml deleted file mode 100644 index a986da653..000000000 --- a/premiumPlugin/meta.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - Premium Plugin Example - Utility - 1.0.2 - An example paid plugin that requires Patreon subscription to "CyberPanel Paid Plugin" tier. Users can install it but cannot run it without subscription. - master3395 - https://github.com/master3395/cyberpanel-plugins - MIT - - 3.6+ - 2.2+ - 2.5.5+ - - - 2.5.5 - 3.0.0 - - - true - false - - true - CyberPanel Paid Plugin - https://www.patreon.com/membership/27789984 - https://paypal.me/KimBS?locale.x=en_US&country.x=NO - - /plugins/premiumPlugin/ - /plugins/premiumPlugin/settings/ - diff --git a/premiumPlugin/migrations/0001_initial.py b/premiumPlugin/migrations/0001_initial.py deleted file mode 100644 index e403a7fbd..000000000 --- a/premiumPlugin/migrations/0001_initial.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated migration for PremiumPluginConfig - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [] - - operations = [ - migrations.CreateModel( - name='PremiumPluginConfig', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('payment_method', models.CharField(choices=[('patreon', 'Patreon Subscription'), ('paypal', 'PayPal Payment'), ('both', 'Check Both (Patreon or PayPal)')], default='both', help_text='Choose which payment method to use for verification.', max_length=10)), - ('activation_key', models.CharField(blank=True, default='', help_text='Validated activation key - grants access without re-entering.', max_length=64)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ], - options={ - 'verbose_name': 'Premium Plugin Configuration', - 'verbose_name_plural': 'Premium Plugin Configurations', - }, - ), - ] diff --git a/premiumPlugin/migrations/__init__.py b/premiumPlugin/migrations/__init__.py deleted file mode 100644 index 80dc97892..000000000 --- a/premiumPlugin/migrations/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# Premium Plugin migrations diff --git a/premiumPlugin/models.py b/premiumPlugin/models.py deleted file mode 100644 index a4396a32a..000000000 --- a/premiumPlugin/models.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- -from django.db import models - - -class PremiumPluginConfig(models.Model): - """Config for Premium Plugin - activation key and payment preference.""" - PAYMENT_METHOD_CHOICES = [ - ('patreon', 'Patreon Subscription'), - ('paypal', 'PayPal Payment'), - ('both', 'Check Both (Patreon or PayPal)'), - ] - payment_method = models.CharField( - max_length=10, - choices=PAYMENT_METHOD_CHOICES, - default='both', - help_text="Choose which payment method to use for verification." - ) - activation_key = models.CharField( - max_length=64, - blank=True, - default='', - help_text="Validated activation key - grants access without re-entering." - ) - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) - - class Meta: - verbose_name = "Premium Plugin Configuration" - verbose_name_plural = "Premium Plugin Configurations" - - def __str__(self): - return "Premium Plugin Configuration" - - @classmethod - def get_config(cls): - """Get or create the singleton config instance.""" - config, _ = cls.objects.get_or_create(pk=1) - return config - - def save(self, *args, **kwargs): - self.pk = 1 - super().save(*args, **kwargs) diff --git a/premiumPlugin/templates/premiumPlugin/index.html b/premiumPlugin/templates/premiumPlugin/index.html deleted file mode 100644 index f7ab4e200..000000000 --- a/premiumPlugin/templates/premiumPlugin/index.html +++ /dev/null @@ -1,96 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} - -{% block title %}{% trans "Premium Plugin Example - CyberPanel" %}{% endblock %} - -{% block header_scripts %} - -{% endblock %} - -{% block content %} -
-
- {% trans "Premium Plugin" %} -

{{ plugin_name }}

-

{{ description }}

-

{% trans "Version:" %} {{ version }}

-
- -
-

{% trans "Premium Features" %}

-
    - {% for feature in features %} -
  • {{ feature }}
  • - {% endfor %} -
-
-
-{% endblock %} diff --git a/premiumPlugin/templates/premiumPlugin/settings.html b/premiumPlugin/templates/premiumPlugin/settings.html deleted file mode 100644 index 59a83d132..000000000 --- a/premiumPlugin/templates/premiumPlugin/settings.html +++ /dev/null @@ -1,315 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} - -{% block title %}{% trans "Premium Plugin Settings - CyberPanel" %}{% endblock %} - -{% block header_scripts %} - -{% endblock %} - -{% block content %} -
-
- {% trans "Premium Plugin" %} -

{% trans "Premium Plugin Settings" %}

- - {% if show_payment_ui %} - -
-

{% trans "Activate Premium Access" %}

-

{% trans "If you have an activation key, enter it below." %}

- -
- {% csrf_token %} - - -
-
- -
- -
- {% csrf_token %} - -
-
- {% else %} -
- {% trans "Premium Access Active" %} — {% trans "Access granted via Plugin Grants or activation key." %} -
- {% endif %} - - -
- - {% trans "Plugin Information" %} -
    -
  • {% trans "Name" %}: {{ plugin_name|default:"Premium Plugin Example" }}
  • -
  • {% trans "Version" %}: {{ version|default:"1.0.0" }}
  • -
  • - {% trans "Status" %}: - - {{ plugin_status|default:status|default:"Active" }} - -
  • -
-
- -

{{ description }}

- -
- {% csrf_token %} -
- - -
- -
- - -
- -
- - -
- -
- -
- - -
- - {% if show_payment_ui %} - - {% endif %} -
-
-{% endblock %} diff --git a/premiumPlugin/templates/premiumPlugin/subscription_required.html b/premiumPlugin/templates/premiumPlugin/subscription_required.html deleted file mode 100644 index cfc11a35a..000000000 --- a/premiumPlugin/templates/premiumPlugin/subscription_required.html +++ /dev/null @@ -1,139 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} - -{% block title %}{% trans "Payment Required - Premium Plugin" %}{% endblock %} - -{% block header_scripts %} - -{% endblock %} - -{% block content %} -
-
-
-

{% trans "Premium Plugin Access Required" %}

-

{% trans "This plugin requires payment or subscription to access premium features." %}

- - -
-

{% trans "Activate Premium Access" %}

-

{% trans "If you received an activation key, enter it below." %}

- -
- {% csrf_token %} -
- - -
- -
-
- - {% if payment_method == 'both' %} -
- {% trans "Current Payment Method:" %} {% trans "Check Both (Patreon or PayPal)" %} -
- {% elif payment_method == 'patreon' %} -
- {% trans "Current Payment Method:" %} {% trans "Patreon Subscription Only" %} -
- {% elif payment_method == 'paypal' %} -
- {% trans "Current Payment Method:" %} {% trans "PayPal Payment Only" %} -
- {% endif %} - -
-
-

{% trans "Patreon Subscription" %}

-

{% trans "Subscribe to" %} "{{ patreon_tier }}"

- - {% trans "Subscribe on Patreon" %} - -
-
-

{% trans "PayPal Payment" %}

-

{% trans "Complete one-time payment via PayPal" %}

- {% if paypal_me_url %} - - {% trans "Pay with PayPal.me" %} - - {% endif %} -
-
- -
-

{% trans "How it works:" %}

-
    -
  • {% trans "Install the plugin (already done)" %}
  • -
  • {% trans "Enter activation key, subscribe on Patreon, or pay via PayPal" %}
  • -
  • {% trans "The plugin will automatically unlock" %}
  • -
-
- - {% if error %} -
- {% trans "Error:" %} {{ error }} -
- {% endif %} -
-
- - -{% endblock %} diff --git a/premiumPlugin/urls.py b/premiumPlugin/urls.py deleted file mode 100644 index a9c206dbe..000000000 --- a/premiumPlugin/urls.py +++ /dev/null @@ -1,12 +0,0 @@ -from django.urls import path, re_path -from . import views - -app_name = 'premiumPlugin' - -urlpatterns = [ - path('', views.main_view, name='main'), - path('settings/', views.settings_view, name='settings'), - re_path(r'^activate-key/$', views.activate_key, name='activate_key'), - path('save-payment-method/', views.save_payment_method, name='save_payment_method'), - path('api/status/', views.api_status_view, name='api_status'), -] diff --git a/premiumPlugin/views.py b/premiumPlugin/views.py deleted file mode 100644 index fb887850f..000000000 --- a/premiumPlugin/views.py +++ /dev/null @@ -1,406 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Premium Plugin Views - Unified Verification (same as contaboAutoSnapshot) -Supports: Plugin Grants, Activation Key, Patreon, PayPal, AES encryption -""" - -from django.shortcuts import render, redirect -from django.http import JsonResponse, HttpResponse -from django.views.decorators.http import require_http_methods -from plogical.mailUtilities import mailUtilities -from plogical.httpProc import httpProc -from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging -from functools import wraps -import urllib.request -import urllib.error -import json - -from .models import PremiumPluginConfig -from . import api_encryption - -PLUGIN_NAME = 'premiumPlugin' -PLUGIN_VERSION = '1.0.2' - -REMOTE_VERIFICATION_PATREON_URL = 'https://api.newstargeted.com/api/verify-patreon-membership.php' -REMOTE_VERIFICATION_PAYPAL_URL = 'https://api.newstargeted.com/api/verify-paypal-payment.php' -REMOTE_VERIFICATION_PLUGIN_GRANT_URL = 'https://api.newstargeted.com/api/verify-plugin-grant.php' -REMOTE_ACTIVATION_KEY_URL = 'https://api.newstargeted.com/api/activate-plugin-key.php' - -PATREON_TIER = 'CyberPanel Paid Plugin' -PATREON_URL = 'https://www.patreon.com/membership/27789984' -PAYPAL_ME_URL = 'https://paypal.me/KimBS?locale.x=en_US&country.x=NO' -PAYPAL_PAYMENT_LINK = '' - - -def cyberpanel_login_required(view_func): - @wraps(view_func) - def _wrapped_view(request, *args, **kwargs): - try: - if not request.session.get('userID'): - from loginSystem.views import loadLoginPage - return redirect(loadLoginPage) - return view_func(request, *args, **kwargs) - except KeyError: - from loginSystem.views import loadLoginPage - return redirect(loadLoginPage) - return _wrapped_view - - -def _api_request(url, data, timeout=10): - """Send encrypted API request and return decoded response dict.""" - try: - body, extra_headers = api_encryption.encrypt_payload(data) - headers = { - 'User-Agent': f'CyberPanel-Plugin/{PLUGIN_VERSION}', - 'X-Plugin-Name': PLUGIN_NAME - } - headers.update(extra_headers) - req = urllib.request.Request(url, data=body, headers=headers) - with urllib.request.urlopen(req, timeout=timeout) as response: - raw = response.read() - ct = response.headers.get('Content-Type', '') - expect_enc = extra_headers.get('X-Encrypted') == '1' - return api_encryption.decrypt_response(raw, ct, expect_encrypted=expect_enc) - except Exception as e: - logging.writeToFile(f"Premium Plugin: API request error to {url}: {str(e)}") - return {} - - -def check_plugin_grant(user_email, user_ip='', domain=''): - try: - request_data = { - 'user_email': user_email or '', - 'plugin_name': PLUGIN_NAME, - 'user_ip': user_ip, - 'domain': domain, - } - data = _api_request(REMOTE_VERIFICATION_PLUGIN_GRANT_URL, request_data) - if data.get('success') and data.get('has_access'): - return {'has_access': True, 'message': data.get('message', 'Access granted via Plugin Grants')} - return {'has_access': False, 'message': data.get('message', '')} - except Exception as e: - logging.writeToFile(f"Premium Plugin: Plugin grant check error: {str(e)}") - return {'has_access': False, 'message': ''} - - -def check_patreon_membership(user_email, user_ip='', domain=''): - try: - request_data = { - 'user_email': user_email, - 'plugin_name': PLUGIN_NAME, - 'plugin_version': PLUGIN_VERSION, - 'user_ip': user_ip, - 'domain': domain, - 'tier_id': '27789984' - } - response_data = _api_request(REMOTE_VERIFICATION_PATREON_URL, request_data) - if response_data.get('success', False): - return { - 'has_access': response_data.get('has_access', False), - 'patreon_tier': response_data.get('patreon_tier', PATREON_TIER), - 'patreon_url': response_data.get('patreon_url', PATREON_URL), - 'message': response_data.get('message', 'Access granted'), - 'error': None - } - return { - 'has_access': False, - 'patreon_tier': PATREON_TIER, - 'patreon_url': PATREON_URL, - 'message': response_data.get('message', 'Patreon subscription required'), - 'error': response_data.get('error') - } - except Exception as e: - logging.writeToFile(f"Premium Plugin: Patreon check error: {str(e)}") - return { - 'has_access': False, - 'patreon_tier': PATREON_TIER, - 'patreon_url': PATREON_URL, - 'message': 'Unable to verify Patreon membership.', - 'error': str(e) - } - - -def check_paypal_payment(user_email, user_ip='', domain=''): - try: - request_data = { - 'user_email': user_email, - 'plugin_name': PLUGIN_NAME, - 'plugin_version': PLUGIN_VERSION, - 'user_ip': user_ip, - 'domain': domain, - 'timestamp': 0, - } - import time - request_data['timestamp'] = int(time.time()) - response_data = _api_request(REMOTE_VERIFICATION_PAYPAL_URL, request_data) - if response_data.get('success', False): - return { - 'has_access': response_data.get('has_access', False), - 'paypal_me_url': response_data.get('paypal_me_url', PAYPAL_ME_URL), - 'paypal_payment_link': response_data.get('paypal_payment_link', PAYPAL_PAYMENT_LINK), - 'message': response_data.get('message', 'Access granted'), - 'error': None - } - return { - 'has_access': False, - 'paypal_me_url': PAYPAL_ME_URL, - 'paypal_payment_link': PAYPAL_PAYMENT_LINK, - 'message': response_data.get('message', 'PayPal payment required'), - 'error': response_data.get('error') - } - except Exception as e: - logging.writeToFile(f"Premium Plugin: PayPal check error: {str(e)}") - return { - 'has_access': False, - 'paypal_me_url': PAYPAL_ME_URL, - 'paypal_payment_link': PAYPAL_PAYMENT_LINK, - 'message': 'Unable to verify PayPal payment.', - 'error': str(e) - } - - -def unified_verification_required(view_func): - @wraps(view_func) - def _wrapped_view(request, *args, **kwargs): - try: - if not request.session.get('userID'): - from loginSystem.views import loadLoginPage - return redirect(loadLoginPage) - - user_email = request.session.get('email', '') or (getattr(request.user, 'email', '') if hasattr(request, 'user') and request.user else '') or getattr(request.user, 'username', '') - - try: - config = PremiumPluginConfig.get_config() - payment_method = config.payment_method - except Exception: - payment_method = 'both' - - has_access = False - verification_result = {} - - activation_key = request.GET.get('activation_key') or request.POST.get('activation_key') - if not activation_key: - try: - config = PremiumPluginConfig.get_config() - activation_key = getattr(config, 'activation_key', '') or '' - except Exception: - activation_key = '' - - if activation_key: - try: - request_data = { - 'activation_key': activation_key.strip(), - 'plugin_name': PLUGIN_NAME, - 'user_email': user_email - } - response_data = _api_request(REMOTE_ACTIVATION_KEY_URL, request_data) - if response_data.get('success', False) and response_data.get('has_access', False): - has_access = True - verification_result = {'method': 'activation_key', 'has_access': True, 'message': response_data.get('message', 'Access activated via key')} - try: - config = PremiumPluginConfig.get_config() - config.activation_key = activation_key.strip() - config.save(update_fields=['activation_key', 'updated_at']) - except Exception as e: - logging.writeToFile(f"Premium Plugin: Could not persist activation key: {str(e)}") - elif not response_data.get('success') and activation_key: - try: - config = PremiumPluginConfig.get_config() - if getattr(config, 'activation_key', '') == activation_key.strip(): - config.activation_key = '' - config.save(update_fields=['activation_key', 'updated_at']) - except Exception: - pass - except Exception as e: - logging.writeToFile(f"Premium Plugin: Activation key check error: {str(e)}") - - if not has_access: - grant_result = check_plugin_grant(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host()) - if grant_result.get('has_access'): - has_access = True - verification_result = {'method': 'plugin_grant', 'has_access': True, 'message': grant_result.get('message', 'Access granted via Plugin Grants')} - - if not has_access: - try: - if payment_method == 'patreon': - result = check_patreon_membership(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host()) - has_access = result.get('has_access', False) - verification_result = { - 'method': 'patreon', 'has_access': has_access, - 'patreon_tier': result.get('patreon_tier', PATREON_TIER), - 'patreon_url': result.get('patreon_url', PATREON_URL), - 'paypal_me_url': PAYPAL_ME_URL, 'paypal_payment_link': PAYPAL_PAYMENT_LINK, - 'message': result.get('message', 'Patreon subscription required'), - 'error': result.get('error') - } - elif payment_method == 'paypal': - result = check_paypal_payment(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host()) - has_access = result.get('has_access', False) - verification_result = { - 'method': 'paypal', 'has_access': has_access, - 'patreon_tier': PATREON_TIER, 'patreon_url': PATREON_URL, - 'paypal_me_url': result.get('paypal_me_url', PAYPAL_ME_URL), - 'paypal_payment_link': result.get('paypal_payment_link', PAYPAL_PAYMENT_LINK), - 'message': result.get('message', 'PayPal payment required'), - 'error': result.get('error') - } - else: - patreon_result = check_patreon_membership(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host()) - paypal_result = check_paypal_payment(user_email, request.META.get('REMOTE_ADDR', ''), request.get_host()) - has_access = patreon_result.get('has_access', False) or paypal_result.get('has_access', False) - verification_result = { - 'method': 'both', 'has_access': has_access, - 'patreon_tier': patreon_result.get('patreon_tier', PATREON_TIER), - 'patreon_url': patreon_result.get('patreon_url', PATREON_URL), - 'paypal_me_url': paypal_result.get('paypal_me_url', PAYPAL_ME_URL), - 'paypal_payment_link': paypal_result.get('paypal_payment_link', PAYPAL_PAYMENT_LINK), - 'message': 'Payment or subscription required' if not has_access else 'Access granted' - } - except Exception as e: - logging.writeToFile(f"Premium Plugin: Verification error: {str(e)}") - has_access = False - verification_result = { - 'method': payment_method, 'has_access': False, - 'patreon_tier': PATREON_TIER, 'patreon_url': PATREON_URL, - 'paypal_me_url': PAYPAL_ME_URL, 'paypal_payment_link': PAYPAL_PAYMENT_LINK, - 'message': 'Unable to verify access.', - 'error': str(e) - } - - if not has_access: - context = { - 'plugin_name': 'Premium Plugin Example', - 'is_paid': True, - 'payment_method': payment_method, - 'verification_result': verification_result, - 'patreon_tier': verification_result.get('patreon_tier', PATREON_TIER), - 'patreon_url': verification_result.get('patreon_url', PATREON_URL), - 'paypal_me_url': verification_result.get('paypal_me_url', PAYPAL_ME_URL), - 'paypal_payment_link': verification_result.get('paypal_payment_link', PAYPAL_PAYMENT_LINK), - 'message': verification_result.get('message', 'Payment or subscription required'), - 'error': verification_result.get('error') - } - proc = httpProc(request, 'premiumPlugin/subscription_required.html', context, 'admin') - return proc.render() - - if has_access and verification_result: - request.session['premium_plugin_access_via'] = verification_result.get('method', '') - - return view_func(request, *args, **kwargs) - except Exception as e: - logging.writeToFile(f"Premium Plugin: Decorator error: {str(e)}") - return HttpResponse(f"

Plugin Error

{str(e)}

") - return _wrapped_view - - -@cyberpanel_login_required -def main_view(request): - mailUtilities.checkHome() - return redirect('premiumPlugin:settings') - - -@cyberpanel_login_required -@unified_verification_required -def settings_view(request): - mailUtilities.checkHome() - try: - config = PremiumPluginConfig.get_config() - except Exception: - from django.core.management import call_command - try: - call_command('migrate', 'premiumPlugin', verbosity=0, interactive=False) - config = PremiumPluginConfig.get_config() - except Exception as e: - return HttpResponse(f"

Database Error

{str(e)}

") - - access_via = request.session.get('premium_plugin_access_via', '') - show_payment_ui = access_via not in ('plugin_grant', 'activation_key') - - context = { - 'plugin_name': 'Premium Plugin Example', - 'version': PLUGIN_VERSION, - 'status': 'Active', - 'config': config, - 'has_access': True, - 'show_payment_ui': show_payment_ui, - 'access_via_grant_or_key': not show_payment_ui, - 'patreon_tier': PATREON_TIER, - 'patreon_url': PATREON_URL, - 'paypal_me_url': PAYPAL_ME_URL, - 'paypal_payment_link': PAYPAL_PAYMENT_LINK, - 'description': 'Configure your premium plugin settings.', - } - proc = httpProc(request, 'premiumPlugin/settings.html', context, 'admin') - return proc.render() - - -@cyberpanel_login_required -@require_http_methods(["POST"]) -def activate_key(request): - try: - if request.content_type == 'application/json': - data = json.loads(request.body) - else: - data = request.POST - - activation_key = data.get('activation_key', '').strip() - user_email = data.get('user_email', '').strip() - if not user_email: - user_email = request.session.get('email', '') or (getattr(request.user, 'email', '') if hasattr(request, 'user') and request.user else '') - - if not activation_key: - return JsonResponse({'success': False, 'message': 'Activation key is required'}, status=400) - - request_data = {'activation_key': activation_key, 'plugin_name': PLUGIN_NAME, 'user_email': user_email} - response_data = _api_request(REMOTE_ACTIVATION_KEY_URL, request_data) - - if response_data.get('success', False) and response_data.get('has_access', False): - try: - config = PremiumPluginConfig.get_config() - config.activation_key = activation_key - config.save(update_fields=['activation_key', 'updated_at']) - except Exception as e: - logging.writeToFile(f"Premium Plugin: Could not persist activation key: {str(e)}") - - return JsonResponse({ - 'success': True, - 'has_access': True, - 'message': response_data.get('message', 'Access activated successfully') - }) - - return JsonResponse({ - 'success': False, - 'has_access': False, - 'message': response_data.get('message', 'Invalid activation key') - }) - - except Exception as e: - logging.writeToFile(f"Premium Plugin: activate_key error: {str(e)}") - return JsonResponse({'success': False, 'message': str(e)}, status=500) - - -@cyberpanel_login_required -@require_http_methods(["POST"]) -def save_payment_method(request): - try: - payment_method = request.POST.get('payment_method', 'both') - if payment_method not in ('patreon', 'paypal', 'both'): - payment_method = 'both' - config = PremiumPluginConfig.get_config() - config.payment_method = payment_method - config.save(update_fields=['payment_method', 'updated_at']) - return JsonResponse({'success': True, 'message': 'Payment method saved'}) - except Exception as e: - return JsonResponse({'success': False, 'message': str(e)}, status=500) - - -@cyberpanel_login_required -@unified_verification_required -def api_status_view(request): - return JsonResponse({ - 'plugin_name': 'Premium Plugin Example', - 'version': PLUGIN_VERSION, - 'status': 'active', - 'subscription': 'active', - 'verification_method': 'unified' - }) diff --git a/premiumPlugin/views_remote.py b/premiumPlugin/views_remote.py deleted file mode 100644 index a4adfaeeb..000000000 --- a/premiumPlugin/views_remote.py +++ /dev/null @@ -1,236 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Premium Plugin Views - Remote Verification Version -This version uses remote server verification (no secrets in plugin) -""" - -from django.shortcuts import render, redirect -from django.http import JsonResponse -from plogical.mailUtilities import mailUtilities -from plogical.httpProc import httpProc -from functools import wraps -import sys -import os -import urllib.request -import urllib.error -import json - -# Remote verification server (YOUR server, not user's server) -REMOTE_VERIFICATION_URL = 'https://api.newstargeted.com/api/verify-patreon-membership' -PLUGIN_NAME = 'premiumPlugin' -PLUGIN_VERSION = '1.0.0' - -def cyberpanel_login_required(view_func): - """ - Custom decorator that checks for CyberPanel session userID - """ - @wraps(view_func) - def _wrapped_view(request, *args, **kwargs): - try: - userID = request.session['userID'] - # User is authenticated via CyberPanel session - return view_func(request, *args, **kwargs) - except KeyError: - # Not logged in, redirect to login - from loginSystem.views import loadLoginPage - return redirect(loadLoginPage) - return _wrapped_view - -def remote_verification_required(view_func): - """ - Decorator that checks Patreon membership via remote server - No secrets stored in plugin - all verification happens on your server - """ - @wraps(view_func) - def _wrapped_view(request, *args, **kwargs): - # First check login - try: - userID = request.session['userID'] - except KeyError: - from loginSystem.views import loadLoginPage - return redirect(loadLoginPage) - - # Get user email - user_email = getattr(request.user, 'email', None) if hasattr(request, 'user') and request.user else None - if not user_email: - # Try to get from session or username - user_email = request.session.get('email', '') or getattr(request.user, 'username', '') - - # Check membership via remote server - verification_result = check_remote_membership(user_email, request.META.get('REMOTE_ADDR', '')) - - if not verification_result.get('has_access', False): - # User doesn't have subscription - show subscription required page - context = { - 'plugin_name': 'Premium Plugin Example', - 'is_paid': True, - 'patreon_tier': verification_result.get('patreon_tier', 'CyberPanel Paid Plugin'), - 'patreon_url': verification_result.get('patreon_url', 'https://www.patreon.com/c/newstargeted/membership'), - 'message': verification_result.get('message', 'Patreon subscription required'), - 'error': verification_result.get('error') - } - proc = httpProc(request, 'premiumPlugin/subscription_required.html', context, 'admin') - return proc.render() - - # User has access - proceed with view - return view_func(request, *args, **kwargs) - - return _wrapped_view - -def check_remote_membership(user_email, user_ip=''): - """ - Check Patreon membership via remote verification server - - Args: - user_email: User's email address - user_ip: User's IP address (for logging/security) - - Returns: - dict: { - 'has_access': bool, - 'patreon_tier': str, - 'patreon_url': str, - 'message': str, - 'error': str or None - } - """ - try: - # Prepare request data - request_data = { - 'user_email': user_email, - 'plugin_name': PLUGIN_NAME, - 'plugin_version': PLUGIN_VERSION, - 'user_ip': user_ip, - 'tier_id': '27789984' # CyberPanel Paid Plugin tier ID - } - - # Make request to remote verification server - req = urllib.request.Request( - REMOTE_VERIFICATION_URL, - data=json.dumps(request_data).encode('utf-8'), - headers={ - 'Content-Type': 'application/json', - 'User-Agent': f'CyberPanel-Plugin/{PLUGIN_VERSION}', - 'X-Plugin-Name': PLUGIN_NAME - } - ) - - # Send request with timeout - try: - with urllib.request.urlopen(req, timeout=10) as response: - response_data = json.loads(response.read().decode('utf-8')) - - if response_data.get('success', False): - return { - 'has_access': response_data.get('has_access', False), - 'patreon_tier': response_data.get('patreon_tier', 'CyberPanel Paid Plugin'), - 'patreon_url': response_data.get('patreon_url', 'https://www.patreon.com/c/newstargeted/membership'), - 'message': response_data.get('message', 'Access granted'), - 'error': None - } - else: - return { - 'has_access': False, - 'patreon_tier': response_data.get('patreon_tier', 'CyberPanel Paid Plugin'), - 'patreon_url': response_data.get('patreon_url', 'https://www.patreon.com/c/newstargeted/membership'), - 'message': response_data.get('message', 'Patreon subscription required'), - 'error': response_data.get('error') - } - except urllib.error.HTTPError as e: - # Server returned error - error_body = e.read().decode('utf-8') if e.fp else 'Unknown error' - return { - 'has_access': False, - 'patreon_tier': 'CyberPanel Paid Plugin', - 'patreon_url': 'https://www.patreon.com/c/newstargeted/membership', - 'message': 'Unable to verify subscription. Please try again later.', - 'error': f'HTTP {e.code}: {error_body}' - } - except urllib.error.URLError as e: - # Network error - return { - 'has_access': False, - 'patreon_tier': 'CyberPanel Paid Plugin', - 'patreon_url': 'https://www.patreon.com/c/newstargeted/membership', - 'message': 'Unable to connect to verification server. Please check your internet connection.', - 'error': str(e.reason) if hasattr(e, 'reason') else str(e) - } - except Exception as e: - # Other errors - return { - 'has_access': False, - 'patreon_tier': 'CyberPanel Paid Plugin', - 'patreon_url': 'https://www.patreon.com/c/newstargeted/membership', - 'message': 'Verification error occurred. Please try again later.', - 'error': str(e) - } - - except Exception as e: - import logging - logging.writeToFile(f"Error in remote membership check: {str(e)}") - return { - 'has_access': False, - 'patreon_tier': 'CyberPanel Paid Plugin', - 'patreon_url': 'https://www.patreon.com/c/newstargeted/membership', - 'message': 'Verification error occurred. Please try again later.', - 'error': str(e) - } - -@cyberpanel_login_required -@remote_verification_required -def main_view(request): - """ - Main view for premium plugin - Only accessible with Patreon subscription (verified remotely) - """ - mailUtilities.checkHome() - - context = { - 'plugin_name': 'Premium Plugin Example', - 'version': PLUGIN_VERSION, - 'description': 'This is an example paid plugin. You have access because you are subscribed to Patreon!', - 'features': [ - 'Premium Feature 1', - 'Premium Feature 2', - 'Premium Feature 3', - 'Advanced Configuration', - 'Priority Support' - ] - } - - proc = httpProc(request, 'premiumPlugin/index.html', context, 'admin') - return proc.render() - -@cyberpanel_login_required -@remote_verification_required -def settings_view(request): - """ - Settings page for premium plugin - Only accessible with Patreon subscription (verified remotely) - """ - mailUtilities.checkHome() - - context = { - 'plugin_name': 'Premium Plugin Example', - 'version': PLUGIN_VERSION, - 'description': 'Configure your premium plugin settings' - } - - proc = httpProc(request, 'premiumPlugin/settings.html', context, 'admin') - return proc.render() - -@cyberpanel_login_required -@remote_verification_required -def api_status_view(request): - """ - API endpoint for plugin status - Only accessible with Patreon subscription (verified remotely) - """ - return JsonResponse({ - 'plugin_name': 'Premium Plugin Example', - 'version': PLUGIN_VERSION, - 'status': 'active', - 'subscription': 'active', - 'description': 'Premium plugin is active and accessible', - 'verification_method': 'remote' - }) diff --git a/testPlugin/OS_COMPATIBILITY.md b/testPlugin/OS_COMPATIBILITY.md deleted file mode 100644 index b01441843..000000000 --- a/testPlugin/OS_COMPATIBILITY.md +++ /dev/null @@ -1,464 +0,0 @@ -# OS Compatibility Guide - CyberPanel Test Plugin - -## 🌐 Supported Operating Systems - -The CyberPanel Test Plugin is designed to work seamlessly across all CyberPanel-supported operating systems with comprehensive multi-OS compatibility. - -### āœ… Currently Supported OS - -| Operating System | Version | Support Status | Python Version | Package Manager | Service Manager | -|------------------|---------|----------------|----------------|-----------------|-----------------| -| **Ubuntu** | 22.04 | āœ… Full Support | 3.10+ | apt-get | systemctl | -| **Ubuntu** | 20.04 | āœ… Full Support | 3.8+ | apt-get | systemctl | -| **Debian** | 13 | āœ… Full Support | 3.11+ | apt-get | systemctl | -| **Debian** | 12 | āœ… Full Support | 3.10+ | apt-get | systemctl | -| **Debian** | 11 | āœ… Full Support | 3.9+ | apt-get | systemctl | -| **AlmaLinux** | 10 | āœ… Full Support | 3.11+ | dnf | systemctl | -| **AlmaLinux** | 9 | āœ… Full Support | 3.9+ | dnf | systemctl | -| **AlmaLinux** | 8 | āœ… Full Support | 3.6+ | dnf/yum | systemctl | -| **RockyLinux** | 9 | āœ… Full Support | 3.9+ | dnf | systemctl | -| **RockyLinux** | 8 | āœ… Full Support | 3.6+ | dnf | systemctl | -| **RHEL** | 9 | āœ… Full Support | 3.9+ | dnf | systemctl | -| **RHEL** | 8 | āœ… Full Support | 3.6+ | dnf | systemctl | -| **CloudLinux** | 8 | āœ… Full Support | 3.6+ | yum | systemctl | -| **CentOS** | 9 | āœ… Full Support | 3.9+ | dnf | systemctl | - -### šŸ”§ Third-Party OS Support - -| Operating System | Compatibility | Notes | -|------------------|---------------|-------| -| **Fedora** | āœ… Compatible | Uses dnf package manager | -| **openEuler** | āš ļø Limited | Community-supported, limited testing | -| **Other RHEL derivatives** | āš ļø Limited | May work with AlmaLinux/RockyLinux packages | - -## šŸš€ Installation Compatibility - -### Automatic OS Detection - -The installation script automatically detects your operating system and configures the plugin accordingly: - -```bash -# The script automatically detects: -# - OS name and version -# - Python executable path -# - Package manager (apt-get, dnf, yum) -# - Service manager (systemctl, service) -# - Web server (apache2, httpd) -``` - -### OS-Specific Configurations - -#### Ubuntu/Debian Systems -```bash -# Package Manager: apt-get -# Python: python3 -# Pip: pip3 -# Service Manager: systemctl -# Web Server: apache2 -# User/Group: cyberpanel:cyberpanel -``` - -#### RHEL-based Systems (AlmaLinux, RockyLinux, RHEL, CentOS) -```bash -# Package Manager: dnf (RHEL 8+) / yum (RHEL 7) -# Python: python3 -# Pip: pip3 -# Service Manager: systemctl -# Web Server: httpd -# User/Group: cyberpanel:cyberpanel -``` - -#### CloudLinux -```bash -# Package Manager: yum -# Python: python3 -# Pip: pip3 -# Service Manager: systemctl -# Web Server: httpd -# User/Group: cyberpanel:cyberpanel -``` - -## šŸ Python Compatibility - -### Supported Python Versions - -| Python Version | Ubuntu 22.04 | Ubuntu 20.04 | AlmaLinux 9 | AlmaLinux 8 | RockyLinux 9 | RockyLinux 8 | RHEL 9 | RHEL 8 | CloudLinux 8 | -|----------------|--------------|--------------|-------------|-------------|--------------|--------------|-------|-------|--------------| -| **3.6** | āŒ | āŒ | āŒ | āœ… | āŒ | āœ… | āŒ | āœ… | āœ… | -| **3.7** | āŒ | āŒ | āŒ | āœ… | āŒ | āœ… | āŒ | āœ… | āœ… | -| **3.8** | āŒ | āœ… | āŒ | āœ… | āŒ | āœ… | āŒ | āœ… | āœ… | -| **3.9** | āœ… | āœ… | āœ… | āœ… | āœ… | āœ… | āœ… | āœ… | āœ… | -| **3.10** | āœ… | āœ… | āœ… | āœ… | āœ… | āœ… | āœ… | āœ… | āœ… | -| **3.11** | āœ… | āŒ | āœ… | āœ… | āœ… | āœ… | āœ… | āœ… | āœ… | -| **3.12** | āœ… | āŒ | āœ… | āœ… | āœ… | āœ… | āœ… | āœ… | āœ… | - -### Python Path Detection - -The plugin automatically detects the correct Python executable: - -```python -# Detection order: -1. python3.12 -2. python3.11 -3. python3.10 -4. python3.9 -5. python3.8 -6. python3.7 -7. python3.6 -8. python3 -9. python (fallback) -``` - -## šŸ“¦ Package Manager Compatibility - -### Ubuntu/Debian (apt-get) -```bash -# Required packages -apt-get update -apt-get install -y python3 python3-pip python3-venv git curl -apt-get install -y build-essential python3-dev - -# Python packages -pip3 install Django>=2.2,<4.0 django-cors-headers Pillow requests psutil -``` - -### RHEL-based (dnf/yum) -```bash -# RHEL 8+ (dnf) -dnf install -y python3 python3-pip python3-devel git curl -dnf install -y gcc gcc-c++ make - -# RHEL 7 (yum) -yum install -y python3 python3-pip python3-devel git curl -yum install -y gcc gcc-c++ make - -# Python packages -pip3 install Django>=2.2,<4.0 django-cors-headers Pillow requests psutil -``` - -### CloudLinux (yum) -```bash -# Required packages -yum install -y python3 python3-pip python3-devel git curl -yum install -y gcc gcc-c++ make - -# Python packages -pip3 install Django>=2.2,<4.0 django-cors-headers Pillow requests psutil -``` - -## šŸ”§ Service Management Compatibility - -### systemd (All supported OS) -```bash -# Service management commands -systemctl start lscpd -systemctl restart lscpd -systemctl status lscpd -systemctl enable lscpd - -# Web server management -systemctl start apache2 # Ubuntu/Debian -systemctl start httpd # RHEL-based -systemctl restart apache2 # Ubuntu/Debian -systemctl restart httpd # RHEL-based -``` - -### Legacy init.d (Fallback) -```bash -# Service management commands -service lscpd start -service lscpd restart -service lscpd status - -# Web server management -service apache2 start # Ubuntu/Debian -service httpd start # RHEL-based -``` - -## 🌐 Web Server Compatibility - -### Apache2 (Ubuntu/Debian) -```bash -# Configuration paths -/etc/apache2/apache2.conf -/etc/apache2/sites-available/ -/etc/apache2/sites-enabled/ - -# Service management -systemctl start apache2 -systemctl restart apache2 -systemctl status apache2 -``` - -### HTTPD (RHEL-based) -```bash -# Configuration paths -/etc/httpd/conf/httpd.conf -/etc/httpd/conf.d/ - -# Service management -systemctl start httpd -systemctl restart httpd -systemctl status httpd -``` - -## šŸ” Security Compatibility - -### SELinux (RHEL-based systems) -```bash -# Check SELinux status -sestatus - -# Set proper context for plugin files -setsebool -P httpd_can_network_connect 1 -chcon -R -t httpd_exec_t /usr/local/CyberCP/testPlugin/ -``` - -### AppArmor (Ubuntu/Debian) -```bash -# Check AppArmor status -aa-status - -# Allow Apache to access plugin files -aa-complain apache2 -``` - -### Firewall Compatibility -```bash -# Ubuntu/Debian (ufw) -ufw allow 8090/tcp -ufw allow 80/tcp -ufw allow 443/tcp - -# RHEL-based (firewalld) -firewall-cmd --permanent --add-port=8090/tcp -firewall-cmd --permanent --add-port=80/tcp -firewall-cmd --permanent --add-port=443/tcp -firewall-cmd --reload - -# iptables (legacy) -iptables -A INPUT -p tcp --dport 8090 -j ACCEPT -iptables -A INPUT -p tcp --dport 80 -j ACCEPT -iptables -A INPUT -p tcp --dport 443 -j ACCEPT -``` - -## 🧪 Testing Compatibility - -### Run Compatibility Test -```bash -# Navigate to plugin directory -cd /usr/local/CyberCP/testPlugin - -# Run compatibility test -python3 test_os_compatibility.py - -# Or make it executable and run -chmod +x test_os_compatibility.py -./test_os_compatibility.py -``` - -### Test Results -The compatibility test checks: -- āœ… OS detection and version -- āœ… Python installation and version -- āœ… Package manager availability -- āœ… Service manager functionality -- āœ… Web server configuration -- āœ… File permissions and ownership -- āœ… Network connectivity -- āœ… CyberPanel integration - -### Sample Output -``` -šŸ” Testing OS Compatibility for CyberPanel Test Plugin -============================================================ - -šŸ“‹ Testing OS Detection... - āœ… OS: ubuntu 22.04 (x86_64) - āœ… Supported: True - -šŸ Testing Python Detection... - āœ… Python: Python 3.10.12 - āœ… Path: /usr/bin/python3 - āœ… Pip: /usr/bin/pip3 - āœ… Compatible: True - -šŸ“¦ Testing Package Manager Detection... - āœ… Package Manager: apt-get - āœ… Available: True - -šŸ”§ Testing Service Manager Detection... - āœ… Service Manager: systemctl - āœ… Web Server: apache2 - āœ… Available: True - -🌐 Testing Web Server Detection... - āœ… Web Server: apache2 - āœ… Installed: True - -šŸ” Testing File Permissions... - āœ… Plugin Directory: /home/cyberpanel/plugins - āœ… CyberPanel Directory: /usr/local/CyberCP - -šŸŒ Testing Network Connectivity... - āœ… GitHub: True - āœ… Internet: True - -⚔ Testing CyberPanel Integration... - āœ… CyberPanel Installed: True - āœ… Settings File: True - āœ… URLs File: True - āœ… LSCPD Service: True - -============================================================ -šŸ“Š COMPATIBILITY TEST RESULTS -============================================================ -Total Tests: 8 -āœ… Passed: 8 -āš ļø Warnings: 0 -āŒ Failed: 0 - -šŸŽ‰ All tests passed! The plugin is compatible with this OS. -``` - -## 🚨 Troubleshooting - -### Common Issues by OS - -#### Ubuntu/Debian Issues -```bash -# Python not found -sudo apt-get update -sudo apt-get install -y python3 python3-pip - -# Permission denied -sudo chown -R cyberpanel:cyberpanel /home/cyberpanel/plugins -sudo chown -R cyberpanel:cyberpanel /usr/local/CyberCP/testPlugin - -# Service not starting -sudo systemctl daemon-reload -sudo systemctl restart lscpd -``` - -#### RHEL-based Issues -```bash -# Python not found -sudo dnf install -y python3 python3-pip -# or -sudo yum install -y python3 python3-pip - -# SELinux issues -sudo setsebool -P httpd_can_network_connect 1 -sudo chcon -R -t httpd_exec_t /usr/local/CyberCP/testPlugin/ - -# Permission denied -sudo chown -R cyberpanel:cyberpanel /home/cyberpanel/plugins -sudo chown -R cyberpanel:cyberpanel /usr/local/CyberCP/testPlugin -``` - -#### CloudLinux Issues -```bash -# Python not found -sudo yum install -y python3 python3-pip - -# CageFS issues -cagefsctl --enable cyberpanel -cagefsctl --update - -# Permission denied -sudo chown -R cyberpanel:cyberpanel /home/cyberpanel/plugins -sudo chown -R cyberpanel:cyberpanel /usr/local/CyberCP/testPlugin -``` - -### Debug Commands -```bash -# Check OS information -cat /etc/os-release -uname -a - -# Check Python installation -python3 --version -which python3 -which pip3 - -# Check services -systemctl status lscpd -systemctl status apache2 # Ubuntu/Debian -systemctl status httpd # RHEL-based - -# Check file permissions -ls -la /home/cyberpanel/plugins/ -ls -la /usr/local/CyberCP/testPlugin/ - -# Check CyberPanel logs -tail -f /home/cyberpanel/logs/cyberpanel.log -tail -f /home/cyberpanel/logs/django.log -``` - -## šŸ“‹ Installation Checklist - -### Pre-Installation -- [ ] Verify OS is supported -- [ ] Check Python 3.6+ is installed -- [ ] Ensure CyberPanel is installed and running -- [ ] Verify internet connectivity -- [ ] Check available disk space (minimum 100MB) - -### Installation -- [ ] Download installation script -- [ ] Run as root user -- [ ] Monitor installation output -- [ ] Verify plugin files are created -- [ ] Check Django settings are updated -- [ ] Confirm URL configuration is added - -### Post-Installation -- [ ] Test plugin access via web interface -- [ ] Verify all features work correctly -- [ ] Check security settings -- [ ] Run compatibility test -- [ ] Review installation logs - -## šŸ”„ Updates and Maintenance - -### Updating the Plugin -```bash -# Navigate to plugin directory -cd /usr/local/CyberCP/testPlugin - -# Pull latest changes -git pull origin main - -# Restart services -sudo systemctl restart lscpd -sudo systemctl restart apache2 # Ubuntu/Debian -sudo systemctl restart httpd # RHEL-based -``` - -### Uninstalling the Plugin -```bash -# Run uninstall script -sudo ./install.sh --uninstall - -# Or manually remove -sudo rm -rf /usr/local/CyberCP/testPlugin -sudo rm -f /home/cyberpanel/plugins/testPlugin -``` - -## šŸ“ž Support - -### OS-Specific Support -- **Ubuntu/Debian**: Check Ubuntu/Debian documentation -- **RHEL-based**: Check Red Hat documentation -- **CloudLinux**: Check CloudLinux documentation - -### Plugin Support -- **GitHub Issues**: https://github.com/cyberpanel/testPlugin/issues -- **CyberPanel Forums**: https://forums.cyberpanel.net/ -- **Documentation**: https://cyberpanel.net/docs/ - ---- - -**Last Updated**: September 2025 -**Compatibility Version**: 1.0.0 -**Next Review**: March 2026 diff --git a/testPlugin/SECURITY.md b/testPlugin/SECURITY.md deleted file mode 100644 index ea6cee1b0..000000000 --- a/testPlugin/SECURITY.md +++ /dev/null @@ -1,247 +0,0 @@ -# Security Implementation - CyberPanel Test Plugin - -## šŸ”’ Security Overview - -The CyberPanel Test Plugin has been designed with **enterprise-grade security** as the top priority. This document outlines all security measures implemented to protect against common web application vulnerabilities and attacks. - -## šŸ›”ļø Security Features Implemented - -### 1. Authentication & Authorization -- **Admin-only access** required for all plugin functions -- **User session validation** on every request -- **Privilege escalation protection** -- **Role-based access control** (RBAC) - -### 2. Rate Limiting & Brute Force Protection -- **50 requests per 5-minute window** per user -- **10 test button clicks per minute** limit -- **Automatic lockout** after 5 failed attempts -- **15-minute lockout duration** -- **Progressive punishment system** - -### 3. CSRF Protection -- **HMAC-based CSRF token validation** -- **Token expiration** after 1 hour -- **User-specific token generation** -- **Secure token verification** - -### 4. Input Validation & Sanitization -- **Regex-based input validation** -- **XSS attack prevention** -- **SQL injection prevention** -- **Path traversal protection** -- **Maximum input length limits** (1000 characters) -- **Character whitelisting** - -### 5. Security Monitoring & Logging -- **All security events logged** with IP and user agent -- **Failed attempt tracking** and alerting -- **Suspicious activity detection** -- **Real-time security event monitoring** -- **Comprehensive audit trail** - -### 6. HTTP Security Headers -- **X-Frame-Options: DENY** (clickjacking protection) -- **X-Content-Type-Options: nosniff** -- **X-XSS-Protection: 1; mode=block** -- **Content-Security-Policy (CSP)** -- **Strict-Transport-Security (HSTS)** -- **Referrer-Policy: strict-origin-when-cross-origin** -- **Permissions-Policy** - -### 7. Data Isolation & Privacy -- **User-specific data isolation** -- **Logs restricted** to user's own activities -- **Settings isolated** per user -- **No cross-user data access** - -## šŸ” Security Middleware - -The plugin includes a comprehensive security middleware that performs: - -### Request Analysis -- **Suspicious pattern detection** -- **SQL injection attempt detection** -- **XSS attempt detection** -- **Path traversal attempt detection** -- **Malicious payload identification** - -### Response Protection -- **Security headers injection** -- **Content Security Policy enforcement** -- **Clickjacking protection** -- **MIME type sniffing prevention** - -## 🚨 Attack Prevention - -### OWASP Top 10 Protection -1. **A01: Broken Access Control** āœ… Protected -2. **A02: Cryptographic Failures** āœ… Protected -3. **A03: Injection** āœ… Protected -4. **A04: Insecure Design** āœ… Protected -5. **A05: Security Misconfiguration** āœ… Protected -6. **A06: Vulnerable Components** āœ… Protected -7. **A07: Authentication Failures** āœ… Protected -8. **A08: Software Integrity Failures** āœ… Protected -9. **A09: Logging Failures** āœ… Protected -10. **A10: Server-Side Request Forgery** āœ… Protected - -### Specific Attack Vectors Blocked -- **SQL Injection** - Regex pattern matching + parameterized queries -- **Cross-Site Scripting (XSS)** - Input sanitization + CSP headers -- **Cross-Site Request Forgery (CSRF)** - HMAC token validation -- **Brute Force Attacks** - Rate limiting + account lockout -- **Path Traversal** - Pattern detection + input validation -- **Clickjacking** - X-Frame-Options header -- **Session Hijacking** - Secure session management -- **Privilege Escalation** - Role-based access control - -## šŸ“Š Security Metrics - -- **15+ Security Features** implemented -- **99% Attack Prevention** rate -- **24/7 Security Monitoring** active -- **0 Known Vulnerabilities** in current version -- **Enterprise-grade** security standards - -## šŸ”§ Security Configuration - -### Rate Limiting Settings -```python -RATE_LIMIT_WINDOW = 300 # 5 minutes -MAX_REQUESTS_PER_WINDOW = 50 -MAX_FAILED_ATTEMPTS = 5 -LOCKOUT_DURATION = 900 # 15 minutes -``` - -### Input Validation Settings -```python -SAFE_STRING_PATTERN = re.compile(r'^[a-zA-Z0-9\s\-_.,!?@#$%^&*()+=\[\]{}|\\:";\'<>?/~`]*$') -MAX_MESSAGE_LENGTH = 1000 -``` - -### CSRF Token Settings -```python -TOKEN_EXPIRATION = 3600 # 1 hour -HMAC_ALGORITHM = 'sha256' -``` - -## šŸš€ Security Best Practices - -### For Developers -1. **Always validate input** before processing -2. **Use parameterized queries** for database operations -3. **Implement proper error handling** without information disclosure -4. **Log security events** for monitoring -5. **Keep dependencies updated** -6. **Use HTTPS** in production -7. **Implement proper session management** - -### For Administrators -1. **Keep CyberPanel updated** -2. **Use strong, unique passwords** -3. **Enable 2FA** on admin accounts -4. **Regularly review security logs** -5. **Monitor failed login attempts** -6. **Use HTTPS** in production environments -7. **Regular security audits** - -## šŸ” Security Monitoring - -### Logged Events -- **Authentication attempts** (successful and failed) -- **Authorization failures** -- **Rate limit violations** -- **Suspicious request patterns** -- **Input validation failures** -- **Security policy violations** -- **System errors and exceptions** - -### Monitoring Dashboard -Access the security information page at: `/testPlugin/security/` - -## šŸ› ļø Security Testing - -### Automated Tests -- **Unit tests** for all security functions -- **Integration tests** for security middleware -- **Penetration testing** scenarios -- **Vulnerability scanning** - -### Manual Testing -- **OWASP ZAP** security testing -- **Burp Suite** penetration testing -- **Manual security review** -- **Code security audit** - -## šŸ“‹ Security Checklist - -- [x] Authentication implemented -- [x] Authorization implemented -- [x] CSRF protection enabled -- [x] Rate limiting configured -- [x] Input validation active -- [x] XSS protection enabled -- [x] SQL injection protection -- [x] Security headers configured -- [x] Logging implemented -- [x] Error handling secure -- [x] Session management secure -- [x] Data isolation implemented -- [x] Security monitoring active - -## 🚨 Incident Response - -### Security Incident Procedure -1. **Immediate Response** - - Block suspicious IP addresses - - Review security logs - - Assess impact - -2. **Investigation** - - Analyze attack vectors - - Identify compromised accounts - - Document findings - -3. **Recovery** - - Patch vulnerabilities - - Reset compromised accounts - - Update security measures - -4. **Post-Incident** - - Review security policies - - Update monitoring rules - - Conduct security training - -## šŸ“ž Security Contact - -For security-related issues or vulnerability reports: - -- **Email**: security@cyberpanel.net -- **GitHub**: Create a private security issue -- **Response Time**: Within 24-48 hours - -## šŸ”„ Security Updates - -Security is an ongoing process. Regular updates include: - -- **Security patches** for vulnerabilities -- **Enhanced monitoring** capabilities -- **Improved detection** algorithms -- **Updated security policies** -- **New protection mechanisms** - -## šŸ“š Additional Resources - -- [OWASP Top 10](https://owasp.org/www-project-top-ten/) -- [Django Security](https://docs.djangoproject.com/en/stable/topics/security/) -- [CyberPanel Security](https://cyberpanel.net/docs/) -- [Web Application Security](https://cheatsheetseries.owasp.org/) - ---- - -**Security Note**: This plugin implements enterprise-grade security measures. However, security is an ongoing process. Regular updates and monitoring are essential to maintain the highest security standards. - -**Last Updated**: December 2024 -**Security Version**: 1.0.0 -**Next Review**: March 2025 diff --git a/testPlugin/__init__.py b/testPlugin/__init__.py deleted file mode 100644 index 695a722b6..000000000 --- a/testPlugin/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# -*- coding: utf-8 -*- -default_app_config = 'testPlugin.apps.TestPluginConfig' diff --git a/testPlugin/admin.py b/testPlugin/admin.py deleted file mode 100644 index cd858aeea..000000000 --- a/testPlugin/admin.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -from django.contrib import admin -from .models import TestPluginSettings, TestPluginLog - - -@admin.register(TestPluginSettings) -class TestPluginSettingsAdmin(admin.ModelAdmin): - list_display = ['user', 'plugin_enabled', 'test_count', 'last_test_time'] - list_filter = ['plugin_enabled', 'last_test_time'] - search_fields = ['user__username', 'custom_message'] - readonly_fields = ['last_test_time'] - - -@admin.register(TestPluginLog) -class TestPluginLogAdmin(admin.ModelAdmin): - list_display = ['timestamp', 'action', 'message', 'user'] - list_filter = ['action', 'timestamp', 'user'] - search_fields = ['action', 'message', 'user__username'] - readonly_fields = ['timestamp'] - date_hierarchy = 'timestamp' diff --git a/testPlugin/apps.py b/testPlugin/apps.py deleted file mode 100644 index ae29de970..000000000 --- a/testPlugin/apps.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -from django.apps import AppConfig - - -class TestPluginConfig(AppConfig): - name = 'testPlugin' - verbose_name = 'Test Plugin' - - def ready(self): - # Import signal handlers - import testPlugin.signals diff --git a/testPlugin/install.sh b/testPlugin/install.sh deleted file mode 100644 index b87eb2140..000000000 --- a/testPlugin/install.sh +++ /dev/null @@ -1,580 +0,0 @@ -#!/bin/bash - -# Test Plugin Installation Script for CyberPanel -# Multi-OS Compatible Installation Script -# Supports: Ubuntu, Debian, AlmaLinux, RockyLinux, RHEL, CloudLinux, CentOS - -set -e - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Configuration -PLUGIN_NAME="testPlugin" -PLUGIN_DIR="/home/cyberpanel/plugins" -CYBERPANEL_DIR="/usr/local/CyberCP" -GITHUB_REPO="https://github.com/cyberpanel/testPlugin.git" -TEMP_DIR="/tmp/cyberpanel_plugin_install" - -# OS Detection Variables -OS_NAME="" -OS_VERSION="" -OS_ARCH="" -PYTHON_CMD="" -PIP_CMD="" -SERVICE_CMD="" -WEB_SERVER="" - -# Function to print colored output -print_status() { - echo -e "${BLUE}[INFO]${NC} $1" -} - -print_success() { - echo -e "${GREEN}[SUCCESS]${NC} $1" -} - -print_warning() { - echo -e "${YELLOW}[WARNING]${NC} $1" -} - -print_error() { - echo -e "${RED}[ERROR]${NC} $1" -} - -# Function to detect operating system -detect_os() { - print_status "Detecting operating system..." - - if [ -f /etc/os-release ]; then - . /etc/os-release - OS_NAME="$ID" - OS_VERSION="$VERSION_ID" - elif [ -f /etc/redhat-release ]; then - OS_NAME="rhel" - OS_VERSION=$(cat /etc/redhat-release | grep -oE '[0-9]+\.[0-9]+' | head -1) - elif [ -f /etc/debian_version ]; then - OS_NAME="debian" - OS_VERSION=$(cat /etc/debian_version) - else - print_error "Unable to detect operating system" - exit 1 - fi - - # Detect architecture - OS_ARCH=$(uname -m) - - print_success "Detected: $OS_NAME $OS_VERSION ($OS_ARCH)" - - # Set OS-specific configurations - configure_os_specific -} - -# Function to configure OS-specific settings -configure_os_specific() { - case "$OS_NAME" in - "ubuntu"|"debian") - PYTHON_CMD="python3" - PIP_CMD="pip3" - SERVICE_CMD="systemctl" - WEB_SERVER="apache2" - ;; - "almalinux"|"rocky"|"rhel"|"centos"|"cloudlinux") - PYTHON_CMD="python3" - PIP_CMD="pip3" - SERVICE_CMD="systemctl" - WEB_SERVER="httpd" - ;; - *) - print_warning "Unknown OS: $OS_NAME. Using default configurations." - PYTHON_CMD="python3" - PIP_CMD="pip3" - SERVICE_CMD="systemctl" - WEB_SERVER="httpd" - ;; - esac - - print_status "Using Python: $PYTHON_CMD" - print_status "Using Pip: $PIP_CMD" - print_status "Using Service Manager: $SERVICE_CMD" - print_status "Using Web Server: $WEB_SERVER" -} - -# Function to check if running as root -check_root() { - if [[ $EUID -ne 0 ]]; then - print_error "This script must be run as root" - exit 1 - fi -} - -# Function to check if CyberPanel is installed -check_cyberpanel() { - if [ ! -d "$CYBERPANEL_DIR" ]; then - print_error "CyberPanel is not installed at $CYBERPANEL_DIR" - print_error "Please install CyberPanel first: https://cyberpanel.net/docs/" - exit 1 - fi - - # Check if CyberPanel is running - if ! $SERVICE_CMD is-active --quiet lscpd; then - print_warning "CyberPanel service (lscpd) is not running. Starting it..." - $SERVICE_CMD start lscpd - fi - - print_success "CyberPanel installation verified" -} - -# Function to check Python installation -check_python() { - print_status "Checking Python installation..." - - if ! command -v $PYTHON_CMD &> /dev/null; then - print_error "Python3 is not installed. Installing..." - install_python - fi - - # Check Python version (require 3.6+) - PYTHON_VERSION=$($PYTHON_CMD -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')") - PYTHON_MAJOR=$(echo $PYTHON_VERSION | cut -d. -f1) - PYTHON_MINOR=$(echo $PYTHON_VERSION | cut -d. -f2) - - if [ "$PYTHON_MAJOR" -lt 3 ] || ([ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 6 ]); then - print_error "Python 3.6+ is required. Found: $PYTHON_VERSION" - exit 1 - fi - - print_success "Python $PYTHON_VERSION is available" -} - -# Function to install Python if needed -install_python() { - case "$OS_NAME" in - "ubuntu"|"debian") - apt-get update - apt-get install -y python3 python3-pip python3-venv - ;; - "almalinux"|"rocky"|"rhel"|"centos"|"cloudlinux") - if command -v dnf &> /dev/null; then - dnf install -y python3 python3-pip - elif command -v yum &> /dev/null; then - yum install -y python3 python3-pip - else - print_error "No package manager found (dnf/yum)" - exit 1 - fi - ;; - esac -} - -# Function to check pip installation -check_pip() { - print_status "Checking pip installation..." - - if ! command -v $PIP_CMD &> /dev/null; then - print_error "pip3 is not installed. Installing..." - install_pip - fi - - print_success "pip3 is available" -} - -# Function to install pip if needed -install_pip() { - case "$OS_NAME" in - "ubuntu"|"debian") - apt-get install -y python3-pip - ;; - "almalinux"|"rocky"|"rhel"|"centos"|"cloudlinux") - if command -v dnf &> /dev/null; then - dnf install -y python3-pip - elif command -v yum &> /dev/null; then - yum install -y python3-pip - fi - ;; - esac -} - -# Function to check required packages -check_packages() { - print_status "Checking required packages..." - - # Check for git - if ! command -v git &> /dev/null; then - print_error "git is not installed. Installing..." - install_git - fi - - # Check for curl - if ! command -v curl &> /dev/null; then - print_error "curl is not installed. Installing..." - install_curl - fi - - print_success "All required packages are available" -} - -# Function to install git -install_git() { - case "$OS_NAME" in - "ubuntu"|"debian") - apt-get update - apt-get install -y git - ;; - "almalinux"|"rocky"|"rhel"|"centos"|"cloudlinux") - if command -v dnf &> /dev/null; then - dnf install -y git - elif command -v yum &> /dev/null; then - yum install -y git - fi - ;; - esac -} - -# Function to install curl -install_curl() { - case "$OS_NAME" in - "ubuntu"|"debian") - apt-get update - apt-get install -y curl - ;; - "almalinux"|"rocky"|"rhel"|"centos"|"cloudlinux") - if command -v dnf &> /dev/null; then - dnf install -y curl - elif command -v yum &> /dev/null; then - yum install -y curl - fi - ;; - esac -} - -# Function to create plugin directory -create_plugin_directory() { - print_status "Creating plugin directory structure..." - - # Create main plugin directory - mkdir -p "$PLUGIN_DIR" - - # Create CyberPanel plugin directory - mkdir -p "$CYBERPANEL_DIR/$PLUGIN_NAME" - - # Set proper permissions - chown -R cyberpanel:cyberpanel "$PLUGIN_DIR" 2>/dev/null || chown -R root:root "$PLUGIN_DIR" - chmod -R 755 "$PLUGIN_DIR" - - chown -R cyberpanel:cyberpanel "$CYBERPANEL_DIR/$PLUGIN_NAME" 2>/dev/null || chown -R root:root "$CYBERPANEL_DIR/$PLUGIN_NAME" - chmod -R 755 "$CYBERPANEL_DIR/$PLUGIN_NAME" - - print_success "Plugin directory structure created" -} - -# Function to download plugin -download_plugin() { - print_status "Downloading plugin from GitHub..." - - # Clean up temp directory - rm -rf "$TEMP_DIR" - mkdir -p "$TEMP_DIR" - - # Clone the repository - if ! git clone "$GITHUB_REPO" "$TEMP_DIR"; then - print_error "Failed to download plugin from GitHub" - print_error "Please check your internet connection and try again" - exit 1 - fi - - print_success "Plugin downloaded successfully" -} - -# Function to install plugin files -install_plugin_files() { - print_status "Installing plugin files..." - - # Copy plugin files - cp -r "$TEMP_DIR"/* "$CYBERPANEL_DIR/$PLUGIN_NAME/" - - # Create symlink - ln -sf "$CYBERPANEL_DIR/$PLUGIN_NAME" "$PLUGIN_DIR/$PLUGIN_NAME" - - # Set proper ownership and permissions - chown -R cyberpanel:cyberpanel "$CYBERPANEL_DIR/$PLUGIN_NAME" 2>/dev/null || chown -R root:root "$CYBERPANEL_DIR/$PLUGIN_NAME" - chmod -R 755 "$CYBERPANEL_DIR/$PLUGIN_NAME" - - # Make scripts executable - chmod +x "$CYBERPANEL_DIR/$PLUGIN_NAME/install.sh" 2>/dev/null || true - - print_success "Plugin files installed" -} - -# Function to update Django settings -update_django_settings() { - print_status "Updating Django settings..." - - SETTINGS_FILE="$CYBERPANEL_DIR/cyberpanel/settings.py" - - # Check if plugin is already in INSTALLED_APPS - if ! grep -q "'$PLUGIN_NAME'" "$SETTINGS_FILE"; then - # Add plugin to INSTALLED_APPS - sed -i "/INSTALLED_APPS = \[/a\ '$PLUGIN_NAME'," "$SETTINGS_FILE" - print_success "Added $PLUGIN_NAME to INSTALLED_APPS" - else - print_warning "$PLUGIN_NAME already in INSTALLED_APPS" - fi -} - -# Function to update URL configuration -update_urls() { - print_status "Updating URL configuration..." - - URLS_FILE="$CYBERPANEL_DIR/cyberpanel/urls.py" - - # Check if plugin URLs are already included - if ! grep -q "path(\"$PLUGIN_NAME/\"" "$URLS_FILE"; then - # Add plugin URLs - sed -i "/urlpatterns = \[/a\ path(\"$PLUGIN_NAME/\", include(\"$PLUGIN_NAME.urls\"))," "$URLS_FILE" - print_success "Added $PLUGIN_NAME URLs" - else - print_warning "$PLUGIN_NAME URLs already configured" - fi -} - -# Function to run database migrations -run_migrations() { - print_status "Running database migrations..." - - cd "$CYBERPANEL_DIR" - - # Create migrations - if ! $PYTHON_CMD manage.py makemigrations $PLUGIN_NAME; then - print_warning "No migrations to create for $PLUGIN_NAME" - fi - - # Apply migrations - if ! $PYTHON_CMD manage.py migrate $PLUGIN_NAME; then - print_warning "No migrations to apply for $PLUGIN_NAME" - fi - - print_success "Database migrations completed" -} - -# Function to collect static files -collect_static() { - print_status "Collecting static files..." - - cd "$CYBERPANEL_DIR" - - if ! $PYTHON_CMD manage.py collectstatic --noinput; then - print_warning "Static file collection failed, but continuing..." - else - print_success "Static files collected" - fi -} - -# Function to restart services -restart_services() { - print_status "Restarting CyberPanel services..." - - # Restart lscpd - if $SERVICE_CMD is-active --quiet lscpd; then - $SERVICE_CMD restart lscpd - print_success "lscpd service restarted" - else - print_warning "lscpd service not running" - fi - - # Restart web server - if $SERVICE_CMD is-active --quiet $WEB_SERVER; then - $SERVICE_CMD restart $WEB_SERVER - print_success "$WEB_SERVER service restarted" - else - print_warning "$WEB_SERVER service not running" - fi - - # Additional service restart for different OS - case "$OS_NAME" in - "ubuntu"|"debian") - if $SERVICE_CMD is-active --quiet cyberpanel; then - $SERVICE_CMD restart cyberpanel - print_success "cyberpanel service restarted" - fi - ;; - "almalinux"|"rocky"|"rhel"|"centos"|"cloudlinux") - if $SERVICE_CMD is-active --quiet cyberpanel; then - $SERVICE_CMD restart cyberpanel - print_success "cyberpanel service restarted" - fi - ;; - esac -} - -# Function to verify installation -verify_installation() { - print_status "Verifying installation..." - - # Check if plugin directory exists - if [ ! -d "$CYBERPANEL_DIR/$PLUGIN_NAME" ]; then - print_error "Plugin directory not found" - return 1 - fi - - # Check if symlink exists - if [ ! -L "$PLUGIN_DIR/$PLUGIN_NAME" ]; then - print_error "Plugin symlink not found" - return 1 - fi - - # Check if meta.xml exists - if [ ! -f "$CYBERPANEL_DIR/$PLUGIN_NAME/meta.xml" ]; then - print_error "Plugin meta.xml not found" - return 1 - fi - - print_success "Installation verified successfully" - return 0 -} - -# Function to display installation summary -display_summary() { - echo "" - echo "==========================================" - print_success "Test Plugin Installation Complete!" - echo "==========================================" - echo "Plugin Name: $PLUGIN_NAME" - echo "Installation Directory: $CYBERPANEL_DIR/$PLUGIN_NAME" - echo "Plugin Directory: $PLUGIN_DIR/$PLUGIN_NAME" - echo "Access URL: https://your-domain:8090/testPlugin/" - echo "Operating System: $OS_NAME $OS_VERSION ($OS_ARCH)" - echo "Python Version: $($PYTHON_CMD --version)" - echo "" - echo "Features Installed:" - echo "āœ“ Enable/Disable Toggle" - echo "āœ“ Test Button with Popup Messages" - echo "āœ“ Settings Page" - echo "āœ“ Activity Logs" - echo "āœ“ Inline Integration" - echo "āœ“ Complete Documentation" - echo "āœ“ Official CyberPanel Guide" - echo "āœ“ Advanced Development Guide" - echo "āœ“ Enterprise-Grade Security" - echo "āœ“ Brute Force Protection" - echo "āœ“ CSRF Protection" - echo "āœ“ XSS Prevention" - echo "āœ“ SQL Injection Protection" - echo "āœ“ Rate Limiting" - echo "āœ“ Security Monitoring" - echo "āœ“ Security Information Page" - echo "āœ“ Multi-OS Compatibility" - echo "" - echo "Supported Operating Systems:" - echo "āœ“ Ubuntu 22.04, 20.04" - echo "āœ“ Debian (compatible)" - echo "āœ“ AlmaLinux 8, 9, 10" - echo "āœ“ RockyLinux 8, 9" - echo "āœ“ RHEL 8, 9" - echo "āœ“ CloudLinux 8" - echo "āœ“ CentOS 9" - echo "" - echo "To uninstall, run: $0 --uninstall" - echo "==========================================" -} - -# Function to uninstall plugin -uninstall_plugin() { - print_status "Uninstalling $PLUGIN_NAME..." - - # Remove plugin files - rm -rf "$CYBERPANEL_DIR/$PLUGIN_NAME" - rm -f "$PLUGIN_DIR/$PLUGIN_NAME" - - # Remove from Django settings - SETTINGS_FILE="$CYBERPANEL_DIR/cyberpanel/settings.py" - if [ -f "$SETTINGS_FILE" ]; then - sed -i "/'$PLUGIN_NAME',/d" "$SETTINGS_FILE" - print_success "Removed $PLUGIN_NAME from INSTALLED_APPS" - fi - - # Remove from URLs - URLS_FILE="$CYBERPANEL_DIR/cyberpanel/urls.py" - if [ -f "$URLS_FILE" ]; then - sed -i "/path(\"$PLUGIN_NAME\/\"/d" "$URLS_FILE" - print_success "Removed $PLUGIN_NAME URLs" - fi - - # Restart services - restart_services - - print_success "Plugin uninstalled successfully" -} - -# Main installation function -install_plugin() { - print_status "Starting Test Plugin installation..." - - # Detect OS - detect_os - - # Check requirements - check_root - check_cyberpanel - check_python - check_pip - check_packages - - # Install plugin - create_plugin_directory - download_plugin - install_plugin_files - update_django_settings - update_urls - run_migrations - collect_static - restart_services - - # Verify installation - if verify_installation; then - display_summary - else - print_error "Installation verification failed" - exit 1 - fi -} - -# Main script logic -main() { - case "${1:-}" in - "--uninstall") - check_root - uninstall_plugin - ;; - "--help"|"-h") - echo "Usage: $0 [OPTIONS]" - echo "Options:" - echo " --uninstall Uninstall the plugin" - echo " --help, -h Show this help message" - echo "" - echo "Supported Operating Systems:" - echo " Ubuntu 22.04, 20.04" - echo " Debian (compatible)" - echo " AlmaLinux 8, 9, 10" - echo " RockyLinux 8, 9" - echo " RHEL 8, 9" - echo " CloudLinux 8" - echo " CentOS 9" - ;; - "") - install_plugin - ;; - *) - print_error "Unknown option: $1" - echo "Use --help for usage information" - exit 1 - ;; - esac -} - -# Run main function -main "$@" \ No newline at end of file diff --git a/testPlugin/meta.xml b/testPlugin/meta.xml deleted file mode 100644 index 76993172a..000000000 --- a/testPlugin/meta.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - Test Plugin - Utility - 1.0.0 - A comprehensive test plugin for CyberPanel with enable/disable functionality, test button, popup messages, and inline integration - usmannasir - https://github.com/cyberpanel/testPlugin - MIT - - 3.6+ - 2.2+ - - - true - false - - - true - true - true - true - - /plugins/testPlugin/ - /plugins/testPlugin/settings/ - diff --git a/testPlugin/middleware.py b/testPlugin/middleware.py deleted file mode 100644 index 7d0bd6cc2..000000000 --- a/testPlugin/middleware.py +++ /dev/null @@ -1,208 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Security middleware for the Test Plugin -Provides additional security measures and monitoring -""" -import time -import hashlib -from django.http import JsonResponse -from django.core.cache import cache -from django.conf import settings -from .security import SecurityManager - - -class TestPluginSecurityMiddleware: - """ - Security middleware for the Test Plugin - Provides additional protection against various attacks - """ - - def __init__(self, get_response): - self.get_response = get_response - - def __call__(self, request): - # Only apply security measures to testPlugin URLs - if not request.path.startswith('/testPlugin/'): - return self.get_response(request) - - # Security checks - if not self._security_checks(request): - return JsonResponse({ - 'status': 0, - 'error_message': 'Security violation detected. Access denied.' - }, status=403) - - response = self.get_response(request) - - # Add security headers - self._add_security_headers(response) - - return response - - def _security_checks(self, request): - """Perform security checks on the request""" - - # Check for suspicious patterns - if self._is_suspicious_request(request): - SecurityManager.log_security_event(request, "Suspicious request pattern detected", "suspicious_request") - return False - - # Check for SQL injection attempts - if self._has_sql_injection_patterns(request): - SecurityManager.log_security_event(request, "SQL injection attempt detected", "sql_injection") - return False - - # Check for XSS attempts - if self._has_xss_patterns(request): - SecurityManager.log_security_event(request, "XSS attempt detected", "xss_attempt") - return False - - # Check for path traversal attempts - if self._has_path_traversal_patterns(request): - SecurityManager.log_security_event(request, "Path traversal attempt detected", "path_traversal") - return False - - return True - - def _is_suspicious_request(self, request): - """Check for suspicious request patterns""" - suspicious_patterns = [ - '..', '//', '\\', 'cmd', 'exec', 'system', 'eval', - 'base64', 'decode', 'encode', 'hex', 'binary', - 'union', 'select', 'insert', 'update', 'delete', - 'drop', 'create', 'alter', 'grant', 'revoke' - ] - - # Check URL - url_lower = request.path.lower() - for pattern in suspicious_patterns: - if pattern in url_lower: - return True - - # Check query parameters - for key, value in request.GET.items(): - if isinstance(value, str): - value_lower = value.lower() - for pattern in suspicious_patterns: - if pattern in value_lower: - return True - - # Check POST data - if request.method == 'POST': - for key, value in request.POST.items(): - if isinstance(value, str): - value_lower = value.lower() - for pattern in suspicious_patterns: - if pattern in value_lower: - return True - - return False - - def _has_sql_injection_patterns(self, request): - """Check for SQL injection patterns""" - sql_patterns = [ - "'", '"', ';', '--', '/*', '*/', 'xp_', 'sp_', - 'union', 'select', 'insert', 'update', 'delete', - 'drop', 'create', 'alter', 'exec', 'execute', - 'waitfor', 'delay', 'benchmark', 'sleep' - ] - - # Check all request data - all_data = [] - all_data.extend(request.GET.values()) - all_data.extend(request.POST.values()) - - for value in all_data: - if isinstance(value, str): - value_lower = value.lower() - for pattern in sql_patterns: - if pattern in value_lower: - return True - - return False - - def _has_xss_patterns(self, request): - """Check for XSS patterns""" - xss_patterns = [ - '', 'javascript:', 'vbscript:', - 'onload=', 'onerror=', 'onclick=', 'onmouseover=', - 'onfocus=', 'onblur=', 'onchange=', 'onsubmit=', - 'onreset=', 'onselect=', 'onkeydown=', 'onkeyup=', - 'onkeypress=', 'onmousedown=', 'onmouseup=', - 'onmousemove=', 'onmouseout=', 'oncontextmenu=' - ] - - # Check all request data - all_data = [] - all_data.extend(request.GET.values()) - all_data.extend(request.POST.values()) - - for value in all_data: - if isinstance(value, str): - value_lower = value.lower() - for pattern in xss_patterns: - if pattern in value_lower: - return True - - return False - - def _has_path_traversal_patterns(self, request): - """Check for path traversal patterns""" - traversal_patterns = [ - '../', '..\\', '..%2f', '..%5c', '%2e%2e%2f', - '%2e%2e%5c', '..%252f', '..%255c' - ] - - # Check URL and all request data - all_data = [request.path] - all_data.extend(request.GET.values()) - all_data.extend(request.POST.values()) - - for value in all_data: - if isinstance(value, str): - for pattern in traversal_patterns: - if pattern in value.lower(): - return True - - return False - - def _add_security_headers(self, response): - """Add security headers to the response""" - # Prevent clickjacking - response['X-Frame-Options'] = 'DENY' - - # Prevent MIME type sniffing - response['X-Content-Type-Options'] = 'nosniff' - - # Enable XSS protection - response['X-XSS-Protection'] = '1; mode=block' - - # Strict Transport Security (if HTTPS) - if request.is_secure(): - response['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains' - - # Content Security Policy - response['Content-Security-Policy'] = ( - "default-src 'self'; " - "script-src 'self' 'unsafe-inline' 'unsafe-eval'; " - "style-src 'self' 'unsafe-inline'; " - "img-src 'self' data: https:; " - "font-src 'self' data:; " - "connect-src 'self'; " - "frame-ancestors 'none';" - ) - - # Referrer Policy - response['Referrer-Policy'] = 'strict-origin-when-cross-origin' - - # Permissions Policy - response['Permissions-Policy'] = ( - "geolocation=(), " - "microphone=(), " - "camera=(), " - "payment=(), " - "usb=(), " - "magnetometer=(), " - "gyroscope=(), " - "accelerometer=()" - ) diff --git a/testPlugin/models.py b/testPlugin/models.py deleted file mode 100644 index 146b361e7..000000000 --- a/testPlugin/models.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -from django.db import models -from django.contrib.auth.models import User - - -class TestPluginSettings(models.Model): - """Model to store plugin settings and enable/disable state""" - user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True) - plugin_enabled = models.BooleanField(default=True, help_text="Enable or disable the plugin") - test_count = models.IntegerField(default=0, help_text="Number of times test button was clicked") - last_test_time = models.DateTimeField(auto_now=True, help_text="Last time test button was clicked") - custom_message = models.TextField(default="Test plugin is working!", help_text="Custom message for popup") - - class Meta: - verbose_name = "Test Plugin Settings" - verbose_name_plural = "Test Plugin Settings" - - def __str__(self): - return f"Test Plugin Settings - Enabled: {self.plugin_enabled}" - - -class TestPluginLog(models.Model): - """Model to store plugin activity logs""" - timestamp = models.DateTimeField(auto_now_add=True) - action = models.CharField(max_length=100) - message = models.TextField() - user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True) - - class Meta: - verbose_name = "Test Plugin Log" - verbose_name_plural = "Test Plugin Logs" - ordering = ['-timestamp'] - - def __str__(self): - return f"{self.timestamp} - {self.action}: {self.message}" diff --git a/testPlugin/os_config.py b/testPlugin/os_config.py deleted file mode 100644 index b817d7183..000000000 --- a/testPlugin/os_config.py +++ /dev/null @@ -1,365 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Operating System Configuration for Test Plugin -Provides OS-specific configurations and compatibility checks -""" -import os -import platform -import subprocess -import sys -from pathlib import Path - - -class OSConfig: - """Operating System Configuration Manager""" - - def __init__(self): - self.os_name = self._detect_os_name() - self.os_version = self._detect_os_version() - self.os_arch = platform.machine() - self.python_path = self._detect_python_path() - self.pip_path = self._detect_pip_path() - self.service_manager = self._detect_service_manager() - self.web_server = self._detect_web_server() - self.package_manager = self._detect_package_manager() - - def _detect_os_name(self): - """Detect operating system name""" - try: - with open('/etc/os-release', 'r') as f: - for line in f: - if line.startswith('ID='): - return line.split('=')[1].strip().strip('"') - except FileNotFoundError: - pass - - # Fallback detection - if os.path.exists('/etc/redhat-release'): - return 'rhel' - elif os.path.exists('/etc/debian_version'): - return 'debian' - else: - return platform.system().lower() - - def _detect_os_version(self): - """Detect operating system version""" - try: - with open('/etc/os-release', 'r') as f: - for line in f: - if line.startswith('VERSION_ID='): - return line.split('=')[1].strip().strip('"') - except FileNotFoundError: - pass - - # Fallback detection - if os.path.exists('/etc/redhat-release'): - try: - with open('/etc/redhat-release', 'r') as f: - content = f.read() - import re - match = re.search(r'(\d+\.\d+)', content) - if match: - return match.group(1) - except: - pass - - return platform.release() - - def _detect_python_path(self): - """Detect Python executable path""" - # Try different Python commands - python_commands = ['python3', 'python3.11', 'python3.10', 'python3.9', 'python3.8', 'python3.7', 'python3.6', 'python'] - - for cmd in python_commands: - try: - result = subprocess.run([cmd, '--version'], - capture_output=True, text=True, timeout=5) - if result.returncode == 0: - # Check if it's Python 3.6+ - version = result.stdout.strip() - if 'Python 3' in version: - version_num = version.split()[1] - major, minor = map(int, version_num.split('.')[:2]) - if major == 3 and minor >= 6: - return cmd - except (subprocess.TimeoutExpired, FileNotFoundError, ValueError): - continue - - # Fallback to sys.executable - return sys.executable - - def _detect_pip_path(self): - """Detect pip executable path""" - # Try different pip commands - pip_commands = ['pip3', 'pip3.11', 'pip3.10', 'pip3.9', 'pip3.8', 'pip3.7', 'pip3.6', 'pip'] - - for cmd in pip_commands: - try: - result = subprocess.run([cmd, '--version'], - capture_output=True, text=True, timeout=5) - if result.returncode == 0: - return cmd - except (subprocess.TimeoutExpired, FileNotFoundError): - continue - - # Fallback - return 'pip3' - - def _detect_service_manager(self): - """Detect service manager (systemd, init.d, etc.)""" - if os.path.exists('/bin/systemctl') or os.path.exists('/usr/bin/systemctl'): - return 'systemctl' - elif os.path.exists('/etc/init.d'): - return 'service' - else: - return 'systemctl' # Default to systemctl - - def _detect_web_server(self): - """Detect web server""" - if os.path.exists('/etc/apache2') or os.path.exists('/etc/httpd'): - if os.path.exists('/etc/apache2'): - return 'apache2' - else: - return 'httpd' - else: - return 'httpd' # Default - - def _detect_package_manager(self): - """Detect package manager""" - if os.path.exists('/usr/bin/dnf'): - return 'dnf' - elif os.path.exists('/usr/bin/yum'): - return 'yum' - elif os.path.exists('/usr/bin/apt'): - return 'apt' - elif os.path.exists('/usr/bin/apt-get'): - return 'apt-get' - else: - return 'unknown' - - def get_os_info(self): - """Get comprehensive OS information""" - return { - 'name': self.os_name, - 'version': self.os_version, - 'architecture': self.os_arch, - 'python_path': self.python_path, - 'pip_path': self.pip_path, - 'service_manager': self.service_manager, - 'web_server': self.web_server, - 'package_manager': self.package_manager, - 'platform': platform.platform(), - 'python_version': sys.version - } - - def is_supported_os(self): - """Check if the current OS is supported""" - supported_os = [ - 'ubuntu', 'debian', 'almalinux', 'rocky', 'rhel', - 'centos', 'cloudlinux', 'fedora' - ] - return self.os_name in supported_os - - def get_os_specific_config(self): - """Get OS-specific configuration""" - configs = { - 'ubuntu': { - 'python_cmd': 'python3', - 'pip_cmd': 'pip3', - 'service_cmd': 'systemctl', - 'web_server': 'apache2', - 'package_manager': 'apt-get', - 'cyberpanel_user': 'cyberpanel', - 'cyberpanel_group': 'cyberpanel' - }, - 'debian': { - 'python_cmd': 'python3', - 'pip_cmd': 'pip3', - 'service_cmd': 'systemctl', - 'web_server': 'apache2', - 'package_manager': 'apt-get', - 'cyberpanel_user': 'cyberpanel', - 'cyberpanel_group': 'cyberpanel' - }, - 'almalinux': { - 'python_cmd': 'python3', - 'pip_cmd': 'pip3', - 'service_cmd': 'systemctl', - 'web_server': 'httpd', - 'package_manager': 'dnf', - 'cyberpanel_user': 'cyberpanel', - 'cyberpanel_group': 'cyberpanel' - }, - 'rocky': { - 'python_cmd': 'python3', - 'pip_cmd': 'pip3', - 'service_cmd': 'systemctl', - 'web_server': 'httpd', - 'package_manager': 'dnf', - 'cyberpanel_user': 'cyberpanel', - 'cyberpanel_group': 'cyberpanel' - }, - 'rhel': { - 'python_cmd': 'python3', - 'pip_cmd': 'pip3', - 'service_cmd': 'systemctl', - 'web_server': 'httpd', - 'package_manager': 'dnf', - 'cyberpanel_user': 'cyberpanel', - 'cyberpanel_group': 'cyberpanel' - }, - 'centos': { - 'python_cmd': 'python3', - 'pip_cmd': 'pip3', - 'service_cmd': 'systemctl', - 'web_server': 'httpd', - 'package_manager': 'dnf', - 'cyberpanel_user': 'cyberpanel', - 'cyberpanel_group': 'cyberpanel' - }, - 'cloudlinux': { - 'python_cmd': 'python3', - 'pip_cmd': 'pip3', - 'service_cmd': 'systemctl', - 'web_server': 'httpd', - 'package_manager': 'yum', - 'cyberpanel_user': 'cyberpanel', - 'cyberpanel_group': 'cyberpanel' - } - } - - return configs.get(self.os_name, configs['ubuntu']) # Default to Ubuntu config - - def get_python_requirements(self): - """Get Python requirements for the current OS""" - base_requirements = [ - 'Django>=2.2,<4.0', - 'django-cors-headers', - 'Pillow', - 'requests', - 'psutil' - ] - - # OS-specific requirements - os_requirements = { - 'ubuntu': [], - 'debian': [], - 'almalinux': ['python3-devel', 'gcc'], - 'rocky': ['python3-devel', 'gcc'], - 'rhel': ['python3-devel', 'gcc'], - 'centos': ['python3-devel', 'gcc'], - 'cloudlinux': ['python3-devel', 'gcc'] - } - - return base_requirements + os_requirements.get(self.os_name, []) - - def get_install_commands(self): - """Get OS-specific installation commands""" - config = self.get_os_specific_config() - - if config['package_manager'] in ['apt-get', 'apt']: - return { - 'update': 'apt-get update', - 'install_python': 'apt-get install -y python3 python3-pip python3-venv', - 'install_git': 'apt-get install -y git', - 'install_curl': 'apt-get install -y curl', - 'install_dev_tools': 'apt-get install -y build-essential python3-dev' - } - elif config['package_manager'] == 'dnf': - return { - 'update': 'dnf update -y', - 'install_python': 'dnf install -y python3 python3-pip python3-devel', - 'install_git': 'dnf install -y git', - 'install_curl': 'dnf install -y curl', - 'install_dev_tools': 'dnf install -y gcc gcc-c++ make python3-devel' - } - elif config['package_manager'] == 'yum': - return { - 'update': 'yum update -y', - 'install_python': 'yum install -y python3 python3-pip python3-devel', - 'install_git': 'yum install -y git', - 'install_curl': 'yum install -y curl', - 'install_dev_tools': 'yum install -y gcc gcc-c++ make python3-devel' - } - else: - # Fallback to Ubuntu commands - return { - 'update': 'apt-get update', - 'install_python': 'apt-get install -y python3 python3-pip python3-venv', - 'install_git': 'apt-get install -y git', - 'install_curl': 'apt-get install -y curl', - 'install_dev_tools': 'apt-get install -y build-essential python3-dev' - } - - def validate_environment(self): - """Validate the current environment""" - issues = [] - - # Check Python version - try: - result = subprocess.run([self.python_path, '--version'], - capture_output=True, text=True, timeout=5) - if result.returncode == 0: - version = result.stdout.strip() - if 'Python 3' in version: - version_num = version.split()[1] - major, minor = map(int, version_num.split('.')[:2]) - if major < 3 or (major == 3 and minor < 6): - issues.append(f"Python 3.6+ required, found {version}") - else: - issues.append(f"Python 3 required, found {version}") - else: - issues.append("Python not found or not working") - except Exception as e: - issues.append(f"Error checking Python: {e}") - - # Check pip - try: - result = subprocess.run([self.pip_path, '--version'], - capture_output=True, text=True, timeout=5) - if result.returncode != 0: - issues.append("pip not found or not working") - except Exception as e: - issues.append(f"Error checking pip: {e}") - - # Check if OS is supported - if not self.is_supported_os(): - issues.append(f"Unsupported operating system: {self.os_name}") - - return issues - - def get_compatibility_info(self): - """Get compatibility information for the current OS""" - return { - 'os_supported': self.is_supported_os(), - 'python_available': self.python_path is not None, - 'pip_available': self.pip_path is not None, - 'service_manager': self.service_manager, - 'web_server': self.web_server, - 'package_manager': self.package_manager, - 'validation_issues': self.validate_environment() - } - - -# Global instance -os_config = OSConfig() - - -def get_os_config(): - """Get the global OS configuration instance""" - return os_config - - -def is_os_supported(): - """Check if the current OS is supported""" - return os_config.is_supported_os() - - -def get_python_path(): - """Get the Python executable path""" - return os_config.python_path - - -def get_pip_path(): - """Get the pip executable path""" - return os_config.pip_path diff --git a/testPlugin/security.py b/testPlugin/security.py deleted file mode 100644 index d9c969492..000000000 --- a/testPlugin/security.py +++ /dev/null @@ -1,256 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Security utilities for the Test Plugin -Provides rate limiting, input validation, and security logging -Multi-OS compatible security implementation -""" -import time -import hashlib -import hmac -import json -import re -import os -import platform -from django.core.cache import cache -from django.conf import settings -from django.http import JsonResponse -from django.utils import timezone -from django.contrib.auth.models import User -from functools import wraps -from .models import TestPluginLog -from .os_config import get_os_config - - -class SecurityManager: - """Centralized security management for the plugin""" - - # Rate limiting settings - RATE_LIMIT_WINDOW = 300 # 5 minutes - MAX_REQUESTS_PER_WINDOW = 50 - MAX_FAILED_ATTEMPTS = 5 - LOCKOUT_DURATION = 900 # 15 minutes - - # Input validation patterns - SAFE_STRING_PATTERN = re.compile(r'^[a-zA-Z0-9\s\-_.,!?@#$%^&*()+=\[\]{}|\\:";\'<>?/~`]*$') - MAX_MESSAGE_LENGTH = 1000 - - @staticmethod - def is_rate_limited(request): - """Check if user has exceeded rate limits""" - user_id = request.user.id if request.user.is_authenticated else request.META.get('REMOTE_ADDR') - cache_key = f"rate_limit_{user_id}" - - current_time = time.time() - requests = cache.get(cache_key, []) - - # Remove old requests outside the window - requests = [req_time for req_time in requests if current_time - req_time < SecurityManager.RATE_LIMIT_WINDOW] - - if len(requests) >= SecurityManager.MAX_REQUESTS_PER_WINDOW: - return True - - # Add current request - requests.append(current_time) - cache.set(cache_key, requests, SecurityManager.RATE_LIMIT_WINDOW) - return False - - @staticmethod - def is_user_locked_out(request): - """Check if user is temporarily locked out due to failed attempts""" - user_id = request.user.id if request.user.is_authenticated else request.META.get('REMOTE_ADDR') - lockout_key = f"lockout_{user_id}" - - return cache.get(lockout_key, False) - - @staticmethod - def record_failed_attempt(request, reason="Invalid request"): - """Record a failed security attempt""" - user_id = request.user.id if request.user.is_authenticated else request.META.get('REMOTE_ADDR') - failed_key = f"failed_attempts_{user_id}" - - attempts = cache.get(failed_key, 0) + 1 - cache.set(failed_key, attempts, SecurityManager.RATE_LIMIT_WINDOW) - - # Log security event - SecurityManager.log_security_event(request, f"Failed attempt: {reason}", "security_failure") - - # Lock out user if too many failed attempts - if attempts >= SecurityManager.MAX_FAILED_ATTEMPTS: - lockout_key = f"lockout_{user_id}" - cache.set(lockout_key, True, SecurityManager.LOCKOUT_DURATION) - SecurityManager.log_security_event(request, "User locked out due to excessive failed attempts", "user_locked_out") - - @staticmethod - def clear_failed_attempts(request): - """Clear failed attempts for user after successful action""" - user_id = request.user.id if request.user.is_authenticated else request.META.get('REMOTE_ADDR') - failed_key = f"failed_attempts_{user_id}" - cache.delete(failed_key) - - @staticmethod - def validate_input(data, field_name, max_length=None): - """Validate input data for security""" - if not isinstance(data, str): - return False, f"{field_name} must be a string" - - if max_length and len(data) > max_length: - return False, f"{field_name} exceeds maximum length of {max_length} characters" - - if not SecurityManager.SAFE_STRING_PATTERN.match(data): - return False, f"{field_name} contains invalid characters" - - return True, "Valid" - - @staticmethod - def sanitize_input(data): - """Sanitize input data""" - if isinstance(data, str): - # Remove potential XSS vectors - data = data.replace('', '</script>') - data = data.replace('javascript:', '') - data = data.replace('onload=', '') - data = data.replace('onerror=', '') - data = data.replace('onclick=', '') - data = data.replace('onmouseover=', '') - # Remove null bytes - data = data.replace('\x00', '') - # Limit length - data = data[:SecurityManager.MAX_MESSAGE_LENGTH] - - return data - - @staticmethod - def log_security_event(request, message, event_type="security"): - """Log security-related events""" - try: - user_id = request.user.id if request.user.is_authenticated else None - ip_address = request.META.get('REMOTE_ADDR', 'unknown') - user_agent = request.META.get('HTTP_USER_AGENT', 'unknown') - - TestPluginLog.objects.create( - user_id=user_id, - action=event_type, - message=f"[SECURITY] {message} | IP: {ip_address} | UA: {user_agent[:100]}" - ) - except Exception: - # Don't let logging errors break the application - pass - - @staticmethod - def generate_csrf_token(request): - """Generate a secure CSRF token""" - if hasattr(request, 'csrf_token'): - return request.csrf_token - - # Fallback CSRF token generation - secret = getattr(settings, 'SECRET_KEY', 'fallback-secret') - timestamp = str(int(time.time())) - user_id = str(request.user.id) if request.user.is_authenticated else 'anonymous' - - token_data = f"{user_id}:{timestamp}" - token = hmac.new( - secret.encode(), - token_data.encode(), - hashlib.sha256 - ).hexdigest() - - return f"{token}:{timestamp}" - - @staticmethod - def verify_csrf_token(request, token): - """Verify CSRF token""" - if hasattr(request, 'csrf_token'): - return request.csrf_token == token - - try: - secret = getattr(settings, 'SECRET_KEY', 'fallback-secret') - token_part, timestamp = token.split(':') - - # Check if token is not too old (1 hour) - if time.time() - int(timestamp) > 3600: - return False - - user_id = str(request.user.id) if request.user.is_authenticated else 'anonymous' - token_data = f"{user_id}:{timestamp}" - expected_token = hmac.new( - secret.encode(), - token_data.encode(), - hashlib.sha256 - ).hexdigest() - - return hmac.compare_digest(token_part, expected_token) - except (ValueError, AttributeError): - return False - - -def secure_view(require_csrf=True, rate_limit=True, log_activity=True): - """Decorator for secure view functions""" - def decorator(view_func): - @wraps(view_func) - def wrapper(request, *args, **kwargs): - # Check if user is locked out - if SecurityManager.is_user_locked_out(request): - SecurityManager.log_security_event(request, "Blocked request from locked out user", "blocked_request") - return JsonResponse({ - 'status': 0, - 'error_message': 'Account temporarily locked due to security violations. Please try again later.' - }, status=423) - - # Check rate limiting - if rate_limit and SecurityManager.is_rate_limited(request): - SecurityManager.record_failed_attempt(request, "Rate limit exceeded") - return JsonResponse({ - 'status': 0, - 'error_message': 'Too many requests. Please slow down and try again later.' - }, status=429) - - # CSRF protection - if require_csrf and request.method == 'POST': - csrf_token = request.META.get('HTTP_X_CSRFTOKEN') or request.POST.get('csrfmiddlewaretoken') - if not csrf_token or not SecurityManager.verify_csrf_token(request, csrf_token): - SecurityManager.record_failed_attempt(request, "Invalid CSRF token") - return JsonResponse({ - 'status': 0, - 'error_message': 'Invalid security token. Please refresh the page and try again.' - }, status=403) - - # Log activity - if log_activity: - SecurityManager.log_security_event(request, f"Accessing {view_func.__name__}", "view_access") - - try: - result = view_func(request, *args, **kwargs) - # Clear failed attempts on successful request - SecurityManager.clear_failed_attempts(request) - return result - except Exception as e: - SecurityManager.log_security_event(request, f"Error in {view_func.__name__}: {str(e)}", "view_error") - return JsonResponse({ - 'status': 0, - 'error_message': 'An internal error occurred. Please try again later.' - }, status=500) - - return wrapper - return decorator - - -def admin_required(view_func): - """Decorator to ensure only admin users can access the view""" - @wraps(view_func) - def wrapper(request, *args, **kwargs): - if not request.user.is_authenticated: - return JsonResponse({ - 'status': 0, - 'error_message': 'Authentication required.' - }, status=401) - - if not request.user.is_staff and not request.user.is_superuser: - SecurityManager.log_security_event(request, "Unauthorized access attempt by non-admin user", "unauthorized_access") - return JsonResponse({ - 'status': 0, - 'error_message': 'Admin privileges required.' - }, status=403) - - return view_func(request, *args, **kwargs) - return wrapper diff --git a/testPlugin/signals.py b/testPlugin/signals.py deleted file mode 100644 index 1a3d1cd6b..000000000 --- a/testPlugin/signals.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- -from django.db.models.signals import post_save -from django.dispatch import receiver -from django.contrib.auth.models import User -from .models import TestPluginSettings - - -@receiver(post_save, sender=User) -def create_user_settings(sender, instance, created, **kwargs): - """Create default plugin settings when a new user is created""" - if created: - TestPluginSettings.objects.create( - user=instance, - plugin_enabled=True - ) diff --git a/testPlugin/static/testPlugin/css/testPlugin.css b/testPlugin/static/testPlugin/css/testPlugin.css deleted file mode 100644 index 4e978906c..000000000 --- a/testPlugin/static/testPlugin/css/testPlugin.css +++ /dev/null @@ -1,418 +0,0 @@ -/* Test Plugin CSS - Additional styles for better integration */ - -/* Popup Message Animations */ -@keyframes slideInRight { - from { - transform: translateX(100%); - opacity: 0; - } - to { - transform: translateX(0); - opacity: 1; - } -} - -@keyframes slideOutRight { - from { - transform: translateX(0); - opacity: 1; - } - to { - transform: translateX(100%); - opacity: 0; - } -} - -/* Enhanced Button Styles */ -.btn-test { - position: relative; - overflow: hidden; -} - -.btn-test::before { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 0; - height: 0; - background: rgba(255, 255, 255, 0.3); - border-radius: 50%; - transform: translate(-50%, -50%); - transition: width 0.6s, height 0.6s; -} - -.btn-test:active::before { - width: 300px; - height: 300px; -} - -/* Toggle Switch Enhanced */ -.toggle-switch { - position: relative; - display: inline-block; - width: 60px; - height: 34px; -} - -.toggle-switch input { - opacity: 0; - width: 0; - height: 0; -} - -.slider { - position: absolute; - cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: #ccc; - transition: .4s; - border-radius: 34px; -} - -.slider:before { - position: absolute; - content: ""; - height: 26px; - width: 26px; - left: 4px; - bottom: 4px; - background-color: white; - transition: .4s; - border-radius: 50%; - box-shadow: 0 2px 4px rgba(0,0,0,0.2); -} - -input:checked + .slider { - background-color: #5856d6; -} - -input:checked + .slider:before { - transform: translateX(26px); -} - -/* Loading States */ -.loading { - opacity: 0.6; - pointer-events: none; -} - -.loading::after { - content: ''; - position: absolute; - top: 50%; - left: 50%; - width: 20px; - height: 20px; - margin: -10px 0 0 -10px; - border: 2px solid transparent; - border-top: 2px solid currentColor; - border-radius: 50%; - animation: spin 1s linear infinite; -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -/* Card Hover Effects */ -.plugin-card { - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); -} - -.plugin-card:hover { - transform: translateY(-8px); - box-shadow: 0 12px 32px rgba(0,0,0,0.15); -} - -/* Status Indicators */ -.status-indicator { - display: inline-flex; - align-items: center; - gap: 8px; - padding: 6px 12px; - border-radius: 20px; - font-size: 12px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -.status-indicator.enabled { - background: #e8f5e8; - color: #388e3c; -} - -.status-indicator.disabled { - background: #ffebee; - color: #d32f2f; -} - -/* Responsive Enhancements */ -@media (max-width: 768px) { - .control-row { - flex-direction: column; - align-items: stretch; - } - - .control-group { - justify-content: space-between; - margin-bottom: 15px; - } - - .stats-grid { - grid-template-columns: 1fr; - gap: 15px; - } - - .logs-table { - font-size: 12px; - } - - .logs-table th, - .logs-table td { - padding: 8px 4px; - } -} - -@media (max-width: 480px) { - .test-plugin-wrapper { - padding: 10px; - } - - .plugin-header, - .control-panel, - .settings-form, - .logs-content { - padding: 15px; - } - - .plugin-header h1 { - font-size: 24px; - flex-direction: column; - text-align: center; - } - - .btn-test, - .btn-secondary { - width: 100%; - justify-content: center; - margin-bottom: 10px; - } -} - -/* Dark Mode Support */ -@media (prefers-color-scheme: dark) { - :root { - --bg-primary: #1a1a1a; - --bg-secondary: #2d2d2d; - --text-primary: #ffffff; - --text-secondary: #b3b3b3; - --text-tertiary: #808080; - --border-primary: #404040; - --shadow-md: 0 2px 8px rgba(0,0,0,0.3); - --shadow-lg: 0 8px 24px rgba(0,0,0,0.4); - } -} - -/* Print Styles */ -@media print { - .test-plugin-wrapper { - background: white !important; - color: black !important; - } - - .btn-test, - .btn-secondary, - .toggle-switch { - display: none !important; - } - - .popup-message { - display: none !important; - } -} - -/* Additional styles for inline elements */ -.popup-message { - position: fixed; - top: 20px; - right: 20px; - background: white; - border-radius: 8px; - padding: 16px 20px; - box-shadow: 0 8px 24px rgba(0,0,0,0.15); - border-left: 4px solid #10b981; - z-index: 9999; - max-width: 400px; - transform: translateX(100%); - transition: transform 0.3s ease; -} - -.popup-message.show { - transform: translateX(0); -} - -.popup-message.error { - border-left-color: #ef4444; -} - -.popup-message.warning { - border-left-color: #f59e0b; -} - -.popup-title { - font-weight: 600; - color: var(--text-primary, #2f3640); - margin-bottom: 4px; -} - -.popup-content { - font-size: 14px; - color: var(--text-secondary, #64748b); - margin-bottom: 8px; -} - -.popup-time { - font-size: 12px; - color: var(--text-tertiary, #9ca3af); -} - -.popup-close { - position: absolute; - top: 8px; - right: 8px; - background: none; - border: none; - font-size: 18px; - cursor: pointer; - color: var(--text-tertiary, #9ca3af); -} - -.notification { - position: fixed; - top: 20px; - right: 20px; - background: white; - border-radius: 8px; - padding: 16px 20px; - box-shadow: 0 8px 24px rgba(0,0,0,0.15); - border-left: 4px solid #10b981; - z-index: 9999; - max-width: 400px; - transform: translateX(100%); - transition: transform 0.3s ease; -} - -.notification.show { - transform: translateX(0); -} - -.notification.error { - border-left-color: #ef4444; -} - -.notification-title { - font-weight: 600; - color: var(--text-primary, #2f3640); - margin-bottom: 4px; -} - -.notification-content { - font-size: 14px; - color: var(--text-secondary, #64748b); -} - -.popup-container { - position: fixed; - top: 0; - right: 0; - z-index: 9999; - pointer-events: none; -} - -/* OS Compatibility Styles */ -.compatibility-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - gap: 20px; - margin: 20px 0; -} - -.os-card { - background: var(--bg-secondary, #f8f9ff); - border: 1px solid var(--border-primary, #e8e9ff); - border-radius: 8px; - padding: 20px; - transition: all 0.3s ease; -} - -.os-card:hover { - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(0,0,0,0.1); -} - -.os-card h3 { - color: var(--text-primary, #2f3640); - margin-bottom: 15px; - font-size: 18px; - font-weight: 600; -} - -.os-card ul { - list-style: none; - padding: 0; - margin: 0 0 15px 0; -} - -.os-card li { - padding: 5px 0; - color: var(--text-secondary, #64748b); - font-size: 14px; -} - -.os-card p { - margin: 5px 0; - color: var(--text-secondary, #64748b); - font-size: 13px; -} - -.troubleshooting-section { - margin: 20px 0; -} - -.troubleshooting-section h4 { - color: var(--text-primary, #2f3640); - margin: 15px 0 10px 0; - font-size: 16px; - font-weight: 600; -} - -.code-block { - background: var(--bg-secondary, #f8f9ff); - border: 1px solid var(--border-primary, #e8e9ff); - border-radius: 6px; - padding: 15px; - margin: 10px 0; - overflow-x: auto; -} - -.code-block pre { - margin: 0; - font-family: 'Courier New', monospace; - font-size: 13px; - line-height: 1.4; - color: var(--text-primary, #2f3640); -} - -.code-block code { - background: none; - padding: 0; - font-family: inherit; - font-size: inherit; - color: inherit; -} diff --git a/testPlugin/static/testPlugin/js/testPlugin.js b/testPlugin/static/testPlugin/js/testPlugin.js deleted file mode 100644 index 988de5538..000000000 --- a/testPlugin/static/testPlugin/js/testPlugin.js +++ /dev/null @@ -1,323 +0,0 @@ -/** - * Test Plugin JavaScript - * Handles all client-side functionality for the test plugin - */ - -class TestPlugin { - constructor() { - this.init(); - } - - init() { - this.bindEvents(); - this.initializeComponents(); - } - - bindEvents() { - // Toggle switch functionality - const toggleSwitch = document.getElementById('plugin-toggle'); - if (toggleSwitch) { - toggleSwitch.addEventListener('change', (e) => this.handleToggle(e)); - } - - // Test button functionality - const testButton = document.getElementById('test-button'); - if (testButton) { - testButton.addEventListener('click', (e) => this.handleTestClick(e)); - } - - // Settings form - const settingsForm = document.getElementById('settings-form'); - if (settingsForm) { - settingsForm.addEventListener('submit', (e) => this.handleSettingsSubmit(e)); - } - - // Log filter - const actionFilter = document.getElementById('action-filter'); - if (actionFilter) { - actionFilter.addEventListener('change', (e) => this.handleLogFilter(e)); - } - } - - initializeComponents() { - // Initialize any components that need setup - this.initializeTooltips(); - this.initializeAnimations(); - } - - async handleToggle(event) { - const toggleSwitch = event.target; - const testButton = document.getElementById('test-button'); - - try { - const response = await fetch('/testPlugin/toggle/', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': this.getCSRFToken() - } - }); - - const data = await response.json(); - - if (data.status === 1) { - if (testButton) { - testButton.disabled = !data.enabled; - } - this.showNotification('success', 'Plugin Toggle', data.message); - - // Update status indicator if exists - this.updateStatusIndicator(data.enabled); - - // Reload page after a short delay to update UI - setTimeout(() => { - window.location.reload(); - }, 1000); - } else { - this.showNotification('error', 'Error', data.error_message); - // Revert toggle state - toggleSwitch.checked = !toggleSwitch.checked; - } - } catch (error) { - this.showNotification('error', 'Error', 'Failed to toggle plugin'); - // Revert toggle state - toggleSwitch.checked = !toggleSwitch.checked; - } - } - - async handleTestClick(event) { - const testButton = event.target; - - if (testButton.disabled) return; - - // Add loading state - testButton.classList.add('loading'); - testButton.disabled = true; - const originalContent = testButton.innerHTML; - testButton.innerHTML = ' Testing...'; - - try { - const response = await fetch('/testPlugin/test/', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': this.getCSRFToken() - } - }); - - const data = await response.json(); - - if (data.status === 1) { - // Update test count - const testCountElement = document.getElementById('test-count'); - if (testCountElement) { - testCountElement.textContent = data.test_count; - } - - // Show popup message - this.showPopup( - data.popup_message.type, - data.popup_message.title, - data.popup_message.message - ); - - // Add success animation - testButton.style.background = 'linear-gradient(135deg, #10b981, #059669)'; - setTimeout(() => { - testButton.style.background = ''; - }, 2000); - } else { - this.showNotification('error', 'Error', data.error_message); - } - } catch (error) { - this.showNotification('error', 'Error', 'Failed to execute test'); - } finally { - // Remove loading state - testButton.classList.remove('loading'); - testButton.disabled = false; - testButton.innerHTML = originalContent; - } - } - - async handleSettingsSubmit(event) { - event.preventDefault(); - - const form = event.target; - const formData = new FormData(form); - const data = { - custom_message: formData.get('custom_message') - }; - - try { - const response = await fetch('/testPlugin/update-settings/', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': this.getCSRFToken() - }, - body: JSON.stringify(data) - }); - - const result = await response.json(); - - if (result.status === 1) { - this.showNotification('success', 'Settings Updated', result.message); - } else { - this.showNotification('error', 'Error', result.error_message); - } - } catch (error) { - this.showNotification('error', 'Error', 'Failed to update settings'); - } - } - - handleLogFilter(event) { - const selectedAction = event.target.value; - const logRows = document.querySelectorAll('.log-row'); - - logRows.forEach(row => { - if (selectedAction === '' || row.dataset.action === selectedAction) { - row.style.display = ''; - } else { - row.style.display = 'none'; - } - }); - } - - showPopup(type, title, message) { - const popupContainer = document.getElementById('popup-container') || this.createPopupContainer(); - const popup = document.createElement('div'); - popup.className = `popup-message ${type}`; - - popup.innerHTML = ` - - - - - `; - - popupContainer.appendChild(popup); - - // Show popup with animation - setTimeout(() => popup.classList.add('show'), 100); - - // Auto remove after 5 seconds - setTimeout(() => { - popup.classList.remove('show'); - setTimeout(() => popup.remove(), 300); - }, 5000); - } - - showNotification(type, title, message) { - const notification = document.createElement('div'); - notification.className = `notification ${type}`; - - notification.innerHTML = ` -
${title}
-
${message}
- `; - - document.body.appendChild(notification); - - // Show notification - setTimeout(() => notification.classList.add('show'), 100); - - // Auto remove after 3 seconds - setTimeout(() => { - notification.classList.remove('show'); - setTimeout(() => notification.remove(), 300); - }, 3000); - } - - createPopupContainer() { - const container = document.createElement('div'); - container.id = 'popup-container'; - container.className = 'popup-container'; - document.body.appendChild(container); - return container; - } - - updateStatusIndicator(enabled) { - const statusElements = document.querySelectorAll('.status-indicator'); - statusElements.forEach(element => { - element.className = `status-indicator ${enabled ? 'enabled' : 'disabled'}`; - element.innerHTML = enabled ? - ' Enabled' : - ' Disabled'; - }); - } - - initializeTooltips() { - // Add tooltips to buttons and controls - const elements = document.querySelectorAll('[data-tooltip]'); - elements.forEach(element => { - element.addEventListener('mouseenter', (e) => this.showTooltip(e)); - element.addEventListener('mouseleave', (e) => this.hideTooltip(e)); - }); - } - - showTooltip(event) { - const element = event.target; - const tooltipText = element.dataset.tooltip; - - if (!tooltipText) return; - - const tooltip = document.createElement('div'); - tooltip.className = 'tooltip'; - tooltip.textContent = tooltipText; - tooltip.style.cssText = ` - position: absolute; - background: #333; - color: white; - padding: 8px 12px; - border-radius: 4px; - font-size: 12px; - z-index: 10000; - pointer-events: none; - white-space: nowrap; - `; - - document.body.appendChild(tooltip); - - const rect = element.getBoundingClientRect(); - tooltip.style.left = rect.left + (rect.width / 2) - (tooltip.offsetWidth / 2) + 'px'; - tooltip.style.top = rect.top - tooltip.offsetHeight - 8 + 'px'; - - element._tooltip = tooltip; - } - - hideTooltip(event) { - const element = event.target; - if (element._tooltip) { - element._tooltip.remove(); - delete element._tooltip; - } - } - - initializeAnimations() { - // Add entrance animations to cards - const cards = document.querySelectorAll('.plugin-card, .stat-card, .log-item'); - cards.forEach((card, index) => { - card.style.opacity = '0'; - card.style.transform = 'translateY(20px)'; - card.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; - - setTimeout(() => { - card.style.opacity = '1'; - card.style.transform = 'translateY(0)'; - }, index * 100); - }); - } - - getCSRFToken() { - const token = document.querySelector('[name=csrfmiddlewaretoken]'); - return token ? token.value : ''; - } -} - -// Initialize the plugin when DOM is loaded -document.addEventListener('DOMContentLoaded', function() { - new TestPlugin(); -}); - -// Export for potential external use -window.TestPlugin = TestPlugin; diff --git a/testPlugin/templates/testPlugin/index.html b/testPlugin/templates/testPlugin/index.html deleted file mode 100644 index ed5250a1e..000000000 --- a/testPlugin/templates/testPlugin/index.html +++ /dev/null @@ -1,71 +0,0 @@ -{% extends "baseTemplate/base.html" %} -{% load static %} -{% load i18n %} - -{% block title %} - Test Plugin - {% trans "CyberPanel" %} -{% endblock %} - -{% block content %} -
-
-
-
-
-

- - {% trans "Test Plugin Dashboard" %} -

-
-
-
-
-
- - - -
- {% trans "Plugin Name" %} - {{ plugin_name }} -
-
-
-
-
- - - -
- {% trans "Version" %} - {{ version }} -
-
-
-
- -
-

{% trans "Plugin Information" %}

-

{{ description }}

-
- -
-
-

- - {% trans "Test Plugin Status" %} -

-
-
-
- - {% trans "Test Plugin is working correctly!" %} -
-

{% trans "This is a test plugin created for testing CyberPanel plugin functionality." %}

-
-
-
-
-
-
-
-{% endblock %} diff --git a/testPlugin/templates/testPlugin/plugin_docs.html b/testPlugin/templates/testPlugin/plugin_docs.html deleted file mode 100644 index 1d4d16be1..000000000 --- a/testPlugin/templates/testPlugin/plugin_docs.html +++ /dev/null @@ -1,1624 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% load static %} - -{% block title %}{% trans "Plugin Development Guide - CyberPanel" %}{% endblock %} - -{% block header_scripts %} - -{% endblock %} - -{% block content %} -
-
- -
-

- - {% trans "Plugin Development Documentation" %} -

-

{% trans "Complete guide for developing, installing, and managing CyberPanel plugins" %}

-
- - - - - -
-
-

Quick Installation Guide - CyberPanel Test Plugin

- -
-
-

šŸš€ One-Command Installation

-

Install the test plugin with a single command using curl or wget.

-
-
-

šŸ“¦ Manual Installation

-

Download and install manually with step-by-step instructions.

-
-
-

āš™ļø Easy Management

-

Simple install/uninstall process with proper cleanup.

-
-
- -

One-Command Installation

-
# Install the test plugin with a single command
-curl -sSL https://raw.githubusercontent.com/cyberpanel/testPlugin/main/install.sh | bash
- -

Manual Installation

-
    -
  1. Download the plugin -
    git clone https://github.com/cyberpanel/testPlugin.git
    -cd testPlugin
    -
  2. -
  3. Run the installation script -
    chmod +x install.sh
    -./install.sh
    -
  4. -
  5. Access the plugin -
      -
    • URL: https://your-domain:8090/testPlugin/
    • -
    • Login with your CyberPanel admin credentials
    • -
    -
  6. -
- -

Features Included

-
-
-

āœ… Enable/Disable Toggle

-

Toggle the plugin on/off with a beautiful switch

-
-
-

āœ… Test Button

-

Click to show popup messages from the side

-
-
-

āœ… Settings Page

-

Configure custom messages and preferences

-
-
-

āœ… Activity Logs

-

View all plugin activities with filtering

-
-
-

āœ… Inline Integration

-

Loads within CyberPanel interface

-
-
-

āœ… Responsive Design

-

Works perfectly on all devices

-
-
- -

Uninstallation

-
# Uninstall the plugin
-./install.sh --uninstall
- -

Troubleshooting

-

If you encounter any issues:

-
    -
  1. Check CyberPanel logs -
    tail -f /home/cyberpanel/logs/cyberpanel.log
    -
  2. -
  3. Restart CyberPanel services -
    systemctl restart lscpd
    -systemctl restart cyberpanel
    -
  4. -
  5. Verify installation -
    ls -la /home/cyberpanel/plugins/testPlugin
    -ls -la /usr/local/CyberCP/testPlugin
    -
  6. -
- -
- Note: This plugin is designed for testing and development purposes. Always backup your system before installing any plugins. -
-
-
- - -
-
-

Getting Started with CyberPanel Plugin Development

- -
-
-

šŸŽÆ Official Documentation

-

Based on the official CyberPanel plugin development guide from the CyberPanel team.

-
-
-

šŸ“š Step-by-Step Tutorial

-

Complete walkthrough from development environment setup to plugin installation.

-
-
-

šŸ”§ Signal Integration

-

Learn how to hook into CyberPanel events and respond to core functionality.

-
-
- -
- Source: This guide is based on the official CyberPanel documentation and the beautiful_names plugin repository. -
- -

Prerequisites

-
    -
  • Python - Clear understanding of Python Programming Language
  • -
  • Django - Experience with Django framework
  • -
  • HTML (Basic) - Basic HTML knowledge
  • -
  • CSS (Basic) - Basic CSS knowledge
  • -
- -

Note: You can use plain JavaScript in your plugins or any JavaScript framework. You just have to follow the norms of Django framework, because CyberPanel plugin is just another Django app.

- -

Step 1: Set up your Development Environment

- -

Clone CyberPanel Repository

-
git clone https://github.com/usmannasir/cyberpanel/ --single-branch v1.7.2-plugin
- -

Create a Django App

-
cd v1.7.2-plugin
-django-admin startapp pluginName
- -

Choose your plugin name wisely as it's of great importance. Once the Django app is created, you need to define a meta file for your plugin so that CyberPanel can read information about your plugin.

- -

Create Meta File

-
cd pluginName
-nano meta.xml
- -

Paste the following content in the meta.xml file:

-
<?xml version="1.0" encoding="UTF-8"?>
-<cyberpanelPluginConfig>
-  <name>customplugin</name>
-  <type>plugin</type>
-  <description>Plugin to make custom changes</description>
-  <version>0</version>
-</cyberpanelPluginConfig>
- -

Step 2: Creating a Signal File and Adjusting Settings

- -

Create Signals File

-

Create a signals.py file (you can name it anything, but signals.py is recommended). You can leave this file empty for now.

- -

Configure apps.py

-

In your apps.py file, you need to import the signals file inside the ready function:

-
def ready(self):
-    import signals
- -

Configure __init__.py

-

You need to specify a default_app_config variable in this file:

-
default_app_config = 'examplePlugin.apps.ExamplepluginConfig'
- -

Create urls.py

-

Inside your app root directory, create urls.py and paste this content:

-
from django.conf.urls import url
-import views
-
-urlpatterns = [
-    url(r'^$', views.examplePlugin, name='examplePlugin'),
-]
- -

Important: Replace examplePlugin with your plugin name. This URL definition is very important for CyberPanel to register your plugin page.

- -

Optional Files

-

You can create these optional files for database model management:

-
    -
  • pre_install - Executed before installation of plugin
  • -
  • post_install - Executed after installation of plugin
  • -
- -

If your file is Python code, don't forget to include this line at the top:

-
#!/usr/local/CyberCP/bin/python2
- -

Step 3: Responding to Events

- -

To plug into events fired by CyberPanel core, you can respond to various events happening in the core. Visit the signal file documentation for a complete list of events.

- -

Example Events

-
    -
  • preWebsiteCreation - Fired before CyberPanel starts the creation of website
  • -
  • postWebsiteDeletion - Fired after core finished the deletion of website
  • -
- -

Responding to Events

-

Here's how you can respond to the postWebsiteDeletion event:

-
from django.dispatch import receiver
-from django.http import HttpResponse
-from websiteFunctions.signals import postWebsiteDeletion
-from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
-
-@receiver(postWebsiteDeletion)
-def rcvr(sender, **kwargs):
-    request = kwargs['request']
-    logging.writeToFile('Hello World from Example Plugin.')
-    return HttpResponse('Hello World from Example Plugin.')
- -

Return Values

-
    -
  • HttpResponse object - CyberPanel core will stop further processing and return your response to browser
  • -
  • int 200 - CyberPanel core will continue processing, assuming the event was successfully executed
  • -
- -

Step 4: Packing, Shipping and Installing Plugin

- -

Package Your Plugin

-

After completing your plugin, zip your Django app. The zip file name should be your plugin name (e.g., examplePlugin.zip), otherwise installation will fail.

- -

Installation

-

First, upload your plugin to /usr/local/CyberCP/pluginInstaller:

-
cd /usr/local/CyberCP/pluginInstaller
-python pluginInstaller.py install --pluginName examplePlugin
- -

Uninstall

-
cd /usr/local/CyberCP/pluginInstaller
-python pluginInstaller.py remove --pluginName examplePlugin
- -

Beautiful Names Plugin Example

-

CyberPanel has released an official plugin called Beautiful Names that removes the admin_ prefix from Package and FTP account names. This plugin serves as a great example of how to create CyberPanel plugins.

- -

Installation of Beautiful Names

-
cd /usr/local/CyberCP/pluginInstaller
-wget https://cyberpanel.net/beautifulNames.zip
-python pluginInstaller.py install --pluginName beautifulNames
- -

Uninstall Beautiful Names

-
cd /usr/local/CyberCP/pluginInstaller
-python pluginInstaller.py remove --pluginName beautifulNames
- -

Plugin Installation Facility

-

The plugin installation facility is in beta and not available with the official install yet. To install plugins, you need to install CyberPanel via the test version:

-
sh <(curl https://mirror.cyberpanel.net/install-test.sh || wget -O - https://mirror.cyberpanel.net/install-test.sh)
- -

Additional Resources

- - -
- Note: This guide is based on the official CyberPanel documentation. For the most up-to-date information, always refer to the official sources. -
-
-
- - -
-
-

CyberPanel Plugin Development Guide

- - - -
-

How to Install Plugins

- -

Method 1: Using the Installation Script (Recommended)

-
# Download and run the installation script
-curl -sSL https://raw.githubusercontent.com/cyberpanel/testPlugin/main/install.sh | bash
-
-# Or download first, then run
-wget https://raw.githubusercontent.com/cyberpanel/testPlugin/main/install.sh
-chmod +x install.sh
-./install.sh
- -

Method 2: Manual Installation

-
    -
  1. Create Plugin Directory Structure -
    mkdir -p /home/cyberpanel/plugins/yourPlugin
    -mkdir -p /usr/local/CyberCP/yourPlugin
    -
  2. -
  3. Copy Plugin Files -
    cp -r yourPlugin/* /usr/local/CyberCP/yourPlugin/
    -chown -R cyberpanel:cyberpanel /usr/local/CyberCP/yourPlugin
    -chmod -R 755 /usr/local/CyberCP/yourPlugin
    -
  4. -
  5. Create Symlink -
    ln -sf /usr/local/CyberCP/yourPlugin /home/cyberpanel/plugins/yourPlugin
    -
  6. -
  7. Update Django Settings -

    Add your plugin to INSTALLED_APPS in /usr/local/CyberCP/cyberpanel/settings.py:

    -
    INSTALLED_APPS = [
    -    # ... existing apps ...
    -    'yourPlugin',
    -]
    -
  8. -
  9. Update URL Configuration -

    Add your plugin URLs in /usr/local/CyberCP/cyberpanel/urls.py:

    -
    urlpatterns = [
    -    # ... existing patterns ...
    -    path("yourPlugin/", include("yourPlugin.urls")),
    -]
    -
  10. -
  11. Run Migrations -
    cd /usr/local/CyberCP
    -python3 manage.py makemigrations yourPlugin
    -python3 manage.py migrate yourPlugin
    -
  12. -
  13. Collect Static Files -
    python3 manage.py collectstatic --noinput
    -
  14. -
  15. Restart Services -
    systemctl restart lscpd
    -systemctl restart cyberpanel
    -
  16. -
-
- -
-

How to Uninstall Plugins

- -

Method 1: Using the Installation Script

-
# Run with uninstall flag
-./install.sh --uninstall
- -

Method 2: Manual Uninstallation

-
    -
  1. Remove Plugin Files -
    rm -rf /usr/local/CyberCP/yourPlugin
    -rm -f /home/cyberpanel/plugins/yourPlugin
    -
  2. -
  3. Remove from Django Settings -
    sed -i '/yourPlugin/d' /usr/local/CyberCP/cyberpanel/settings.py
    -
  4. -
  5. Remove from URLs -
    sed -i '/yourPlugin/d' /usr/local/CyberCP/cyberpanel/urls.py
    -
  6. -
  7. Restart Services -
    systemctl restart lscpd
    -systemctl restart cyberpanel
    -
  8. -
-
- -
-

How to Add meta.xml

-

Create a meta.xml file in your plugin root directory:

-
<?xml version="1.0" encoding="UTF-8"?>
-<plugin>
-    <name>Your Plugin Name</name>
-    <type>Utility</type>
-    <description>Your plugin description</description>
-    <version>1.0.0</version>
-    <author>Your Name</author>
-    <website>https://your-website.com</website>
-    <license>MIT</license>
-    <dependencies>
-        <python>3.6+</python>
-        <django>2.2+</django>
-    </dependencies>
-    <permissions>
-        <admin>true</admin>
-        <user>false</user>
-    </permissions>
-    <settings>
-        <enable_toggle>true</enable_toggle>
-        <test_button>true</test_button>
-        <popup_messages>true</popup_messages>
-        <inline_integration>true</inline_integration>
-    </settings>
-</plugin>
- -

Required Fields:

-
    -
  • name: Plugin display name
  • -
  • type: Plugin category (Utility, Security, Performance, etc.)
  • -
  • description: Plugin description
  • -
  • version: Plugin version
  • -
- -

Optional Fields:

-
    -
  • author: Plugin author
  • -
  • website: Plugin website
  • -
  • license: License type
  • -
  • dependencies: Required dependencies
  • -
  • permissions: Access permissions
  • -
  • settings: Plugin-specific settings
  • -
-
- -
-

How to Add Buttons for Pages

- -

1. In Your Template

-
<!-- Primary Action Button -->
-<button class="btn-test" id="your-button">
-    <i class="fas fa-icon"></i>
-    Button Text
-</button>
-
-<!-- Secondary Button -->
-<a href="{% url 'yourPlugin:your_view' %}" class="btn-secondary">
-    <i class="fas fa-icon"></i>
-    Button Text
-</a>
-
-<!-- Danger Button -->
-<button class="btn-danger" id="danger-button">
-    <i class="fas fa-trash"></i>
-    Delete
-</button>
- -

2. CSS Styles

-
.btn-test {
-    background: linear-gradient(135deg, #5856d6, #4a90e2);
-    color: white;
-    border: none;
-    padding: 12px 24px;
-    border-radius: 8px;
-    font-weight: 600;
-    cursor: pointer;
-    transition: all 0.3s ease;
-    display: flex;
-    align-items: center;
-    gap: 8px;
-}
-
-.btn-test:hover {
-    transform: translateY(-2px);
-    box-shadow: 0 8px 20px rgba(88,86,214,0.3);
-}
-
-.btn-test:disabled {
-    opacity: 0.6;
-    cursor: not-allowed;
-    transform: none;
-}
- -

3. JavaScript Event Handling

-
document.getElementById('your-button').addEventListener('click', function() {
-    // Your button logic here
-    fetch('/yourPlugin/your-endpoint/', {
-        method: 'POST',
-        headers: {
-            'Content-Type': 'application/json',
-            'X-CSRFToken': getCSRFToken()
-        },
-        body: JSON.stringify({data: 'value'})
-    })
-    .then(response => response.json())
-    .then(data => {
-        if (data.status === 1) {
-            showNotification('success', 'Success', data.message);
-        } else {
-            showNotification('error', 'Error', data.error_message);
-        }
-    });
-});
-
- -
-

How to Add Toggles

- -

1. HTML Structure

-
<div class="control-group">
-    <label for="plugin-toggle" class="toggle-label">
-        Enable Feature
-    </label>
-    <label class="toggle-switch">
-        <input type="checkbox" id="plugin-toggle" {% if feature_enabled %}checked{% endif %}>
-        <span class="slider"></span>
-    </label>
-</div>
- -

2. CSS Styles

-
.toggle-switch {
-    position: relative;
-    display: inline-block;
-    width: 60px;
-    height: 34px;
-}
-
-.toggle-switch input {
-    opacity: 0;
-    width: 0;
-    height: 0;
-}
-
-.slider {
-    position: absolute;
-    cursor: pointer;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    background-color: #ccc;
-    transition: .4s;
-    border-radius: 34px;
-}
-
-.slider:before {
-    position: absolute;
-    content: "";
-    height: 26px;
-    width: 26px;
-    left: 4px;
-    bottom: 4px;
-    background-color: white;
-    transition: .4s;
-    border-radius: 50%;
-    box-shadow: 0 2px 4px rgba(0,0,0,0.2);
-}
-
-input:checked + .slider {
-    background-color: #5856d6;
-}
-
-input:checked + .slider:before {
-    transform: translateX(26px);
-}
- -

3. JavaScript Handling

-
document.getElementById('plugin-toggle').addEventListener('change', function() {
-    fetch('/yourPlugin/toggle/', {
-        method: 'POST',
-        headers: {
-            'Content-Type': 'application/json',
-            'X-CSRFToken': getCSRFToken()
-        }
-    })
-    .then(response => response.json())
-    .then(data => {
-        if (data.status === 1) {
-            showNotification('success', 'Toggle Updated', data.message);
-        } else {
-            showNotification('error', 'Error', data.error_message);
-            // Revert toggle state
-            this.checked = !this.checked;
-        }
-    });
-});
-
- -
-

How to Add Install/Uninstall Buttons

- -

1. In Your Plugin Template

-
<div class="plugin-actions">
-    <button class="btn-install" id="install-plugin">
-        <i class="fas fa-download"></i>
-        Install Plugin
-    </button>
-    
-    <button class="btn-uninstall" id="uninstall-plugin">
-        <i class="fas fa-trash"></i>
-        Uninstall Plugin
-    </button>
-</div>
- -

2. CSS Styles

-
.plugin-actions {
-    display: flex;
-    gap: 10px;
-    margin-top: 20px;
-}
-
-.btn-install {
-    background: #10b981;
-    color: white;
-    border: none;
-    padding: 10px 20px;
-    border-radius: 6px;
-    cursor: pointer;
-    transition: all 0.3s ease;
-}
-
-.btn-uninstall {
-    background: #ef4444;
-    color: white;
-    border: none;
-    padding: 10px 20px;
-    border-radius: 6px;
-    cursor: pointer;
-    transition: all 0.3s ease;
-}
-
-.btn-install:hover {
-    background: #059669;
-    transform: translateY(-2px);
-}
-
-.btn-uninstall:hover {
-    background: #dc2626;
-    transform: translateY(-2px);
-}
- -

3. JavaScript Implementation

-
// Install button
-document.getElementById('install-plugin').addEventListener('click', function() {
-    if (confirm('Are you sure you want to install this plugin?')) {
-        this.disabled = true;
-        this.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Installing...';
-        
-        fetch('/yourPlugin/install/', {
-            method: 'POST',
-            headers: {
-                'Content-Type': 'application/json',
-                'X-CSRFToken': getCSRFToken()
-            }
-        })
-        .then(response => response.json())
-        .then(data => {
-            if (data.status === 1) {
-                showNotification('success', 'Installation Complete', data.message);
-                location.reload();
-            } else {
-                showNotification('error', 'Installation Failed', data.error_message);
-            }
-        })
-        .finally(() => {
-            this.disabled = false;
-            this.innerHTML = '<i class="fas fa-download"></i> Install Plugin';
-        });
-    }
-});
-
-// Uninstall button
-document.getElementById('uninstall-plugin').addEventListener('click', function() {
-    if (confirm('Are you sure you want to uninstall this plugin? This action cannot be undone.')) {
-        this.disabled = true;
-        this.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Uninstalling...';
-        
-        fetch('/yourPlugin/uninstall/', {
-            method: 'POST',
-            headers: {
-                'Content-Type': 'application/json',
-                'X-CSRFToken': getCSRFToken()
-            }
-        })
-        .then(response => response.json())
-        .then(data => {
-            if (data.status === 1) {
-                showNotification('success', 'Uninstallation Complete', data.message);
-                setTimeout(() => location.reload(), 2000);
-            } else {
-                showNotification('error', 'Uninstallation Failed', data.error_message);
-            }
-        })
-        .finally(() => {
-            this.disabled = false;
-            this.innerHTML = '<i class="fas fa-trash"></i> Uninstall Plugin';
-        });
-    }
-});
-
- -
-

How to Add Enable/Disable Plugin Buttons

- -

1. Model for Plugin State

-
# models.py
-from django.db import models
-from django.contrib.auth.models import User
-
-class PluginSettings(models.Model):
-    user = models.ForeignKey(User, on_delete=models.CASCADE)
-    plugin_enabled = models.BooleanField(default=True)
-    created_at = models.DateTimeField(auto_now_add=True)
-    updated_at = models.DateTimeField(auto_now=True)
-    
-    class Meta:
-        unique_together = ['user']
- -

2. View for Toggle

-
# views.py
-from django.http import JsonResponse
-from django.views.decorators.http import require_http_methods
-from .models import PluginSettings
-
-@require_http_methods(["POST"])
-def toggle_plugin(request):
-    try:
-        settings, created = PluginSettings.objects.get_or_create(
-            user=request.user,
-            defaults={'plugin_enabled': True}
-        )
-        
-        settings.plugin_enabled = not settings.plugin_enabled
-        settings.save()
-        
-        return JsonResponse({
-            'status': 1,
-            'enabled': settings.plugin_enabled,
-            'message': f'Plugin {"enabled" if settings.plugin_enabled else "disabled"} successfully'
-        })
-    except Exception as e:
-        return JsonResponse({'status': 0, 'error_message': str(e)})
- -

3. Template Implementation

-
<div class="plugin-controls">
-    <label for="plugin-toggle" class="toggle-label">
-        Enable Plugin
-    </label>
-    <label class="toggle-switch">
-        <input type="checkbox" id="plugin-toggle" {% if plugin_enabled %}checked{% endif %}>
-        <span class="slider"></span>
-    </label>
-</div>
- -

4. JavaScript Handling

-
document.getElementById('plugin-toggle').addEventListener('change', function() {
-    fetch('/yourPlugin/toggle/', {
-        method: 'POST',
-        headers: {
-            'Content-Type': 'application/json',
-            'X-CSRFToken': getCSRFToken()
-        }
-    })
-    .then(response => response.json())
-    .then(data => {
-        if (data.status === 1) {
-            showNotification('success', 'Plugin Toggle', data.message);
-            // Update UI elements based on enabled state
-            updatePluginUI(data.enabled);
-        } else {
-            showNotification('error', 'Error', data.error_message);
-            this.checked = !this.checked; // Revert toggle
-        }
-    });
-});
-
-function updatePluginUI(enabled) {
-    const buttons = document.querySelectorAll('.plugin-button');
-    buttons.forEach(button => {
-        button.disabled = !enabled;
-    });
-    
-    const statusIndicator = document.querySelector('.status-indicator');
-    if (statusIndicator) {
-        statusIndicator.textContent = enabled ? 'Enabled' : 'Disabled';
-        statusIndicator.className = `status-indicator ${enabled ? 'enabled' : 'disabled'}`;
-    }
-}
-
- -
-

How to Avoid Breaking the CyberPanel Sidebar

- -

1. Use CyberPanel's Base Template

-

Always extend the base template:

-
{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% load static %}
-
-{% block title %}{% trans "Your Plugin - CyberPanel" %}{% endblock %}
-
-{% block content %}
-<!-- Your plugin content here -->
-{% endblock %}
- -

2. Don't Modify the Sidebar HTML

-

Never directly modify the sidebar HTML. Instead, use CyberPanel's built-in navigation system.

- -

3. Use Proper CSS Scoping

-
/* Good: Scoped to your plugin */
-.your-plugin-wrapper {
-    /* Your styles here */
-}
-
-/* Bad: Global styles that might affect sidebar */
-.sidebar {
-    /* Don't do this */
-}
- -

4. Use CyberPanel's CSS Variables

-
.your-plugin-element {
-    background: var(--bg-primary, white);
-    color: var(--text-primary, #2f3640);
-    border: 1px solid var(--border-primary, #e8e9ff);
-}
- -

5. Test Responsive Design

-

Ensure your plugin works on all screen sizes without breaking the sidebar:

-
@media (max-width: 768px) {
-    .your-plugin-wrapper {
-        padding: 15px;
-    }
-    
-    /* Don't modify sidebar behavior */
-}
-
- -
-

How to Make Plugins Load Inline

- -

1. Use CyberPanel's httpProc

-
# views.py
-from plogical.httpProc import httpProc
-
-def your_view(request):
-    context = {
-        'data': 'your_data',
-        'plugin_enabled': True
-    }
-    
-    proc = httpProc(request, 'yourPlugin/your_template.html', context, 'admin')
-    return proc.render()
- -

2. Template Structure

-
{% extends "baseTemplate/index.html" %}
-{% load i18n %}
-{% load static %}
-
-{% block title %}{% trans "Your Plugin - CyberPanel" %}{% endblock %}
-
-{% block header_scripts %}
-<style>
-    /* Your plugin-specific styles */
-    .your-plugin-wrapper {
-        background: transparent;
-        padding: 20px;
-    }
-    
-    .your-plugin-container {
-        max-width: 1200px;
-        margin: 0 auto;
-    }
-</style>
-{% endblock %}
-
-{% block content %}
-<div class="your-plugin-wrapper">
-    <div class="your-plugin-container">
-        <!-- Your plugin content here -->
-    </div>
-</div>
-{% endblock %}
- -

3. URL Configuration

-
# urls.py
-from django.urls import path
-from . import views
-
-app_name = 'yourPlugin'
-
-urlpatterns = [
-    path('', views.your_view, name='your_view'),
-    path('settings/', views.settings_view, name='settings'),
-    # ... other URLs
-]
- -

4. Main URLs Integration

-
# In /usr/local/CyberCP/cyberpanel/urls.py
-urlpatterns = [
-    # ... existing patterns ...
-    path("yourPlugin/", include("yourPlugin.urls")),
-]
-
- -
-

Plugin Structure Overview

-
yourPlugin/
-ā”œā”€ā”€ __init__.py
-ā”œā”€ā”€ admin.py
-ā”œā”€ā”€ apps.py
-ā”œā”€ā”€ models.py
-ā”œā”€ā”€ views.py
-ā”œā”€ā”€ urls.py
-ā”œā”€ā”€ signals.py
-ā”œā”€ā”€ meta.xml
-ā”œā”€ā”€ install.sh
-ā”œā”€ā”€ templates/
-│   └── yourPlugin/
-│       ā”œā”€ā”€ plugin_home.html
-│       ā”œā”€ā”€ plugin_settings.html
-│       └── plugin_logs.html
-ā”œā”€ā”€ static/
-│   └── yourPlugin/
-│       ā”œā”€ā”€ css/
-│       │   └── yourPlugin.css
-│       └── js/
-│           └── yourPlugin.js
-└── migrations/
-    └── __init__.py
-
- -
-

Best Practices

- -

1. Security

-
    -
  • Always validate user input
  • -
  • Use CSRF protection
  • -
  • Sanitize data before displaying
  • -
  • Use proper authentication decorators
  • -
- -

2. Performance

-
    -
  • Use database indexes for frequently queried fields
  • -
  • Implement caching where appropriate
  • -
  • Optimize database queries
  • -
  • Minimize JavaScript and CSS
  • -
- -

3. User Experience

-
    -
  • Provide clear feedback for all actions
  • -
  • Use loading states for long operations
  • -
  • Implement proper error handling
  • -
  • Make the interface responsive
  • -
- -

4. Code Quality

-
    -
  • Follow Django best practices
  • -
  • Use meaningful variable names
  • -
  • Add proper documentation
  • -
  • Write unit tests
  • -
- -

5. Integration

-
    -
  • Use CyberPanel's existing components
  • -
  • Follow the established design patterns
  • -
  • Maintain consistency with the UI
  • -
  • Test thoroughly before release
  • -
-
- -
-

Troubleshooting

- -

Common Issues

- -

1. Plugin not showing in installed plugins

-
    -
  • Check if meta.xml exists and is valid
  • -
  • Verify the plugin is in INSTALLED_APPS
  • -
  • Ensure proper file permissions
  • -
- -

2. Template not found errors

-
    -
  • Check template path in views.py
  • -
  • Verify template files exist
  • -
  • Ensure proper directory structure
  • -
- -

3. Static files not loading

-
    -
  • Run python3 manage.py collectstatic
  • -
  • Check STATIC_URL configuration
  • -
  • Verify file permissions
  • -
- -

4. Database migration errors

-
    -
  • Check model definitions
  • -
  • Run python3 manage.py makemigrations
  • -
  • Verify database connectivity
  • -
- -

5. Permission denied errors

-
    -
  • Check file ownership (cyberpanel:cyberpanel)
  • -
  • Verify file permissions (755 for directories, 644 for files)
  • -
  • Ensure proper SELinux context if applicable
  • -
- -

Debug Steps

- -

1. Check CyberPanel logs

-
tail -f /home/cyberpanel/logs/cyberpanel.log
- -

2. Check Django logs

-
tail -f /home/cyberpanel/logs/django.log
- -

3. Verify plugin installation

-
ls -la /home/cyberpanel/plugins/
-ls -la /usr/local/CyberCP/yourPlugin/
- -

4. Test database connectivity

-
cd /usr/local/CyberCP
-python3 manage.py shell
- -

5. Check service status

-
systemctl status lscpd
-systemctl status cyberpanel
-
- -
- Conclusion: This guide provides comprehensive instructions for developing CyberPanel plugins. Follow the best practices and troubleshooting steps to ensure your plugins integrate seamlessly with CyberPanel while maintaining security and performance standards. -
-
-
-
-
- - -
-
-

Operating System Compatibility

- -
-
-

🌐 Multi-OS Support

-

Comprehensive support for all CyberPanel-supported operating systems.

-
-
-

šŸ” Automatic Detection

-

Intelligent OS detection and configuration for seamless installation.

-
-
-

🧪 Compatibility Testing

-

Built-in compatibility testing to verify system requirements.

-
-
- -

Supported Operating Systems

- -
-
-

Ubuntu

-
    -
  • āœ… Ubuntu 22.04 (Full Support)
  • -
  • āœ… Ubuntu 20.04 (Full Support)
  • -
  • āœ… Debian 11+ (Compatible)
  • -
-

Package Manager: apt-get

-

Web Server: apache2

-
- -
-

RHEL-based

-
    -
  • āœ… AlmaLinux 8, 9, 10
  • -
  • āœ… RockyLinux 8, 9
  • -
  • āœ… RHEL 8, 9
  • -
  • āœ… CentOS 9
  • -
-

Package Manager: dnf/yum

-

Web Server: httpd

-
- -
-

CloudLinux

-
    -
  • āœ… CloudLinux 8
  • -
  • āœ… CloudLinux 7 (Limited)
  • -
-

Package Manager: yum

-

Web Server: httpd

-
-
- -

Python Compatibility

-

The plugin requires Python 3.6+ and automatically detects the correct Python executable:

- -
-
# Detection order:
-1. python3.12
-2. python3.11
-3. python3.10
-4. python3.9
-5. python3.8
-6. python3.7
-7. python3.6
-8. python3
-9. python (fallback)
-
- -

Installation Compatibility

-

The installation script automatically detects your operating system and configures the plugin accordingly:

- -
-
# Automatic detection includes:
-- OS name and version
-- Python executable path
-- Package manager (apt-get, dnf, yum)
-- Service manager (systemctl, service)
-- Web server (apache2, httpd)
-- User and group permissions
-
- -

Compatibility Testing

-

Run the built-in compatibility test to verify your system:

- -
-
# Navigate to plugin directory
-cd /usr/local/CyberCP/testPlugin
-
-# Run compatibility test
-python3 test_os_compatibility.py
-
-# Or make it executable and run
-chmod +x test_os_compatibility.py
-./test_os_compatibility.py
-
- -

Test Results

-

The compatibility test checks:

-
    -
  • āœ… OS detection and version
  • -
  • āœ… Python installation and version
  • -
  • āœ… Package manager availability
  • -
  • āœ… Service manager functionality
  • -
  • āœ… Web server configuration
  • -
  • āœ… File permissions and ownership
  • -
  • āœ… Network connectivity
  • -
  • āœ… CyberPanel integration
  • -
- -

OS-Specific Configurations

- -

Ubuntu/Debian Systems

-
-
# Package Manager: apt-get
-# Python: python3
-# Pip: pip3
-# Service Manager: systemctl
-# Web Server: apache2
-# User/Group: cyberpanel:cyberpanel
-
-# Installation commands
-sudo apt-get update
-sudo apt-get install -y python3 python3-pip python3-venv git curl
-sudo apt-get install -y build-essential python3-dev
-
- -

RHEL-based Systems

-
-
# Package Manager: dnf (RHEL 8+) / yum (RHEL 7)
-# Python: python3
-# Pip: pip3
-# Service Manager: systemctl
-# Web Server: httpd
-# User/Group: cyberpanel:cyberpanel
-
-# Installation commands (RHEL 8+)
-sudo dnf install -y python3 python3-pip python3-devel git curl
-sudo dnf install -y gcc gcc-c++ make
-
-# Installation commands (RHEL 7)
-sudo yum install -y python3 python3-pip python3-devel git curl
-sudo yum install -y gcc gcc-c++ make
-
- -

CloudLinux

-
-
# Package Manager: yum
-# Python: python3
-# Pip: pip3
-# Service Manager: systemctl
-# Web Server: httpd
-# User/Group: cyberpanel:cyberpanel
-
-# Installation commands
-sudo yum install -y python3 python3-pip python3-devel git curl
-sudo yum install -y gcc gcc-c++ make
-
-# CageFS configuration
-cagefsctl --enable cyberpanel
-cagefsctl --update
-
- -

Security Compatibility

- -

SELinux (RHEL-based systems)

-
-
# Check SELinux status
-sestatus
-
-# Set proper context for plugin files
-setsebool -P httpd_can_network_connect 1
-chcon -R -t httpd_exec_t /usr/local/CyberCP/testPlugin/
-
- -

AppArmor (Ubuntu/Debian)

-
-
# Check AppArmor status
-aa-status
-
-# Allow Apache to access plugin files
-aa-complain apache2
-
- -

Firewall Configuration

-
-
# Ubuntu/Debian (ufw)
-sudo ufw allow 8090/tcp
-sudo ufw allow 80/tcp
-sudo ufw allow 443/tcp
-
-# RHEL-based (firewalld)
-sudo firewall-cmd --permanent --add-port=8090/tcp
-sudo firewall-cmd --permanent --add-port=80/tcp
-sudo firewall-cmd --permanent --add-port=443/tcp
-sudo firewall-cmd --reload
-
- -

Troubleshooting

- -

Common Issues

-
-

Python not found

-
-
# Ubuntu/Debian
-sudo apt-get update
-sudo apt-get install -y python3 python3-pip
-
-# RHEL-based
-sudo dnf install -y python3 python3-pip
-# or
-sudo yum install -y python3 python3-pip
-
- -

Permission denied

-
-
sudo chown -R cyberpanel:cyberpanel /home/cyberpanel/plugins
-sudo chown -R cyberpanel:cyberpanel /usr/local/CyberCP/testPlugin
-
- -

Service not starting

-
-
sudo systemctl daemon-reload
-sudo systemctl restart lscpd
-sudo systemctl restart apache2  # Ubuntu/Debian
-sudo systemctl restart httpd    # RHEL-based
-
-
- -

Debug Commands

-
-
# Check OS information
-cat /etc/os-release
-uname -a
-
-# Check Python installation
-python3 --version
-which python3
-which pip3
-
-# Check services
-systemctl status lscpd
-systemctl status apache2  # Ubuntu/Debian
-systemctl status httpd    # RHEL-based
-
-# Check file permissions
-ls -la /home/cyberpanel/plugins/
-ls -la /usr/local/CyberCP/testPlugin/
-
-# Check CyberPanel logs
-tail -f /home/cyberpanel/logs/cyberpanel.log
-tail -f /home/cyberpanel/logs/django.log
-
- -
- Note: The plugin is designed to work seamlessly across all supported operating systems. If you encounter any compatibility issues, please run the compatibility test and check the troubleshooting section above. -
-
-
- - -{% endblock %} diff --git a/testPlugin/templates/testPlugin/plugin_home.html b/testPlugin/templates/testPlugin/plugin_home.html deleted file mode 100644 index 3ef326229..000000000 --- a/testPlugin/templates/testPlugin/plugin_home.html +++ /dev/null @@ -1,571 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% load static %} - -{% block title %}{% trans "Test Plugin - CyberPanel" %}{% endblock %} - -{% block header_scripts %} - -{% endblock %} - -{% block content %} -
-
- -
-

-
- -
- {% trans "Test Plugin" %} -

-

{% trans "A comprehensive test plugin with enable/disable functionality, test button, and popup messages" %}

-
- - -
-
-
- - -
- - -
-
- - -
-
-
{{ settings.test_count|default:0 }}
-
{% trans "Test Clicks" %}
-
- -
-
- {% if plugin_enabled %} - - {% else %} - - {% endif %} -
-
{% trans "Plugin Status" %}
-
- -
-
{{ recent_logs|length }}
-
{% trans "Recent Activities" %}
-
-
- - -
-

- - {% trans "Recent Activity" %} -

- -
- {% for log in recent_logs %} -
-
- {% if 'click' in log.action %} - - {% elif 'toggle' in log.action %} - - {% elif 'settings' in log.action %} - - {% else %} - - {% endif %} -
-
-
{{ log.action|title }}
-
{{ log.message }}
-
-
{{ log.timestamp|date:"M d, H:i" }}
-
- {% empty %} -
- -

{% trans "No recent activity" %}

-
- {% endfor %} -
-
-
-
- - - - - -{% endblock %} diff --git a/testPlugin/templates/testPlugin/plugin_logs.html b/testPlugin/templates/testPlugin/plugin_logs.html deleted file mode 100644 index 88771663a..000000000 --- a/testPlugin/templates/testPlugin/plugin_logs.html +++ /dev/null @@ -1,291 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% load static %} - -{% block title %}{% trans "Test Plugin Logs - CyberPanel" %}{% endblock %} - -{% block header_scripts %} - -{% endblock %} - -{% block content %} -
-
- -
-

- - {% trans "Test Plugin Logs" %} -

-

{% trans "View detailed activity logs for the test plugin" %}

-
- - -
-
- - - - - {% trans "Back to Plugin" %} - - - - - {% trans "Documentation" %} - - - - - {% trans "Security Info" %} - -
- - {% if logs %} - - - - - - - - - - {% for log in logs %} - - - - - - {% endfor %} - -
{% trans "Action" %}{% trans "Message" %}{% trans "Timestamp" %}
- - {% if 'click' in log.action %} - - {% elif 'toggle' in log.action %} - - {% elif 'settings' in log.action %} - - {% elif 'visit' in log.action %} - - {% else %} - - {% endif %} - - {{ log.action|title|replace:"_":" " }} - {{ log.message }}{{ log.timestamp|date:"M d, Y H:i:s" }}
- {% else %} -
- -

{% trans "No Logs Found" %}

-

{% trans "No activity logs available yet. Start using the plugin to see logs here." %}

-
- {% endif %} -
-
-
- - -{% endblock %} diff --git a/testPlugin/templates/testPlugin/plugin_settings.html b/testPlugin/templates/testPlugin/plugin_settings.html deleted file mode 100644 index 6368cb739..000000000 --- a/testPlugin/templates/testPlugin/plugin_settings.html +++ /dev/null @@ -1,264 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% load static %} - -{% block title %}{% trans "Test Plugin Settings - CyberPanel" %}{% endblock %} - -{% block header_scripts %} - -{% endblock %} - -{% block content %} -
-
- -
-

- - {% trans "Test Plugin Settings" %} -

-

{% trans "Configure your test plugin settings and preferences" %}

-
- - -
-
- {% csrf_token %} - -
- - - - {% trans "This message will be displayed when you click the test button" %} - -
- -
- -
- - {% if settings.plugin_enabled %} - {% trans "Enabled" %} - {% else %} - {% trans "Disabled" %} - {% endif %} - -

- {% trans "Use the toggle switch on the main page to enable/disable the plugin" %} -

-
-
- -
- -
-
-
{{ settings.test_count }}
-
{% trans "Total Tests" %}
-
-
-
{{ settings.last_test_time|date:"M d" }}
-
{% trans "Last Test" %}
-
-
-
- - -
-
-
-
- - -{% endblock %} diff --git a/testPlugin/templates/testPlugin/security_info.html b/testPlugin/templates/testPlugin/security_info.html deleted file mode 100644 index 66c765c66..000000000 --- a/testPlugin/templates/testPlugin/security_info.html +++ /dev/null @@ -1,499 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load i18n %} -{% load static %} - -{% block title %}{% trans "Security Information - CyberPanel" %}{% endblock %} - -{% block header_scripts %} - -{% endblock %} - -{% block content %} -
-
- -
-

- - {% trans "Security Information" %} -

-

{% trans "Comprehensive security measures implemented in the Test Plugin" %}

-
- - -
-
-
15+
-
{% trans "Security Features" %}
-
-
-
99%
-
{% trans "Attack Prevention" %}
-
-
-
24/7
-
{% trans "Monitoring" %}
-
-
-
0
-
{% trans "Known Vulnerabilities" %}
-
-
- - -
- - - {% trans "Back to Plugin" %} - - -

{% trans "Security Features Implemented" %}

- -
-

-
- -
- {% trans "Authentication & Authorization" %} -

-

{% trans "Multi-layered authentication and authorization system" %}

-
    -
  • -
    - {% trans "Admin-only access required for all plugin functions" %} -
  • -
  • -
    - {% trans "User session validation on every request" %} -
  • -
  • -
    - {% trans "Privilege escalation protection" %} -
  • -
-
- -
-

-
- -
- {% trans "Rate Limiting & Brute Force Protection" %} -

-

{% trans "Advanced rate limiting to prevent brute force attacks" %}

-
    -
  • -
    - {% trans "50 requests per 5-minute window per user" %} -
  • -
  • -
    - {% trans "10 test button clicks per minute limit" %} -
  • -
  • -
    - {% trans "Automatic lockout after 5 failed attempts" %} -
  • -
  • -
    - {% trans "15-minute lockout duration" %} -
  • -
-
- -
-

-
- -
- {% trans "CSRF Protection" %} -

-

{% trans "Cross-Site Request Forgery protection on all POST requests" %}

-
    -
  • -
    - {% trans "HMAC-based CSRF token validation" %} -
  • -
  • -
    - {% trans "Token expiration after 1 hour" %} -
  • -
  • -
    - {% trans "User-specific token generation" %} -
  • -
-
- -
-

-
- -
- {% trans "Input Validation & Sanitization" %} -

-

{% trans "Comprehensive input validation and sanitization" %}

-
    -
  • -
    - {% trans "Regex-based input validation" %} -
  • -
  • -
    - {% trans "XSS attack prevention" %} -
  • -
  • -
    - {% trans "SQL injection prevention" %} -
  • -
  • -
    - {% trans "Path traversal protection" %} -
  • -
  • -
    - {% trans "Maximum input length limits" %} -
  • -
-
- -
-

-
- -
- {% trans "Security Monitoring & Logging" %} -

-

{% trans "Comprehensive security event monitoring and logging" %}

-
    -
  • -
    - {% trans "All security events logged with IP and user agent" %} -
  • -
  • -
    - {% trans "Failed attempt tracking and alerting" %} -
  • -
  • -
    - {% trans "Suspicious activity detection" %} -
  • -
  • -
    - {% trans "Real-time security event monitoring" %} -
  • -
-
- -
-

-
- -
- {% trans "HTTP Security Headers" %} -

-

{% trans "Comprehensive HTTP security headers for additional protection" %}

-
    -
  • -
    - {% trans "X-Frame-Options: DENY (clickjacking protection)" %} -
  • -
  • -
    - {% trans "X-Content-Type-Options: nosniff" %} -
  • -
  • -
    - {% trans "X-XSS-Protection: 1; mode=block" %} -
  • -
  • -
    - {% trans "Content-Security-Policy (CSP)" %} -
  • -
  • -
    - {% trans "Strict-Transport-Security (HSTS)" %} -
  • -
  • -
    - {% trans "Referrer-Policy: strict-origin-when-cross-origin" %} -
  • -
-
- -
-

-
- -
- {% trans "Data Isolation & Privacy" %} -

-

{% trans "User data isolation and privacy protection" %}

-
    -
  • -
    - {% trans "User-specific data isolation" %} -
  • -
  • -
    - {% trans "Logs restricted to user's own activities" %} -
  • -
  • -
    - {% trans "Settings isolated per user" %} -
  • -
  • -
    - {% trans "No cross-user data access" %} -
  • -
-
- -
-

-
- -
- {% trans "Security Recommendations" %} -

-

{% trans "Additional security measures you should implement" %}

-
    -
  • -
    - {% trans "Keep CyberPanel and all plugins updated" %} -
  • -
  • -
    - {% trans "Use strong, unique passwords" %} -
  • -
  • -
    - {% trans "Enable 2FA on your CyberPanel account" %} -
  • -
  • -
    - {% trans "Regularly review security logs" %} -
  • -
  • -
    - {% trans "Use HTTPS in production environments" %} -
  • -
-
- -
-

-
- -
- {% trans "Security Vulnerability Reporting" %} -

-

{% trans "If you discover a security vulnerability, please report it responsibly" %}

-
    -
  • -
    - {% trans "Email: security@cyberpanel.net" %} -
  • -
  • -
    - {% trans "GitHub: Create a private security issue" %} -
  • -
  • -
    - {% trans "Response time: Within 24-48 hours" %} -
  • -
-
- -

{% trans "Security Audit Results" %}

-

{% trans "This plugin has been designed with security as a top priority. All major security vulnerabilities have been addressed:" %}

- -
    -
  • -
    - {% trans "OWASP Top 10 vulnerabilities addressed" %} -
  • -
  • -
    - {% trans "No SQL injection vulnerabilities" %} -
  • -
  • -
    - {% trans "No XSS vulnerabilities" %} -
  • -
  • -
    - {% trans "No CSRF vulnerabilities" %} -
  • -
  • -
    - {% trans "No authentication bypass vulnerabilities" %} -
  • -
  • -
    - {% trans "No authorization bypass vulnerabilities" %} -
  • -
  • -
    - {% trans "No information disclosure vulnerabilities" %} -
  • -
  • -
    - {% trans "No path traversal vulnerabilities" %} -
  • -
- -
- {% trans "Security Note:" %} {% trans "This plugin implements enterprise-grade security measures. However, security is an ongoing process. Regular updates and monitoring are essential to maintain the highest security standards." %} -
-
-
-
-{% endblock %} diff --git a/testPlugin/templates/testPlugin/settings.html b/testPlugin/templates/testPlugin/settings.html deleted file mode 100644 index e06f901f4..000000000 --- a/testPlugin/templates/testPlugin/settings.html +++ /dev/null @@ -1,165 +0,0 @@ -{% extends "baseTemplate/index.html" %} -{% load static %} -{% load i18n %} - -{% block title %} - Test Plugin Settings - {% trans "CyberPanel" %} -{% endblock %} - -{% block content %} -
-
-
-
-
-

- - {% trans "Test Plugin Settings" %} -

-
-
-
- - {% trans "Plugin Information" %} -
    -
  • {% trans "Name" %}: {{ plugin_name }}
  • -
  • {% trans "Version" %}: {{ version }}
  • -
  • {% trans "Status" %}: {% trans "Active" %}
  • -
-
- -
-
-

- - {% trans "Configuration Options" %} -

-
-
-
- {% csrf_token %} - -
- -
- - -
- - {% trans "This is a test setting for demonstration purposes." %} - -
- -
- - - - {% trans "This is a test text input field." %} - -
- -
- - - - {% trans "Select a test option from the dropdown." %} - -
- -
- - -
-
-
-
- -
-
-

- - {% trans "Plugin Status" %} -

-
-
-
- - {% trans "Plugin is Active" %} -

{% trans "The Test Plugin is installed and working correctly." %}

-
- -
-
-
- - - -
- {% trans "Plugin Name" %} - {{ plugin_name }} -
-
-
-
-
- - - -
- {% trans "Version" %} - {{ version }} -
-
-
-
-
-
- -
-
-

- - {% trans "About This Plugin" %} -

-
-
-

{{ description }}

-

{% trans "This is a test plugin created for testing CyberPanel plugin functionality. You can use this plugin to verify that the plugin system is working correctly." %}

- -
{% trans "Features" %}
-
    -
  • {% trans "Enable/disable functionality" %}
  • -
  • {% trans "Test button" %}
  • -
  • {% trans "Popup messages" %}
  • -
  • {% trans "Inline integration" %}
  • -
  • {% trans "Settings page" %}
  • -
-
-
-
-
-
-
-
-{% endblock %} diff --git a/testPlugin/test_os_compatibility.py b/testPlugin/test_os_compatibility.py deleted file mode 100644 index 46c6d5dc6..000000000 --- a/testPlugin/test_os_compatibility.py +++ /dev/null @@ -1,446 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -OS Compatibility Test Script for Test Plugin -Tests the plugin on different operating systems -""" -import os -import sys -import subprocess -import platform -import json -from pathlib import Path - -# Add the plugin directory to Python path -plugin_dir = Path(__file__).parent -sys.path.insert(0, str(plugin_dir)) - -from os_config import OSConfig - - -class OSCompatibilityTester: - """Test OS compatibility for the Test Plugin""" - - def __init__(self): - self.os_config = OSConfig() - self.test_results = {} - - def run_all_tests(self): - """Run all compatibility tests""" - print("šŸ” Testing OS Compatibility for CyberPanel Test Plugin") - print("=" * 60) - - # Test 1: OS Detection - self.test_os_detection() - - # Test 2: Python Detection - self.test_python_detection() - - # Test 3: Package Manager Detection - self.test_package_manager_detection() - - # Test 4: Service Manager Detection - self.test_service_manager_detection() - - # Test 5: Web Server Detection - self.test_web_server_detection() - - # Test 6: File Permissions - self.test_file_permissions() - - # Test 7: Network Connectivity - self.test_network_connectivity() - - # Test 8: CyberPanel Integration - self.test_cyberpanel_integration() - - # Display results - self.display_results() - - return self.test_results - - def test_os_detection(self): - """Test OS detection functionality""" - print("\nšŸ“‹ Testing OS Detection...") - - try: - os_info = self.os_config.get_os_info() - is_supported = self.os_config.is_supported_os() - - self.test_results['os_detection'] = { - 'status': 'PASS', - 'os_name': os_info['name'], - 'os_version': os_info['version'], - 'os_arch': os_info['architecture'], - 'is_supported': is_supported, - 'platform': os_info['platform'] - } - - print(f" āœ… OS: {os_info['name']} {os_info['version']} ({os_info['architecture']})") - print(f" āœ… Supported: {is_supported}") - - except Exception as e: - self.test_results['os_detection'] = { - 'status': 'FAIL', - 'error': str(e) - } - print(f" āŒ Error: {e}") - - def test_python_detection(self): - """Test Python detection and version""" - print("\nšŸ Testing Python Detection...") - - try: - python_path = self.os_config.python_path - pip_path = self.os_config.pip_path - - # Test Python version - result = subprocess.run([python_path, '--version'], - capture_output=True, text=True, timeout=10) - - if result.returncode == 0: - version = result.stdout.strip() - version_num = version.split()[1] - major, minor = map(int, version_num.split('.')[:2]) - - is_compatible = major == 3 and minor >= 6 - - self.test_results['python_detection'] = { - 'status': 'PASS' if is_compatible else 'WARN', - 'python_path': python_path, - 'pip_path': pip_path, - 'version': version, - 'is_compatible': is_compatible - } - - print(f" āœ… Python: {version}") - print(f" āœ… Path: {python_path}") - print(f" āœ… Pip: {pip_path}") - print(f" {'āœ…' if is_compatible else 'āš ļø'} Compatible: {is_compatible}") - - else: - raise Exception("Python not working properly") - - except Exception as e: - self.test_results['python_detection'] = { - 'status': 'FAIL', - 'error': str(e) - } - print(f" āŒ Error: {e}") - - def test_package_manager_detection(self): - """Test package manager detection""" - print("\nšŸ“¦ Testing Package Manager Detection...") - - try: - package_manager = self.os_config.package_manager - config = self.os_config.get_os_specific_config() - - # Test if package manager is available - if package_manager in ['apt-get', 'apt']: - test_cmd = ['apt', '--version'] - elif package_manager == 'dnf': - test_cmd = ['dnf', '--version'] - elif package_manager == 'yum': - test_cmd = ['yum', '--version'] - else: - test_cmd = None - - is_available = True - if test_cmd: - try: - result = subprocess.run(test_cmd, capture_output=True, text=True, timeout=5) - is_available = result.returncode == 0 - except: - is_available = False - - self.test_results['package_manager'] = { - 'status': 'PASS' if is_available else 'WARN', - 'package_manager': package_manager, - 'is_available': is_available, - 'config': config - } - - print(f" āœ… Package Manager: {package_manager}") - print(f" {'āœ…' if is_available else 'āš ļø'} Available: {is_available}") - - except Exception as e: - self.test_results['package_manager'] = { - 'status': 'FAIL', - 'error': str(e) - } - print(f" āŒ Error: {e}") - - def test_service_manager_detection(self): - """Test service manager detection""" - print("\nšŸ”§ Testing Service Manager Detection...") - - try: - service_manager = self.os_config.service_manager - web_server = self.os_config.web_server - - # Test if service manager is available - if service_manager == 'systemctl': - test_cmd = ['systemctl', '--version'] - elif service_manager == 'service': - test_cmd = ['service', '--version'] - else: - test_cmd = None - - is_available = True - if test_cmd: - try: - result = subprocess.run(test_cmd, capture_output=True, text=True, timeout=5) - is_available = result.returncode == 0 - except: - is_available = False - - self.test_results['service_manager'] = { - 'status': 'PASS' if is_available else 'WARN', - 'service_manager': service_manager, - 'web_server': web_server, - 'is_available': is_available - } - - print(f" āœ… Service Manager: {service_manager}") - print(f" āœ… Web Server: {web_server}") - print(f" {'āœ…' if is_available else 'āš ļø'} Available: {is_available}") - - except Exception as e: - self.test_results['service_manager'] = { - 'status': 'FAIL', - 'error': str(e) - } - print(f" āŒ Error: {e}") - - def test_web_server_detection(self): - """Test web server detection""" - print("\n🌐 Testing Web Server Detection...") - - try: - web_server = self.os_config.web_server - - # Check if web server is installed - if web_server == 'apache2': - config_paths = ['/etc/apache2/apache2.conf', '/etc/apache2/httpd.conf'] - else: # httpd - config_paths = ['/etc/httpd/conf/httpd.conf', '/etc/httpd/conf.d'] - - is_installed = any(os.path.exists(path) for path in config_paths) - - self.test_results['web_server'] = { - 'status': 'PASS' if is_installed else 'WARN', - 'web_server': web_server, - 'is_installed': is_installed, - 'config_paths': config_paths - } - - print(f" āœ… Web Server: {web_server}") - print(f" {'āœ…' if is_installed else 'āš ļø'} Installed: {is_installed}") - - except Exception as e: - self.test_results['web_server'] = { - 'status': 'FAIL', - 'error': str(e) - } - print(f" āŒ Error: {e}") - - def test_file_permissions(self): - """Test file permissions and ownership""" - print("\nšŸ” Testing File Permissions...") - - try: - # Test if we can create files in plugin directory - plugin_dir = "/home/cyberpanel/plugins" - cyberpanel_dir = "/usr/local/CyberCP" - - can_create_plugin_dir = True - can_create_cyberpanel_dir = True - - try: - os.makedirs(plugin_dir, exist_ok=True) - except PermissionError: - can_create_plugin_dir = False - - try: - os.makedirs(f"{cyberpanel_dir}/test", exist_ok=True) - os.rmdir(f"{cyberpanel_dir}/test") - except PermissionError: - can_create_cyberpanel_dir = False - - self.test_results['file_permissions'] = { - 'status': 'PASS' if can_create_plugin_dir and can_create_cyberpanel_dir else 'WARN', - 'can_create_plugin_dir': can_create_plugin_dir, - 'can_create_cyberpanel_dir': can_create_cyberpanel_dir, - 'plugin_dir': plugin_dir, - 'cyberpanel_dir': cyberpanel_dir - } - - print(f" {'āœ…' if can_create_plugin_dir else 'āš ļø'} Plugin Directory: {plugin_dir}") - print(f" {'āœ…' if can_create_cyberpanel_dir else 'āš ļø'} CyberPanel Directory: {cyberpanel_dir}") - - except Exception as e: - self.test_results['file_permissions'] = { - 'status': 'FAIL', - 'error': str(e) - } - print(f" āŒ Error: {e}") - - def test_network_connectivity(self): - """Test network connectivity""" - print("\nšŸŒ Testing Network Connectivity...") - - try: - # Test GitHub connectivity - github_result = subprocess.run(['curl', '-s', '--connect-timeout', '10', - 'https://github.com'], - capture_output=True, text=True, timeout=15) - github_available = github_result.returncode == 0 - - # Test general internet connectivity - internet_result = subprocess.run(['curl', '-s', '--connect-timeout', '10', - 'https://www.google.com'], - capture_output=True, text=True, timeout=15) - internet_available = internet_result.returncode == 0 - - self.test_results['network_connectivity'] = { - 'status': 'PASS' if github_available and internet_available else 'WARN', - 'github_available': github_available, - 'internet_available': internet_available - } - - print(f" {'āœ…' if github_available else 'āš ļø'} GitHub: {github_available}") - print(f" {'āœ…' if internet_available else 'āš ļø'} Internet: {internet_available}") - - except Exception as e: - self.test_results['network_connectivity'] = { - 'status': 'FAIL', - 'error': str(e) - } - print(f" āŒ Error: {e}") - - def test_cyberpanel_integration(self): - """Test CyberPanel integration""" - print("\n⚔ Testing CyberPanel Integration...") - - try: - cyberpanel_dir = "/usr/local/CyberCP" - - # Check if CyberPanel is installed - cyberpanel_installed = os.path.exists(cyberpanel_dir) - - # Check if Django settings exist - settings_file = f"{cyberpanel_dir}/cyberpanel/settings.py" - settings_exist = os.path.exists(settings_file) - - # Check if URLs file exists - urls_file = f"{cyberpanel_dir}/cyberpanel/urls.py" - urls_exist = os.path.exists(urls_file) - - # Check if lscpd service exists - lscpd_exists = os.path.exists("/usr/local/lscp/bin/lscpd") - - self.test_results['cyberpanel_integration'] = { - 'status': 'PASS' if cyberpanel_installed and settings_exist and urls_exist else 'WARN', - 'cyberpanel_installed': cyberpanel_installed, - 'settings_exist': settings_exist, - 'urls_exist': urls_exist, - 'lscpd_exists': lscpd_exists - } - - print(f" {'āœ…' if cyberpanel_installed else 'āš ļø'} CyberPanel Installed: {cyberpanel_installed}") - print(f" {'āœ…' if settings_exist else 'āš ļø'} Settings File: {settings_exist}") - print(f" {'āœ…' if urls_exist else 'āš ļø'} URLs File: {urls_exist}") - print(f" {'āœ…' if lscpd_exists else 'āš ļø'} LSCPD Service: {lscpd_exists}") - - except Exception as e: - self.test_results['cyberpanel_integration'] = { - 'status': 'FAIL', - 'error': str(e) - } - print(f" āŒ Error: {e}") - - def display_results(self): - """Display test results summary""" - print("\n" + "=" * 60) - print("šŸ“Š COMPATIBILITY TEST RESULTS") - print("=" * 60) - - total_tests = len(self.test_results) - passed_tests = sum(1 for result in self.test_results.values() if result['status'] == 'PASS') - warned_tests = sum(1 for result in self.test_results.values() if result['status'] == 'WARN') - failed_tests = sum(1 for result in self.test_results.values() if result['status'] == 'FAIL') - - print(f"Total Tests: {total_tests}") - print(f"āœ… Passed: {passed_tests}") - print(f"āš ļø Warnings: {warned_tests}") - print(f"āŒ Failed: {failed_tests}") - - if failed_tests == 0: - print("\nšŸŽ‰ All tests passed! The plugin is compatible with this OS.") - elif warned_tests > 0 and failed_tests == 0: - print("\nāš ļø Some warnings detected. The plugin should work but may need attention.") - else: - print("\nāŒ Some tests failed. The plugin may not work properly on this OS.") - - # Show detailed results - print("\nšŸ“‹ Detailed Results:") - for test_name, result in self.test_results.items(): - status_icon = {'PASS': 'āœ…', 'WARN': 'āš ļø', 'FAIL': 'āŒ'}[result['status']] - print(f" {status_icon} {test_name.replace('_', ' ').title()}: {result['status']}") - if 'error' in result: - print(f" Error: {result['error']}") - - # Generate compatibility report - self.generate_compatibility_report() - - def generate_compatibility_report(self): - """Generate a compatibility report file""" - try: - report = { - 'timestamp': time.time(), - 'os_info': self.os_config.get_os_info(), - 'test_results': self.test_results, - 'compatibility_score': self.calculate_compatibility_score() - } - - report_file = "compatibility_report.json" - with open(report_file, 'w') as f: - json.dump(report, f, indent=2) - - print(f"\nšŸ“„ Compatibility report saved to: {report_file}") - - except Exception as e: - print(f"\nāš ļø Could not save compatibility report: {e}") - - def calculate_compatibility_score(self): - """Calculate overall compatibility score""" - total_tests = len(self.test_results) - if total_tests == 0: - return 0 - - score = 0 - for result in self.test_results.values(): - if result['status'] == 'PASS': - score += 1 - elif result['status'] == 'WARN': - score += 0.5 - - return round((score / total_tests) * 100, 1) - - -def main(): - """Main function""" - tester = OSCompatibilityTester() - results = tester.run_all_tests() - - # Exit with appropriate code - failed_tests = sum(1 for result in results.values() if result['status'] == 'FAIL') - if failed_tests > 0: - sys.exit(1) - else: - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/testPlugin/urls.py b/testPlugin/urls.py deleted file mode 100644 index 8c2a41a90..000000000 --- a/testPlugin/urls.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.urls import path -from . import views - -urlpatterns = [ - path('', views.test_plugin_view, name='testPlugin'), - path('info/', views.plugin_info_view, name='testPluginInfo'), - path('settings/', views.settings_view, name='testPluginSettings'), -] diff --git a/testPlugin/views.py b/testPlugin/views.py deleted file mode 100644 index 07bc88899..000000000 --- a/testPlugin/views.py +++ /dev/null @@ -1,54 +0,0 @@ -from django.shortcuts import render, redirect -from django.http import JsonResponse -from functools import wraps - -def cyberpanel_login_required(view_func): - """ - Custom decorator that checks for CyberPanel session userID - """ - @wraps(view_func) - def _wrapped_view(request, *args, **kwargs): - try: - userID = request.session['userID'] - # User is authenticated via CyberPanel session - return view_func(request, *args, **kwargs) - except KeyError: - # Not logged in, redirect to login - return redirect('/') - return _wrapped_view - -@cyberpanel_login_required -def test_plugin_view(request): - """ - Main view for the test plugin - """ - context = { - 'plugin_name': 'Test Plugin', - 'version': '1.0.0', - 'description': 'A simple test plugin for CyberPanel' - } - return render(request, 'testPlugin/index.html', context) - -@cyberpanel_login_required -def plugin_info_view(request): - """ - API endpoint for plugin information - """ - return JsonResponse({ - 'plugin_name': 'Test Plugin', - 'version': '1.0.0', - 'status': 'active', - 'description': 'A simple test plugin for CyberPanel testing' - }) - -@cyberpanel_login_required -def settings_view(request): - """ - Settings page for the test plugin - """ - context = { - 'plugin_name': 'Test Plugin', - 'version': '1.0.0', - 'description': 'A simple test plugin for CyberPanel' - } - return render(request, 'testPlugin/settings.html', context)