HEX
Server: LiteSpeed
System: Linux php-prod-1.spaceapp.ru 5.15.0-157-generic #167-Ubuntu SMP Wed Sep 17 21:35:53 UTC 2025 x86_64
User: xnsbb3110 (1041)
PHP: 8.1.33
Disabled: NONE
Upload Files
File: //usr/local/CyberCP/plogical/backupUtilities.py
import json
import os
import sys
import paramiko
sys.path.append('/usr/local/CyberCP')
import django

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings")
try:
    django.setup()
    from ApachController.ApacheVhosts import ApacheVhost
    from plogical.acl import ACLManager
except:
    pass



from plogical.randomPassword import generate_pass
import pexpect
from plogical import CyberCPLogFileWriter as logging
import subprocess
import shlex
from shutil import make_archive, rmtree
from plogical import mysqlUtilities
import tarfile
from multiprocessing import Process
import signal
from plogical.installUtilities import installUtilities
import argparse

try:
    from plogical.virtualHostUtilities import virtualHostUtilities
    from plogical.sslUtilities import sslUtilities
    from plogical.mailUtilities import mailUtilities
except:
    pass

from xml.etree.ElementTree import Element, SubElement
from xml.etree import ElementTree
from xml.dom import minidom
import time
from shutil import copy
from random import randint
from plogical.processUtilities import ProcessUtilities

try:
    from websiteFunctions.models import Websites, ChildDomains, Backups, NormalBackupDests
    from databases.models import Databases
    from loginSystem.models import Administrator
    from plogical.dnsUtilities import DNS
    from mailServer.models import Domains as eDomains
    from backup.models import DBUsers
except:
    pass

VERSION = '2.4'
BUILD = 4


## I am not the monster that you think I am..

class backupUtilities:
    Server_root = "/usr/local/lsws"
    completeKeyPath = "/home/cyberpanel/.ssh"
    destinationsPath = "/home/cyberpanel/destinations"
    licenseKey = '/usr/local/lsws/conf/license.key'
    NiceDefault = '10'
    CPUDefault = '1000'
    CloudBackupConfigPath = '/home/cyberpanel/CloudBackup.json'
    time = 10

    def __init__(self, extraArgs):
        self.extraArgs = extraArgs

    @staticmethod
    def prepareBackupMeta(backupDomain, backupName, tempStoragePath, backupPath, FromInner=1):
        try:

            website = Websites.objects.get(domain=backupDomain)

            connection, cursor = mysqlUtilities.mysqlUtilities.setupConnection()

            if FromInner:
                status = os.path.join(backupPath, 'status')
                #logging.CyberCPLogFileWriter.statusWriter(status, 'Setting up meta data..')
                command = f"echo 'Setting up meta data..' > {status}"
                ProcessUtilities.executioner(command, website.externalApp)
            else:
                status = '/home/cyberpanel/dummy'

            if os.path.exists(ProcessUtilities.debugPath):
                logging.CyberCPLogFileWriter.writeToFile(f'Creating meta for {backupDomain}.')

            ######### Generating meta

            ## XML Generation

            metaFileXML = Element('metaFile')

            child = SubElement(metaFileXML, 'VERSION')
            child.text = VERSION

            child = SubElement(metaFileXML, 'BUILD')
            child.text = str(BUILD)

            ### try to take care of - https://github.com/usmannasir/cyberpanel/issues/1196

            child = SubElement(metaFileXML, 'BackupWholeDir')
            child.text = str(1)

            child = SubElement(metaFileXML, 'masterDomain')
            child.text = backupDomain

            child = SubElement(metaFileXML, 'phpSelection')
            child.text = website.phpSelection

            child = SubElement(metaFileXML, 'externalApp')
            child.text = website.externalApp

            ### Find user of site

            siteUser = website.admin

            child = SubElement(metaFileXML, 'userName')
            child.text = siteUser.userName

            child = SubElement(metaFileXML, 'userPassword')
            child.text = siteUser.password

            child = SubElement(metaFileXML, 'firstName')
            child.text = siteUser.firstName

            child = SubElement(metaFileXML, 'lastName')
            child.text = siteUser.lastName

            child = SubElement(metaFileXML, 'email')
            child.text = siteUser.email

            child = SubElement(metaFileXML, 'type')
            child.text = str(siteUser.type)

            child = SubElement(metaFileXML, 'owner')
            child.text = str(siteUser.owner)

            child = SubElement(metaFileXML, 'token')
            child.text = siteUser.token

            child = SubElement(metaFileXML, 'api')
            child.text = str(siteUser.api)

            child = SubElement(metaFileXML, 'securityLevel')
            child.text = str(siteUser.securityLevel)

            child = SubElement(metaFileXML, 'state')
            child.text = siteUser.state

            child = SubElement(metaFileXML, 'initWebsitesLimit')
            child.text = str(siteUser.initWebsitesLimit)

            child = SubElement(metaFileXML, 'aclName')
            child.text = siteUser.acl.name

            #####################

            childDomains = website.childdomains_set.all()

            databases = website.databases_set.all()

            ## Child domains XML

            childDomainsXML = Element('ChildDomains')

            for items in childDomains:
                childDomainXML = Element('domain')

                child = SubElement(childDomainXML, 'domain')
                child.text = items.domain
                child = SubElement(childDomainXML, 'phpSelection')
                child.text = items.phpSelection
                child = SubElement(childDomainXML, 'path')
                child.text = items.path

                childDomainsXML.append(childDomainXML)

            metaFileXML.append(childDomainsXML)

            ## Databases XML

            databasesXML = Element('Databases')

            for items in databases:

                databaseXML = Element('database')

                child = SubElement(databaseXML, 'dbName')
                child.text = str(items.dbName)

                cursor.execute(f"select user,host from mysql.db where db='{items.dbName}'")
                databaseUsers = cursor.fetchall()

                for databaseUser in databaseUsers:

                    databaseUserXML = Element('databaseUsers')

                    child = SubElement(databaseUserXML, 'dbUser')
                    child.text = databaseUser[0]

                    child = SubElement(databaseUserXML, 'dbHost')
                    child.text = databaseUser[1]

                    ## Fetch user password
                    dbuser = DBUsers.objects.get(user=databaseUser[0], host=databaseUser[1])
                    child = SubElement(databaseUserXML, 'password')
                    child.text = str(dbuser.password)

                    databaseXML.append(databaseUserXML)

                databasesXML.append(databaseXML)

            metaFileXML.append(databasesXML)

            ## Get Aliases

            try:

                aliasesXML = Element('Aliases')

                aliases = backupUtilities.getAliases(backupDomain)

                for items in aliases:
                    child = SubElement(aliasesXML, 'alias')
                    child.text = items

                metaFileXML.append(aliasesXML)
            except BaseException as msg:
                logging.CyberCPLogFileWriter.writeToFile('%s. [167:prepMeta]' % (str(msg)))

            ## Finish Alias

            ## DNS Records XML

            try:

                dnsRecordsXML = Element("dnsrecords")
                dnsRecords = DNS.getDNSRecords(backupDomain)

                for items in dnsRecords:
                    dnsRecordXML = Element('dnsrecord')

                    child = SubElement(dnsRecordXML, 'type')
                    child.text = items.type
                    child = SubElement(dnsRecordXML, 'name')
                    child.text = items.name
                    child = SubElement(dnsRecordXML, 'content')
                    child.text = items.content
                    child = SubElement(dnsRecordXML, 'priority')
                    child.text = str(items.prio)

                    dnsRecordsXML.append(dnsRecordXML)

                metaFileXML.append(dnsRecordsXML)
            except BaseException as msg:
                logging.CyberCPLogFileWriter.writeToFile('%s. [158:prepMeta]' % (str(msg)))

            ## Email accounts XML

            try:
                emailRecordsXML = Element('emails')
                eDomain = eDomains.objects.get(domain=backupDomain)
                emailAccounts = eDomain.eusers_set.all()

                for items in emailAccounts:
                    emailRecordXML = Element('emailAccount')

                    child = SubElement(emailRecordXML, 'email')
                    child.text = items.email
                    child = SubElement(emailRecordXML, 'password')
                    child.text = items.password

                    emailRecordsXML.append(emailRecordXML)

                metaFileXML.append(emailRecordsXML)
            except BaseException as msg:
                logging.CyberCPLogFileWriter.writeToFile('%s. [179:prepMeta]' % (str(msg)))

            ## Email meta generated!

            def prettify(elem):
                """Return a pretty-printed XML string for the Element.
                """
                rough_string = ElementTree.tostring(elem, 'utf-8')
                reparsed = minidom.parseString(rough_string)
                return reparsed.toprettyxml(indent="  ")

            ## /home/example.com/backup/backup-example.com-02.13.2018_10-24-52/meta.xml -- metaPath

            metaPath = '/tmp/%s' % (str(randint(1000, 9999)))

            if os.path.exists(ProcessUtilities.debugPath):
                logging.CyberCPLogFileWriter.writeToFile(f'Path to meta file {metaPath}')

            xmlpretty = prettify(metaFileXML).encode('ascii', 'ignore')
            metaFile = open(metaPath, 'w')
            metaFile.write(xmlpretty.decode())
            metaFile.close()
            os.chmod(metaPath, 0o600)

            ## meta generated

            if FromInner:
                newBackup = Backups(website=website, fileName=backupName, date=time.strftime("%m.%d.%Y_%H-%M-%S"),
                                    size=0, status=1)
                newBackup.save()

                command = f"echo 'Meta data is ready..' > {status}"
                ProcessUtilities.executioner(command, website.externalApp)

            return 1, 'None', metaPath

        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(f"{str(msg)} [207][5009]")
            if FromInner:
                #logging.CyberCPLogFileWriter.statusWriter(status, "%s [207][5009]" % (str(msg)), status)
                command = f"echo '{status} [207][5009]' > {status}"
                ProcessUtilities.executioner(command, website.externalApp)
            return 0, str(msg), 'None'

    @staticmethod
    def startBackup(tempStoragePath, backupName, backupPath, metaPath=None):
        try:

            ## /home/example.com/backup/backup-example.com-02.13.2018_10-24-52 -- tempStoragePath
            ## /home/example.com/backup - backupPath

            ##### Writing the name of backup file.

            ## /home/example.com/backup/backupFileName
            pidFile = f'{backupPath}startBackup'
            writeToFile = open(pidFile, 'w')
            writeToFile.writelines(str(os.getpid()))
            writeToFile.close()

            backupFileNamePath = os.path.join(backupPath, "backupFileName")
            logging.CyberCPLogFileWriter.statusWriter(backupFileNamePath, backupName)

            #####

            status = os.path.join(backupPath, 'status')

            logging.CyberCPLogFileWriter.statusWriter(status, "Making archive of home directory.\n")

            ##### Parsing XML Meta file!

            ## /home/example.com/backup/backup-example.com-02.13.2018_10-24-52 -- tempStoragePath

            metaPathInBackup = os.path.join(tempStoragePath, 'meta.xml')

            if metaPath != None:
                writeToFile = open(metaPathInBackup, 'w')
                writeToFile.write(open(metaPath, 'r').read())
                writeToFile.close()

            backupMetaData = ElementTree.parse(metaPathInBackup)

            ##### Making archive of home directory

            domainName = backupMetaData.find('masterDomain').text

            ## Saving original vhost conf file

            #completPathToConf = f'{backupUtilities.Server_root}/conf/vhosts/{domainName}/vhost.conf'

            #copy(completPathToConf, tempStoragePath + '/vhost.conf')

            ## /home/example.com/backup/backup-example.com-02.13.2018_10-24-52 -- tempStoragePath
            ## shutil.make_archive

            ## Stop making archive of document_root and copy instead

            from shutil import copytree

            #copytree('/home/%s/public_html' % domainName, '%s/%s' % (tempStoragePath, 'public_html'))
            #command = f'cp -R /home/{domainName}/public_html {tempStoragePath}/public_html'
            ### doing backup of whole dir and keeping it in public_html folder will restore from here - ref https://github.com/usmannasir/cyberpanel/issues/1196
            command = f"rsync -av --ignore-errors --exclude=.wp-cli --exclude=logs --exclude=backup --exclude=lscache /home/{domainName}/ {tempStoragePath}/public_html/"
            ProcessUtilities.normalExecutioner(command)
            # if ProcessUtilities.normalExecutioner(command) == 0:
            #      raise BaseException(f'Failed to run cp command during backup generation.')

            # make_archive(os.path.join(tempStoragePath,"public_html"), 'gztar', os.path.join("/home",domainName,"public_html"))

            ##

            logging.CyberCPLogFileWriter.statusWriter(status, "Backing up databases..")
            print('1,None')

        except BaseException as msg:
            # try:
            #     os.remove(os.path.join(backupPath, backupName + ".tar.gz"))
            # except:
            #     pass
            #
            # try:
            #     rmtree(tempStoragePath)
            # except:
            #     pass

            status = os.path.join(backupPath, 'status')
            logging.CyberCPLogFileWriter.statusWriter(status, "Aborted, " + str(msg) + ".[365] [5009]")
            print(f"Aborted, {str(msg)}.[365] [5009]")
        try:
            os.remove(pidFile)
        except:
            pass

    @staticmethod
    def BackupRoot(tempStoragePath, backupName, backupPath, metaPath=None, externalApp = None, CPHomeStorage=None):

        ## /home/example.com/backup/backup-example.com-02.13.2018_10-24-52 -- tempStoragePath
        ## /home/example.com/backup - backupPath
        ## /home/backup/<random_number> - CPHomeStorage

        ### CPHomeStorage /home/cyberpanel/<random_number>


        pidFile = '%sBackupRoot' % (backupPath)

        writeToFile = open(pidFile, 'w')
        writeToFile.writelines(str(os.getpid()))
        writeToFile.close()

        status = os.path.join(backupPath, 'status')
        metaPathInBackup = os.path.join(tempStoragePath, 'meta.xml')
        backupMetaData = ElementTree.parse(metaPathInBackup)

        domainName = backupMetaData.find('masterDomain').text
        ##### Saving SSL Certificates if any

        sslStoragePath = '/etc/letsencrypt/live/' + domainName

        if os.path.exists(sslStoragePath):
            try:

                copy(os.path.join(sslStoragePath, "cert.pem"), os.path.join(CPHomeStorage, domainName + ".cert.pem"))

                copy(os.path.join(sslStoragePath, "fullchain.pem"),os.path.join(CPHomeStorage, domainName + ".fullchain.pem"))

                copy(os.path.join(sslStoragePath, "privkey.pem"),os.path.join(CPHomeStorage, domainName + ".privkey.pem"))

            except BaseException as msg:
                logging.CyberCPLogFileWriter.writeToFile(f'{str(msg)}. [283:startBackup]')

        ## Child Domains SSL.

        ## For master domain copy the conf file to tempStorage path here it was done above, but since it is root operation it should be performed here

        completPathToConf = f'{backupUtilities.Server_root}/conf/vhosts/{domainName}/vhost.conf'

        ### If domain is suspended, this path wont exists, so please check for other


        if os.path.exists(completPathToConf):
            copy(completPathToConf, f'{CPHomeStorage}/vhost.conf')
        else:
            completPathToConf = f'{backupUtilities.Server_root}/conf/vhosts/{domainName}-suspended/vhost.conf'
            if os.path.exists(completPathToConf):
                #copy(completPathToConf, tempStoragePath + '/vhost.conf')

                copy(completPathToConf, f'{CPHomeStorage}/vhost.conf')

        #### also backup apache conf if available
        from ApachController.ApacheVhosts import ApacheVhost

        finalConfPathApache = ApacheVhost.configBasePath + domainName + '.conf'

        if os.path.exists(finalConfPathApache):
            copy(finalConfPathApache, f'{CPHomeStorage}/apache.conf')

        childDomains = backupMetaData.findall('ChildDomains/domain')

        try:
            for childDomain in childDomains:

                actualChildDomain = childDomain.find('domain').text
                childPath = childDomain.find('path').text


                completPathToConf = f'{backupUtilities.Server_root}/conf/vhosts/{actualChildDomain}/vhost.conf'
                TempConfPath = f'/home/cyberpanel/{actualChildDomain}.vhost.conf'

                if os.path.exists(completPathToConf):
                    #copy(completPathToConf, f'{tempStoragePath}/{actualChildDomain}.vhost.conf')
                    copy(completPathToConf, f'{CPHomeStorage}/{actualChildDomain}.vhost.conf')

                else:
                    completPathToConf = f'{backupUtilities.Server_root}/conf/vhosts/{actualChildDomain}-suspended/vhost.conf'
                    if os.path.exists(completPathToConf):
                        #copy(completPathToConf, f'{tempStoragePath}/{actualChildDomain}.vhost.conf')
                        copy(completPathToConf, f'{CPHomeStorage}/{actualChildDomain}.vhost.conf')

                ### also backup apache conf if available

                finalConfPathApacheChild = ApacheVhost.configBasePath + actualChildDomain + '.conf'

                if os.path.exists(finalConfPathApacheChild):
                    copy(finalConfPathApacheChild, f'{CPHomeStorage}/{actualChildDomain}.apache.conf')

                ##

                ### Storing SSL for child domainsa

                sslStoragePath = f'/etc/letsencrypt/live/{actualChildDomain}'

                if os.path.exists(sslStoragePath):
                    try:

                        #copy(os.path.join(sslStoragePath, "cert.pem"), os.path.join(tempStoragePath, actualChildDomain + ".cert.pem"))
                        copy(os.path.join(sslStoragePath, "cert.pem"),os.path.join(CPHomeStorage, actualChildDomain + ".cert.pem"))

                        #copy(os.path.join(sslStoragePath, "fullchain.pem"),os.path.join(tempStoragePath, actualChildDomain + ".fullchain.pem"))
                        copy(os.path.join(sslStoragePath, "fullchain.pem"),os.path.join(CPHomeStorage, actualChildDomain + ".fullchain.pem"))

                        #copy(os.path.join(sslStoragePath, "privkey.pem"),os.path.join(tempStoragePath, actualChildDomain + ".privkey.pem"))
                        copy(os.path.join(sslStoragePath, "privkey.pem"),os.path.join(CPHomeStorage, actualChildDomain + ".privkey.pem"))

                        #make_archive(os.path.join(tempStoragePath, "sslData-" + domainName), 'gztar', sslStoragePath)
                    except:
                        pass
                ## no need to do this as on line 380 whole dir will be backuped up

                # if childPath.find(f'/home/{domainName}/public_html') == -1:
                #     # copy_tree(childPath, '%s/%s-docroot' % (tempStoragePath, actualChildDomain))
                #     command = f'cp -R {childPath} {tempStoragePath}/{actualChildDomain}-docroot'
                #     ProcessUtilities.executioner(command, externalApp)
        except BaseException as msg:
            pass

        ## backup emails

        domainName = backupMetaData.find('masterDomain').text

        if os.path.islink(status) or os.path.islink(tempStoragePath or os.path.islink(backupPath)) or os.path.islink(
                metaPath):
            logging.CyberCPLogFileWriter.writeToFile('symlinked.')
            #logging.CyberCPLogFileWriter.statusWriter(status, 'Symlink attack. [365][5009]')
            return 0

        ## backup email accounts

        if externalApp == None:
            logging.CyberCPLogFileWriter.statusWriter(status, "Backing up email accounts..\n")
        else:
            command = f"echo 'Backing up email accounts..' > {status}"
            ProcessUtilities.executioner(command, externalApp)

        try:

            emailPath = f'/home/vmail/{domainName}'

            if os.path.exists(emailPath):
                # copy_tree(emailPath, '%s/vmail' % (tempStoragePath), preserve_symlinks=True)
                command = f'cp -R {emailPath} {CPHomeStorage}/vmail'
                ProcessUtilities.executioner(command)

            ## shutil.make_archive. Creating final package.

            if externalApp == None:
                logging.CyberCPLogFileWriter.statusWriter(status, "Preparing final compressed package..\n")
            else:
                command = f"echo 'Preparing final compressed package..' > {status}"
                ProcessUtilities.executioner(command, externalApp, True)


            ### change own of CPHomeStorage and move data

            command = f'chown -R {externalApp}:{externalApp} {CPHomeStorage}'
            ProcessUtilities.executioner(command)

            command = f'mv {CPHomeStorage}/* {tempStoragePath}/'
            ProcessUtilities.executioner(command, externalApp, True)

            #make_archive(os.path.join(backupPath, backupName), 'gztar', tempStoragePath)
            #rmtree(tempStoragePath)

            command = f'tar -czf {backupPath}/{backupName}.tar.gz -C {tempStoragePath} .'
            ProcessUtilities.executioner(command, externalApp, True)

            ### remove leftover storages

            command = f'rm -rf {tempStoragePath}'
            ProcessUtilities.executioner(command, externalApp)

            command = f'rm -rf {CPHomeStorage}'
            ProcessUtilities.executioner(command)

            ###

            backupObs = Backups.objects.filter(fileName=backupName)

            filePath = f'{backupPath}/{backupName}.tar.gz'
            totalSize = '%sMB' % (str(int(os.path.getsize(filePath) / 1048576)))

            try:
                for items in backupObs:
                    items.status = 1
                    items.size = totalSize
                    items.save()
            except BaseException as msg:
                logging.CyberCPLogFileWriter.writeToFile('%s. [backupRoot:499]' % str(msg))
                for items in backupObs:
                    items.status = 1
                    items.size = totalSize
                    items.save()

            command = 'chmod 600 %s' % (os.path.join(backupPath, backupName + ".tar.gz"))
            ProcessUtilities.executioner(command)

            if externalApp == None:
                logging.CyberCPLogFileWriter.statusWriter(status, "Completed\n")
            else:
                command = f"echo 'Completed' > {status}"
                ProcessUtilities.executioner(command, externalApp, True)

            os.remove(pidFile)
        except BaseException as msg:
            logging.CyberCPLogFileWriter.statusWriter(status, '%s. [511:BackupRoot][[5009]]\n' % str(msg))
            if externalApp == None:
                logging.CyberCPLogFileWriter.statusWriter(status, '%s. [511:BackupRoot][[5009]]\n')
            else:
                command = f"echo '%s. [511:BackupRoot][[5009]]' > {status}"
                ProcessUtilities.executioner(command, externalApp)

            command = f'rm -rf {tempStoragePath}'
            ProcessUtilities.executioner(command, externalApp)

            command = f'rm -rf {CPHomeStorage}'
            ProcessUtilities.executioner(command)

    @staticmethod
    def initiateBackup(tempStoragePath, backupName, backupPath):
        try:
            p = Process(target=backupUtilities.startBackup, args=(tempStoragePath, backupName, backupPath,))
            p.start()
            pid = open(backupPath + 'pid', "w")
            pid.write(str(p.pid))
            pid.close()
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [initiateBackup]")

    @staticmethod
    def createWebsiteFromBackup(backupFileOrig, dir):
        try:
            backupFile = backupFileOrig.strip(".tar.gz")
            originalFile = f"/home/backup/{backupFileOrig}"

            if os.path.exists(backupFileOrig):
                path = backupFile
            elif not os.path.exists(originalFile):
                dir = dir
                path = "/home/backup/transfer-" + str(dir) + "/" + backupFile
            else:
                path = f"/home/backup/{backupFile}"

            admin = Administrator.objects.get(userName='admin')

            ## open meta file to read data

            ## Parsing XML Meta file!

            backupMetaData = ElementTree.parse(os.path.join(path, 'meta.xml'))

            domain = backupMetaData.find('masterDomain').text
            phpSelection = backupMetaData.find('phpSelection').text
            externalApp = backupMetaData.find('externalApp').text
            VERSION = backupMetaData.find('VERSION').text
            BUILD = backupMetaData.find('BUILD').text

            ### Fetch user details

            try:

                userName = backupMetaData.find('userName').text

                try:
                    siteUser = Administrator.objects.get(userName=userName)
                except:
                    userPassword = backupMetaData.find('userPassword').text
                    firstName = backupMetaData.find('firstName').text
                    lastName = backupMetaData.find('lastName').text
                    email = backupMetaData.find('email').text
                    type = int(backupMetaData.find('type').text)
                    owner = int(backupMetaData.find('owner').text)
                    token = backupMetaData.find('token').text
                    api = int(backupMetaData.find('api').text)
                    securityLevel = int(backupMetaData.find('securityLevel').text)
                    state = backupMetaData.find('state').text
                    initWebsitesLimit = int(backupMetaData.find('initWebsitesLimit').text)
                    from loginSystem.models import ACL
                    acl = ACL.objects.get(name=backupMetaData.find('aclName').text)
                    siteUser = Administrator(userName=userName, password=userPassword, firstName=firstName,
                                             initWebsitesLimit=initWebsitesLimit, acl=acl,
                                             lastName=lastName, email=email, type=type, owner=owner, token=token,
                                             api=api, securityLevel=securityLevel, state=state)
                    siteUser.save()
            except:
                siteUser = Administrator.objects.get(userName='admin')

            ## Pre-creation checks

            if Websites.objects.filter(domain=domain).count() > 0:
                raise BaseException('This website already exists.')

            if ChildDomains.objects.filter(domain=domain).count() > 0:
                raise BaseException("This website already exists as child domain.")

            ####### Pre-creation checks ends

            ## Create Configurations

            # result = virtualHostUtilities.createVirtualHost(domain, siteUser.email, phpSelection, externalApp, 0, 1, 0,
            #                                                 siteUser.userName, 'Default', 0)
            result = virtualHostUtilities.createVirtualHost(domain, siteUser.email, phpSelection, externalApp, 1, 1, 0,
                                                   siteUser.userName, 'Default', 0, None,
                                                   1)

            if result[0] == 0:
                raise BaseException(result[1])

            ## Create Configurations ends here

            ## Create databases

            ### This code is just to create databases, database users will be created later

            databases = backupMetaData.findall('Databases/database')
            website = Websites.objects.get(domain=domain)

            for database in databases:

                dbName = database.find('dbName').text

                if ((VERSION == '2.1' or VERSION == '2.3') and int(BUILD) >= 1) or (VERSION == '2.4' and int(BUILD) >= 0):

                    logging.CyberCPLogFileWriter.writeToFile('Backup version 2.1.1+ detected..')
                    databaseUsers = database.findall('databaseUsers')
                    for databaseUser in databaseUsers:

                        dbUser = databaseUser.find('dbUser').text
                        res = mysqlUtilities.mysqlUtilities.createDatabase(dbName, dbUser, 'cyberpanel')
                        if res == 0:
                            logging.CyberCPLogFileWriter.writeToFile(
                                'Failed to restore database %s. But it can be false positive, moving on..' % (dbName))

                        newDB = Databases(website=website, dbName=dbName, dbUser=dbUser)
                        newDB.save()
                        break

                else:
                    dbUser = database.find('dbUser').text

                    if mysqlUtilities.mysqlUtilities.createDatabase(dbName, dbUser, "cyberpanel") == 0:
                        raise BaseException

                    newDB = Databases(website=website, dbName=dbName, dbUser=dbUser)
                    newDB.save()

            ## Create dns zone

            dnsrecords = backupMetaData.findall('dnsrecords/dnsrecord')

            DNS.createDNSZone(domain, admin)

            zone = DNS.getZoneObject(domain)

            for dnsrecord in dnsrecords:
                recordType = dnsrecord.find('type').text
                value = dnsrecord.find('name').text
                content = dnsrecord.find('content').text
                prio = int(dnsrecord.find('priority').text)

                DNS.createDNSRecord(zone, value, recordType, content, prio, 3600)

            return 1, 'None'

        except BaseException as msg:
            return 0, str(msg)

    @staticmethod
    def startRestore(backupName, dir):
        try:

            if dir == "CyberPanelRestore":
                backupFileName = backupName.strip(".tar.gz")
                completPath = os.path.join("/home", "backup", backupFileName)  ## without extension
                originalFile = os.path.join("/home", "backup", backupName)  ## with extension
            elif dir == 'CLI':
                completPath = backupName.strip(".tar.gz")  ## without extension
                originalFile = backupName  ## with extension
            else:
                backupFileName = backupName.strip(".tar.gz")
                completPath = "/home/backup/transfer-" + str(dir) + "/" + backupFileName  ## without extension
                originalFile = "/home/backup/transfer-" + str(dir) + "/" + backupName  ## with extension

            pathToCompressedHome = os.path.join(completPath, "public_html.tar.gz")

            if not os.path.exists(completPath):
                os.mkdir(completPath)

            ## Writing pid of restore process

            pid = os.path.join(completPath, 'pid')

            logging.CyberCPLogFileWriter.statusWriter(pid, str(os.getpid()))

            status = os.path.join(completPath, 'status')
            logging.CyberCPLogFileWriter.statusWriter(status, "Extracting Main Archive!")

            ## Converting /home/backup/backup-example.com-02.13.2018_10-24-52.tar.gz -> /home/backup/backup-example.com-02.13.2018_10-24-52

            tar = tarfile.open(originalFile)
            tar.extractall(completPath)
            tar.close()

            logging.CyberCPLogFileWriter.statusWriter(status, "Creating Accounts,Databases and DNS records!")

            ########### Creating website and its dabases

            ## extracting master domain for later use
            backupMetaData = ElementTree.parse(os.path.join(completPath, "meta.xml"))
            masterDomain = backupMetaData.find('masterDomain').text
            VERSION = backupMetaData.find('VERSION').text
            BUILD = backupMetaData.find('BUILD').text

            twoPointO = 0
            try:
                version = backupMetaData.find('VERSION').text
                build = backupMetaData.find('BUILD').text
                phpSelectionGlobalMainSite = backupMetaData.find('phpSelection').text
                twoPointO = 1
            except:
                twoPointO = 0

            try:
                BackupWholeDir = int(backupMetaData.find('BackupWholeDir').text)
            except:
                BackupWholeDir = 0

            result = backupUtilities.createWebsiteFromBackup(backupName, dir)

            if result[0] == 1:
                ## Let us try to restore SSL.

                sslStoragePath = completPath + "/" + masterDomain + ".cert.pem"

                if os.path.exists(sslStoragePath):
                    sslHome = '/etc/letsencrypt/live/' + masterDomain

                    try:
                        if not os.path.exists(sslHome):
                            os.mkdir(sslHome)

                        copy(completPath + "/" + masterDomain + ".cert.pem", sslHome + "/cert.pem")
                        copy(completPath + "/" + masterDomain + ".privkey.pem", sslHome + "/privkey.pem")
                        copy(completPath + "/" + masterDomain + ".fullchain.pem", sslHome + "/fullchain.pem")

                        sslUtilities.installSSLForDomain(masterDomain)
                    except BaseException as msg:
                        logging.CyberCPLogFileWriter.writeToFile('%s. [555:startRestore]' % (str(msg)))

            else:
                logging.CyberCPLogFileWriter.statusWriter(status, "Error Message: " + result[
                    1] + ". Not able to create Account, Databases and DNS Records, aborting. [575][5009]")
                return 0

            #### Find out web server from backup conf

            CurrentServer = ProcessUtilities.OLS

            if os.path.exists(completPath + '/vhost.conf'):
                if open(f'{completPath}/vhost.conf', 'r').read().find('ServerName') > -1:
                    CurrentServer = ProcessUtilities.ent


            ########### Creating child/sub/addon/parked domains

            logging.CyberCPLogFileWriter.statusWriter(status, "Creating Child Domains!")

            ## Reading meta file to create subdomains

            externalApp = backupMetaData.find('externalApp').text
            websiteHome = os.path.join("/home", masterDomain, "public_html")

            ### Restoring Child Domains if any.

            childDomains = backupMetaData.findall('ChildDomains/domain')

            try:
                for childDomain in childDomains:

                    domain = childDomain.find('domain').text

                    ## mail domain check

                    mailDomain = 'mail.%s' % (masterDomain)

                    if domain == mailDomain:
                        continue

                    ## Mail domain check

                    phpSelection = childDomain.find('phpSelection').text
                    path = childDomain.find('path').text

                    retValues = virtualHostUtilities.createDomain(masterDomain, domain, phpSelection, path, 0, 0, 0,
                                                                  'admin', 0)

                    if retValues[0] == 1:
                        if os.path.exists(websiteHome):
                            rmtree(websiteHome)

                        ## Let us try to restore SSL for Child Domains.
                        from ApachController.ApacheController import ApacheController

                        try:

                            if os.path.exists(completPath + '/' + domain + '.vhost.conf'):

                                if CurrentServer == ProcessUtilities.decideServer():

                                    completPathToConf = backupUtilities.Server_root + '/conf/vhosts/' + domain + '/vhost.conf'
                                    childConfPathinBKUP = completPath + '/' + domain + '.vhost.conf'
                                    copy(childConfPathinBKUP, completPathToConf)

                                    ### take care of apache conf

                                    url = "https://platform.cyberpersons.com/CyberpanelAdOns/Adonpermission"
                                    data = {
                                        "name": "all",
                                        "IP": ACLManager.GetServerIP()
                                    }

                                    import requests
                                    response = requests.post(url, data=json.dumps(data))
                                    Status = response.json()['status']

                                    if (Status == 1):

                                        childConfPathinBKUPApache = completPath + '/' + domain + '.apache.conf'
                                        tempStatusPath = '/home/cyberpanel/fakePath'

                                        if os.path.exists(ProcessUtilities.debugPath):
                                            logging.CyberCPLogFileWriter.writeToFile(f'Conf path of apache for child domain {domain} in backup is {childConfPathinBKUPApache}')

                                        childData = open(childConfPathinBKUP, 'r').read()

                                        if childData.find('proxyApacheBackendSSL') > -1 and os.path.exists(childConfPathinBKUPApache):

                                            if os.path.exists(ProcessUtilities.debugPath):
                                                logging.CyberCPLogFileWriter.writeToFile(
                                                    f'It seems child domain {domain} is using apache conf and {childConfPathinBKUPApache} also exists in backup file')

                                            virtualHostUtilities.switchServer(domain, phpSelection, virtualHostUtilities.apache, tempStatusPath)

                                            finalConfPathApache = ApacheVhost.configBasePath + domain + '.conf'


                                            if os.path.exists(finalConfPathApache):

                                                if os.path.exists(ProcessUtilities.debugPath):
                                                    logging.CyberCPLogFileWriter.writeToFile(
                                                        f'CyberPanel was able to successfully convert {domain} to apache conf as {finalConfPathApache} exists..')

                                                copy(childConfPathinBKUPApache, finalConfPathApache)

                                    ### apache ends




                            sslStoragePath = completPath + "/" + domain + ".cert.pem"

                            if os.path.exists(sslStoragePath):
                                sslHome = '/etc/letsencrypt/live/' + domain

                                try:
                                    if not os.path.exists(sslHome):
                                        os.mkdir(sslHome)

                                    copy(completPath + "/" + domain + ".cert.pem", sslHome + "/cert.pem")
                                    copy(completPath + "/" + domain + ".privkey.pem", sslHome + "/privkey.pem")
                                    copy(completPath + "/" + domain + ".fullchain.pem",
                                         sslHome + "/fullchain.pem")

                                    sslUtilities.installSSLForDomain(domain)
                                except:
                                    pass
                        except:
                            logging.CyberCPLogFileWriter.writeToFile(
                                'While restoring backup we had minor issues for rebuilding vhost conf for: ' + domain + '. However this will be auto healed.')

                        if float(version) > 2.0 or float(build) > 0:
                            if path.find('/home/%s/public_html' % masterDomain) == -1:

                                if BackupWholeDir == 0:

                                    #copy_tree('%s/%s-docroot' % (completPath, domain), path)

                                    ## First remove if already exists

                                    command = 'rm -rf %s' % (path)
                                    ProcessUtilities.executioner(command)

                                    ##

                                    command = 'cp -R %s/%s-docroot %s' % (completPath, domain, path)
                                    ProcessUtilities.executioner(command)

                        continue
                    else:
                        logging.CyberCPLogFileWriter.writeToFile('Error domain %s' % (domain))
                        logging.CyberCPLogFileWriter.statusWriter(status, "Error Message: " + retValues[
                            1] + ". Not able to create child domains, aborting. [635][5009]")
                        return 0
            except BaseException as msg:
                status = open(os.path.join(completPath, 'status'), "w")
                status.write("Error Message: " + str(msg) + ". Not able to create child domains, aborting. [638][5009]")
                status.close()
                logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [startRestore]")
                return 0

            ## Restore Aliases

            logging.CyberCPLogFileWriter.statusWriter(status, "Restoring Domain Aliases!")

            aliases = backupMetaData.findall('Aliases/alias')

            for items in aliases:
                virtualHostUtilities.createAlias(masterDomain, items.text, 0, "", "", "admin")

            ## Restoring email accounts

            logging.CyberCPLogFileWriter.statusWriter(status, "Restoring email accounts!")

            emailAccounts = backupMetaData.findall('emails/emailAccount')

            try:
                for emailAccount in emailAccounts:

                    email = emailAccount.find('email').text
                    username = email.split("@")[0]
                    password = emailAccount.find('password').text

                    result = mailUtilities.createEmailAccount(masterDomain, username, password, 'restore')
                    if result[0] == 0:
                        raise BaseException(result[1])
            except BaseException as msg:
                logging.CyberCPLogFileWriter.statusWriter(status, "Error Message: " + str(
                    msg) + ". Not able to create email accounts, aborting. [671][5009]")
                logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [startRestore]")
                return 0

            ## Emails restored

            ## restoring databases

            ### This will actually restore mysql dump and create mysql users

            logging.CyberCPLogFileWriter.statusWriter(status, "Restoring Databases!")

            databases = backupMetaData.findall('Databases/database')

            for database in databases:

                dbName = database.find('dbName').text

                if ((VERSION == '2.1' or VERSION == '2.3') and int(BUILD) >= 1) or (VERSION == '2.4' and int(BUILD) >= 0):

                    logging.CyberCPLogFileWriter.writeToFile('Backup version 2.1.1+ detected..')

                    first = 1

                    databaseUsers = database.findall('databaseUsers')

                    for databaseUser in databaseUsers:

                        dbUser = databaseUser.find('dbUser').text
                        dbHost = databaseUser.find('dbHost').text
                        password = databaseUser.find('password').text

                        if os.path.exists(ProcessUtilities.debugPath):

                            logging.CyberCPLogFileWriter.writeToFile('Database user: %s' % (dbUser))
                            logging.CyberCPLogFileWriter.writeToFile('Database host: %s' % (dbHost))
                            logging.CyberCPLogFileWriter.writeToFile('Database password: %s' % (password))

                        ## Future ref, this logic can be further refactored to improve restore backup logic
                        if first:
                            first = 0
                            res = mysqlUtilities.mysqlUtilities.restoreDatabaseBackup(dbName, completPath, password, 1)
                            if res == 0:
                                logging.CyberCPLogFileWriter.writeToFile(
                                    'Failed to restore database %s. But it can be false positive, moving on..' % (
                                        dbName))


                        ### This function will not create database, only database user is created as third value is 0 for createDB

                        mysqlUtilities.mysqlUtilities.createDatabase(dbName, dbUser, password, 0, dbHost)
                        mysqlUtilities.mysqlUtilities.changePassword(dbUser, password, 1, dbHost)

                        # UserInMySQLTable = DBUsers.objects.get(user=dbUser, host=dbHost)
                        # UserInMySQLTable.password = password
                        # UserInMySQLTable.save()

                else:
                    password = database.find('password').text
                    if mysqlUtilities.mysqlUtilities.restoreDatabaseBackup(dbName, completPath, password) == 0:
                        raise BaseException

            ## Databases restored

            logging.CyberCPLogFileWriter.statusWriter(status, "Extracting web home data!")

            # /home/backup/backup-example.com-02.13.2018_10-24-52/public_html.tar.gz
            ## Moving above v2.0.0 extracting webhome data is not required, thus commenting below lines


            if not twoPointO:
                tar = tarfile.open(pathToCompressedHome)
                tar.extractall(websiteHome)
                tar.close()
            else:
                if float(version) > 2.0 or float(build) > 0:
                    #copy_tree('%s/public_html' % (completPath), websiteHome)

                    ## First remove if already exists

                    command = 'rm -rf %s' % (websiteHome)
                    ProcessUtilities.executioner(command)

                    ##
                    if BackupWholeDir:
                        #command = 'cp -R %s/public_html/* %s/*' % (completPath, websiteHome)
                        command = f'rsync -av {completPath}/public_html/ /home/{masterDomain}'
                    else:
                        command = 'cp -R %s/public_html %s' % (completPath, websiteHome)
                    ProcessUtilities.executioner(command)

            ## extracting email accounts

            logging.CyberCPLogFileWriter.statusWriter(status, "Extracting email accounts!")

            if not twoPointO:

                try:
                    pathToCompressedEmails = os.path.join(completPath, masterDomain + ".tar.gz")
                    emailHome = os.path.join("/home", "vmail", masterDomain)

                    tar = tarfile.open(pathToCompressedEmails)
                    tar.extractall(emailHome)
                    tar.close()

                    ## Change permissions

                    command = "chown -R vmail:vmail " + emailHome
                    subprocess.call(shlex.split(command))

                except:
                    pass
            else:

                emailsPath = '%s/vmail' % (completPath)

                if os.path.exists(emailsPath):
                    #copy_tree(emailsPath, '/home/vmail/%s' % (masterDomain))

                    ## First remove if already exists

                    command = 'rm -rf /home/vmail/%s' % (masterDomain)
                    ProcessUtilities.executioner(command)

                    ##

                    command = 'cp -R %s /home/vmail/%s' % (emailsPath, masterDomain)
                    ProcessUtilities.executioner(command)

                command = "chown -R vmail:vmail /home/vmail/%s" % (masterDomain)
                ProcessUtilities.executioner(command)

            ## emails extracted

            completPathToConf = backupUtilities.Server_root + '/conf/vhosts/' + masterDomain + '/vhost.conf'
            if os.path.exists(completPath + '/vhost.conf'):
                if CurrentServer == ProcessUtilities.decideServer():
                    confPathMainSite = completPath + '/vhost.conf'
                    copy(confPathMainSite, completPathToConf)


                    ### apache starts here

                    url = "https://platform.cyberpersons.com/CyberpanelAdOns/Adonpermission"
                    data = {
                        "name": "all",
                        "IP": ACLManager.GetServerIP()
                    }

                    import requests
                    response = requests.post(url, data=json.dumps(data))
                    Status = response.json()['status']

                    if (Status == 1):
                        confPathApache = completPath + '/apache.conf'

                        if os.path.exists(ProcessUtilities.debugPath):
                            logging.CyberCPLogFileWriter.writeToFile(f'Conf path of apache for main site {masterDomain} in backup is {confPathApache}')

                        tempStatusPath = '/home/cyberpanel/fakePath'

                        childData = open(confPathMainSite, 'r').read()

                        if childData.find('proxyApacheBackendSSL') > -1 and os.path.exists(confPathApache):

                            if os.path.exists(ProcessUtilities.debugPath):
                                logging.CyberCPLogFileWriter.writeToFile(
                                    f'It seems main site {masterDomain} is using apache conf.')

                            virtualHostUtilities.switchServer(masterDomain, phpSelectionGlobalMainSite, virtualHostUtilities.apache,
                                                              tempStatusPath)

                            finalConfPathApache = ApacheVhost.configBasePath + masterDomain + '.conf'

                            if os.path.exists(ProcessUtilities.debugPath):
                                logging.CyberCPLogFileWriter.writeToFile(
                                    f'Apache conf path of main domain exists which means CyberPanel successfully converted site to Apache for {masterDomain}')

                            if os.path.exists(confPathApache):
                                copy(confPathApache, finalConfPathApache)

                    ### apache ends here

            logging.CyberCPLogFileWriter.statusWriter(status, "Done")


            ## Fix permissions

            from filemanager.filemanager import FileManager

            fm = FileManager(None, None)
            fm.fixPermissions(masterDomain)

            installUtilities.reStartLiteSpeed()

        except BaseException as msg:
            status = os.path.join(completPath, 'status')
            logging.CyberCPLogFileWriter.statusWriter(status, str(msg) + " [736][5009]")
            logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [startRestore]")

    @staticmethod
    def initiateRestore(backupName, dir):
        try:
            p = Process(target=backupUtilities.startRestore, args=(backupName, dir,))
            p.start()
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [initiateRestore]")

    # @staticmethod
    # def sendKey(IPAddress, password, port='22', user='root'):
    #     try:
    #
    #         expectation = []
    #         expectation.append("password:")
    #         expectation.append("Password:")
    #         expectation.append("Permission denied")
    #         expectation.append("100%")
    #
    #         ## Temp changes
    #
    #         command = 'chmod 600 %s' % ('/root/.ssh/cyberpanel.pub')
    #         ProcessUtilities.executioner(command)
    #
    #         command = "scp -o StrictHostKeyChecking=no -P " + port + " /root/.ssh/cyberpanel.pub " + user + "@" + IPAddress + ":~/.ssh/authorized_keys"
    #         setupKeys = pexpect.spawn(command, timeout=3)
    #
    #         if os.path.exists(ProcessUtilities.debugPath):
    #             logging.CyberCPLogFileWriter.writeToFile(command)
    #
    #         index = setupKeys.expect(expectation)
    #
    #         ## on first login attempt send password
    #
    #         if index == 0:
    #             setupKeys.sendline(password)
    #             setupKeys.expect("100%")
    #             setupKeys.wait()
    #         elif index == 1:
    #             setupKeys.sendline(password)
    #             setupKeys.expect("100%")
    #             setupKeys.wait()
    #         elif index == 2:
    #             return [0, 'Please enable password authentication on your remote server.']
    #         elif index == 3:
    #             pass
    #         else:
    #             raise BaseException
    #
    #         ## Temp changes
    #
    #         command = 'chmod 644 %s' % ('/root/.ssh/cyberpanel.pub')
    #         ProcessUtilities.executioner(command)
    #
    #         return [1, "None"]
    #
    #     except pexpect.TIMEOUT as msg:
    #
    #         command = 'chmod 644 %s' % ('/root/.ssh/cyberpanel.pub')
    #         ProcessUtilities.executioner(command)
    #
    #         logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [sendKey]")
    #         return [0, "TIMEOUT [sendKey]"]
    #     except pexpect.EOF as msg:
    #
    #         command = 'chmod 644 %s' % ('/root/.ssh/cyberpanel.pub')
    #         ProcessUtilities.executioner(command)
    #
    #         logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [sendKey]")
    #         return [0, "EOF [sendKey]"]
    #     except BaseException as msg:
    #
    #         command = 'chmod 644 %s' % ('/root/.ssh/cyberpanel.pub')
    #         ProcessUtilities.executioner(command)
    #
    #         logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [sendKey]")
    #         return [0, str(msg) + " [sendKey]"]

    # @staticmethod
    # def setupSSHKeys(IPAddress, password, port='22', user='root'):
    #     try:
    #         ## Checking for host verification
    #
    #         backupUtilities.host_key_verification(IPAddress)
    #
    #         if backupUtilities.checkIfHostIsUp(IPAddress) == 1:
    #             pass
    #         else:
    #             logging.CyberCPLogFileWriter.writeToFile("Host is Down.")
    #             # return [0,"Host is Down."]
    #
    #         expectation = []
    #         expectation.append("password:")
    #         expectation.append("Password:")
    #         expectation.append("Permission denied")
    #         expectation.append("File exists")
    #
    #         command = "ssh -o StrictHostKeyChecking=no -p " + port + ' ' + user + "@" + IPAddress + ' "mkdir ~/.ssh || rm -f ~/.ssh/temp && rm -f ~/.ssh/authorized_temp && cp ~/.ssh/authorized_keys ~/.ssh/temp || chmod 700 ~/.ssh || chmod g-w ~"'
    #         setupKeys = pexpect.spawn(command, timeout=3)
    #
    #         if os.path.exists(ProcessUtilities.debugPath):
    #             logging.CyberCPLogFileWriter.writeToFile(command)
    #
    #         index = setupKeys.expect(expectation)
    #
    #         ## on first login attempt send password
    #
    #         if index == 0:
    #             setupKeys.sendline(password)
    #         elif index == 1:
    #             setupKeys.sendline(password)
    #         elif index == 2:
    #             return [0, 'Please enable password authentication on your remote server.']
    #         elif index == 3:
    #             pass
    #         else:
    #             raise BaseException
    #
    #         ## if it again give you password, than provided password is wrong
    #
    #         expectation = []
    #         expectation.append("please try again.")
    #         expectation.append("Password:")
    #         expectation.append(pexpect.EOF)
    #
    #         index = setupKeys.expect(expectation)
    #
    #         if index == 0:
    #             return [0, "Wrong Password!"]
    #         elif index == 1:
    #             return [0, "Wrong Password!"]
    #         elif index == 2:
    #             setupKeys.wait()
    #
    #             sendKey = backupUtilities.sendKey(IPAddress, password, port, user)
    #
    #             if sendKey[0] == 1:
    #                 return [1, "None"]
    #             else:
    #                 return [0, sendKey[1]]
    #
    #
    #     except pexpect.TIMEOUT as msg:
    #         return [0, str(msg) + " [TIMEOUT setupSSHKeys]"]
    #     except BaseException as msg:
    #         return [0, str(msg) + " [setupSSHKeys]"]

    @staticmethod
    def sendKey(IPAddress, password, port='22', user='root'):
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            ssh.connect(IPAddress, port=int(port), username=user, password=password)

            if os.path.exists('/root/.ssh/cyberpanel.pub'):
                pass
            else:
                command = "ssh-keygen -f /root/.ssh/cyberpanel -t rsa -N ''"
                ProcessUtilities.executioner(command, 'root', True)

            command = 'chmod 600 %s' % ('/root/.ssh/cyberpanel.pub')
            ProcessUtilities.executioner(command)

            try:
                # Try to use SFTP to create .ssh directory if it doesn't exist
                sftp = ssh.open_sftp()
                try:
                    sftp.stat('.ssh')
                except FileNotFoundError:
                    # Try to create .ssh directory via SFTP
                    try:
                        sftp.mkdir('.ssh')
                    except:
                        # Directory creation via SFTP might fail on some servers
                        pass
                
                # Try to upload the key
                sftp.put('/root/.ssh/cyberpanel.pub', '.ssh/authorized_keys')
                sftp.close()

                # Try to set permissions via SSH command (might fail on SFTP-only servers)
                try:
                    stdin, stdout, stderr = ssh.exec_command('chmod 600 .ssh/authorized_keys', timeout=5)
                    stdout.channel.recv_exit_status()
                except:
                    # If chmod fails, it's likely an SFTP-only server
                    # The key is uploaded, which is what matters for backups using password auth
                    logging.CyberCPLogFileWriter.writeToFile(
                        f'Could not set permissions on {IPAddress}, likely SFTP-only server')
                    pass

            except Exception as e:
                # If we can't upload the key, it might be an SFTP-only server
                # Return success anyway since password authentication works
                logging.CyberCPLogFileWriter.writeToFile(
                    f'Could not upload SSH key to {IPAddress}: {str(e)}, using password authentication')
                ssh.close()
                command = 'chmod 644 %s' % ('/root/.ssh/cyberpanel.pub')
                ProcessUtilities.executioner(command)
                return [1, "None"]

            ssh.close()

            command = 'chmod 644 %s' % ('/root/.ssh/cyberpanel.pub')
            ProcessUtilities.executioner(command)

            return [1, "None"]


        except paramiko.AuthenticationException:
            return [0, 'Authentication failed. [sendKey]']
        except paramiko.SSHException as e:
            return [0, f'SSH error: {str(e)} [sendKey]']
        except Exception as e:
            return [0, f'General Error: {str(e)} [sendKey]']

    @staticmethod
    def setupSSHKeys(IPAddress, password, port='22', user='root'):
        try:
            ssh = paramiko.SSHClient()
            ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            if password != 'NOT-NEEDED':

                ssh.connect(IPAddress, port=int(port), username=user, password=password)
                
                # Try to execute SSH commands first
                ssh_commands_supported = True
                commands = [
                    "mkdir -p .ssh",
                    "rm -f .ssh/temp",
                    "rm -f .ssh/authorized_temp",
                    "cp .ssh/authorized_keys .ssh/temp",
                    "chmod 700 .ssh",
                    "chmod g-w ~",
                ]

                for command in commands:
                    try:
                        stdin, stdout, stderr = ssh.exec_command(command, timeout=5)
                        exit_status = stdout.channel.recv_exit_status()
                        error_output = stderr.read().decode()
                        
                        # Check if the command was rejected (SFTP-only server)
                        if exit_status != 0 or "not allowed" in error_output.lower() or "channel closed" in error_output.lower():
                            ssh_commands_supported = False
                            logging.CyberCPLogFileWriter.writeToFile(
                                f'SSH commands not supported on {IPAddress}, falling back to pure SFTP mode')
                            break
                    except BaseException as msg:
                        ssh_commands_supported = False
                        logging.CyberCPLogFileWriter.writeToFile(
                            f'Error executing remote command {command}. Error {str(msg)}, falling back to pure SFTP mode')
                        break

                ssh.close()

                # If SSH commands are not supported, use pure SFTP mode
                if not ssh_commands_supported:
                    # For SFTP-only servers, we'll use password authentication directly
                    # No need to setup SSH keys, just verify connection works
                    try:
                        test_ssh = paramiko.SSHClient()
                        test_ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                        test_ssh.connect(IPAddress, port=int(port), username=user, password=password)
                        
                        # Open SFTP connection to verify it works
                        sftp = test_ssh.open_sftp()
                        sftp.close()
                        test_ssh.close()
                        
                        logging.CyberCPLogFileWriter.writeToFile(
                            f'Pure SFTP mode verified for {IPAddress}')
                        return [1, "None"]
                    except Exception as e:
                        return [0, f'SFTP connection failed: {str(e)}']
                else:
                    # SSH commands are supported, proceed with key setup
                    sendKey = backupUtilities.sendKey(IPAddress, password, port, user)

                    if sendKey[0] == 1:
                        command = 'chmod 644 %s' % ('/root/.ssh/cyberpanel.pub')
                        ProcessUtilities.executioner(command)
                        return [1, "None"]
                    else:
                        command = 'chmod 644 %s' % ('/root/.ssh/cyberpanel.pub')
                        ProcessUtilities.executioner(command)
                        return [0, sendKey[1]]
            else:
                # Load the private key
                private_key_path = '/root/.ssh/cyberpanel'
                keyPrivate = paramiko.RSAKey(filename=private_key_path)

                # Connect to the remote server using the private key
                ssh = paramiko.SSHClient()
                ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                ssh.connect(IPAddress, username=user, pkey=keyPrivate)

                return [1, "None"]

        except paramiko.AuthenticationException:
            return [0, 'Authentication failed. [setupSSHKeys]']
        except paramiko.SSHException as e:
            return [0, f'SSH error: {str(e)} [setupSSHKeys]']
        except Exception as e:
            return [0, f'General Error: {str(e)} [setupSSHKeys]']


    @staticmethod
    def checkIfHostIsUp(IPAddress):
        try:
            if subprocess.check_output(['ping', IPAddress, '-c 1']).decode("utf-8").find("0% packet loss") > -1:
                return 1
            else:
                return 0
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(str(msg) + "[checkIfHostIsUp]")

    @staticmethod
    def checkConnection(IPAddress, port='22', user='root'):
        try:

            try:
                import json
                destinations = backupUtilities.destinationsPath
                data = json.loads(open(destinations, 'r').read())
                port = data['port']
                user = data['user']
            except:
                port = "22"

            expectation = []
            expectation.append("password:")
            expectation.append("Password:")
            expectation.append("Last login")
            expectation.append(pexpect.EOF)
            expectation.append(pexpect.TIMEOUT)

            command = "sudo ssh -i /root/.ssh/cyberpanel -o StrictHostKeyChecking=no -p " + port + ' ' + user + "@" + IPAddress

            if os.path.exists(ProcessUtilities.debugPath):
                logging.CyberCPLogFileWriter.writeToFile(command)

            checkConn = pexpect.spawn(command,timeout=3)
            index = checkConn.expect(expectation)

            if index == 0:
                subprocess.call(['kill', str(checkConn.pid)])
                logging.CyberCPLogFileWriter.writeToFile(
                    "Remote Server is not able to authenticate for transfer to initiate, IP Address:" + IPAddress)
                return [0, "Remote Server is not able to authenticate for transfer to initiate."]
            elif index == 1:
                subprocess.call(['kill', str(checkConn.pid)])
                logging.CyberCPLogFileWriter.writeToFile(
                    "Remote Server is not able to authenticate for transfer to initiate, IP Address:" + IPAddress)
                return [0, "Remote Server is not able to authenticate for transfer to initiate."]
            elif index == 2:
                subprocess.call(['kill', str(checkConn.pid)])
                return [1, "None"]
            elif index == 4:
                subprocess.call(['kill', str(checkConn.pid)])
                return [1, "None"]
            else:
                subprocess.call(['kill', str(checkConn.pid)])
                return [1, "None"]

        except pexpect.TIMEOUT as msg:
            logging.CyberCPLogFileWriter.writeToFile("Timeout " + IPAddress + " [checkConnection]")
            return [0, "371 Timeout while making connection to this server [checkConnection]"]
        except pexpect.EOF as msg:
            logging.CyberCPLogFileWriter.writeToFile("EOF " + IPAddress + "[checkConnection]")
            return [0, "374 Remote Server is not able to authenticate for transfer to initiate. [checkConnection]"]
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(str(msg) + " " + IPAddress + " [checkConnection]")
            return [0, "377 Remote Server is not able to authenticate for transfer to initiate. [checkConnection]"]

    @staticmethod
    def verifyHostKey(IPAddress, port='22', user='root'):
        try:
            backupUtilities.host_key_verification(IPAddress)

            password = "hello"  ## dumb password, not used anywhere.

            expectation = []

            expectation.append("continue connecting (yes/no)?")
            expectation.append("password:")

            setupSSHKeys = pexpect.spawn("ssh -p " + port + user + "@" + IPAddress, timeout=3)

            index = setupSSHKeys.expect(expectation)

            if index == 0:
                setupSSHKeys.sendline("yes")

                setupSSHKeys.expect("password:")
                setupSSHKeys.sendline(password)

                expectation = []

                expectation.append("password:")
                expectation.append(pexpect.EOF)

                innerIndex = setupSSHKeys.expect(expectation)

                if innerIndex == 0:
                    setupSSHKeys.kill(signal.SIGTERM)
                    return [1, "None"]
                elif innerIndex == 1:
                    setupSSHKeys.kill(signal.SIGTERM)
                    return [1, "None"]

            elif index == 1:

                setupSSHKeys.expect("password:")
                setupSSHKeys.sendline(password)

                expectation = []

                expectation.append("password:")
                expectation.append(pexpect.EOF)

                innerIndex = setupSSHKeys.expect(expectation)

                if innerIndex == 0:
                    setupSSHKeys.kill(signal.SIGTERM)
                    return [1, "None"]
                elif innerIndex == 1:
                    setupSSHKeys.kill(signal.SIGTERM)
                    return [1, "None"]


        except pexpect.TIMEOUT as msg:
            logging.CyberCPLogFileWriter.writeToFile("Timeout [verifyHostKey]")
            return [0, "Timeout [verifyHostKey]"]
        except pexpect.EOF as msg:
            logging.CyberCPLogFileWriter.writeToFile("EOF [verifyHostKey]")
            return [0, "EOF [verifyHostKey]"]
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [verifyHostKey]")
            return [0, str(msg) + " [verifyHostKey]"]

    @staticmethod
    def createBackupDir(IPAddress, port='22', user='root'):

        try:
            # First try SSH command
            command = "sudo ssh -o StrictHostKeyChecking=no -p " + port + " -i /root/.ssh/cyberpanel " + user + "@" + IPAddress + " mkdir ~/backup"

            if os.path.exists(ProcessUtilities.debugPath):
                logging.CyberCPLogFileWriter.writeToFile(command)

            result = subprocess.call(shlex.split(command))
            
            # If SSH command fails, it might be an SFTP-only server
            if result != 0:
                logging.CyberCPLogFileWriter.writeToFile(
                    f"SSH command failed for {IPAddress}, likely SFTP-only server. Skipping directory creation.")
                # Don't fail - SFTP servers may have their own directory structure
                return 1

            command = "sudo ssh -o StrictHostKeyChecking=no -p " + port + " -i /root/.ssh/cyberpanel " + user + "@" + IPAddress + ' "cat ~/.ssh/authorized_keys ~/.ssh/temp > ~/.ssh/authorized_temp"'

            if os.path.exists(ProcessUtilities.debugPath):
                logging.CyberCPLogFileWriter.writeToFile(command)

            subprocess.call(shlex.split(command))


            command = "sudo ssh -o StrictHostKeyChecking=no -p " + port + " -i /root/.ssh/cyberpanel " + user + "@" + IPAddress + ' "cat ~/.ssh/authorized_temp > ~/.ssh/authorized_keys"'

            if os.path.exists(ProcessUtilities.debugPath):
                logging.CyberCPLogFileWriter.writeToFile(command)

            subprocess.call(shlex.split(command))
            
            return 1

        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [createBackupDir]")
            # Don't fail for SFTP-only servers
            return 1

    @staticmethod
    def host_key_verification(IPAddress):
        try:
            command = 'sudo ssh-keygen -R ' + IPAddress
            subprocess.call(shlex.split(command))
            return 1
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [host_key_verification]")
            return 0

    @staticmethod
    def getAliases(masterDomain):
        try:
            aliases = []
            master = Websites.objects.get(domain=masterDomain)
            aliasDomains = master.aliasdomains_set.all()

            for items in aliasDomains:
                aliases.append(items.aliasDomain)

            return aliases

        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(str(msg) + "  [getAliases]")
            print(0)

    ### Cloud Backup functions

    def CheckIfSleepNeeded(self):
        import psutil
        while (1):
            logging.CyberCPLogFileWriter.writeToFile('Current CPU percent %s.' % (int(psutil.cpu_percent(interval=None))))
            if int(psutil.cpu_percent(interval=None)) > int(self.cpu):
                logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                          'Current CPU usage exceeds %s percent. Backup process will sleep for %s seconds..,0' % (self.cpu, str(self.time)))
                import time
                time.sleep(self.time)
            else:
                break

    def BackupData(self):
        try:

            ### Creating the dir to store backups
            self.BackupDataPath = '%s/data' % (self.BackupPath)
            command = 'mkdir -p %s' % (self.BackupDataPath)
            ProcessUtilities.executioner(command)
            self.DataPath = '/home/%s' % (self.extraArgs['domain'])

            ## Backing up data

            self.CheckIfSleepNeeded()

            command = 'nice -n %s cp -Rp %s %s' % (self.nice, self.DataPath, self.BackupDataPath)
            ProcessUtilities.executioner(command)

            ## Store child domains if any in json format

            DataJson = {}
            childs = []
            import json

            for child in self.website.childdomains_set.all():
                childs.append({'domain': child.domain, 'path': child.path, 'php': child.phpSelection})

            DataJson['ChildDomains'] = childs

            DataJsonPath = '%s/%s' % (self.BackupPath, 'data.json')

            writeToFile = open(DataJsonPath, 'w')
            writeToFile.write(json.dumps(DataJson))
            writeToFile.close()

            return 1, None
        except BaseException as msg:
            return 0, str(msg)

    def BackupEmails(self):
        try:

            from mailServer.models import Domains, EUsers
            try:
                emailDomain = Domains.objects.get(domainOwner=self.website)
            except:
                return 1, None

            ### Creating the dir to store backups
            self.BackupDataPath = '%s/emails' % (self.BackupPath)
            command = 'mkdir -p %s' % (self.BackupDataPath)
            ProcessUtilities.executioner(command)
            self.DataPath = '/home/vmail/%s' % (self.extraArgs['domain'])

            ## Backing up data

            self.CheckIfSleepNeeded()

            command = 'nice -n %s cp -Rp %s %s' % (self.nice, self.DataPath, self.BackupDataPath)
            ProcessUtilities.executioner(command)

            ## Store child domains if any in json format

            DataJson = {}
            emailsList = []
            import json

            for emails in emailDomain.eusers_set.all():
                emailsList.append({'email': emails.email, 'password': emails.password})

            DataJson['emails'] = emailsList
            DataJsonPath = '%s/%s' % (self.BackupPath, 'emails.json')
            writeToFile = open(DataJsonPath, 'w')
            writeToFile.write(json.dumps(DataJson))
            writeToFile.close()

            return 1, None
        except BaseException as msg:
            return 0, str(msg)

    def BackupDatabases(self):
        try:

            ### Creating the dir to store backups
            self.BackupDataPath = '%s/databases' % (self.BackupPath)
            command = 'mkdir -p %s' % (self.BackupDataPath)
            ProcessUtilities.executioner(command)

            ## Backing up data

            self.CheckIfSleepNeeded()
            DataJson = {}
            databases = []
            import json

            for items in self.website.databases_set.all():
                try:
                    dbuser = DBUsers.objects.get(user=items.dbUser)
                    userToTry = items.dbUser
                except:
                    try:
                        dbusers = DBUsers.objects.all().filter(user=items.dbUser)
                        userToTry = items.dbUser
                        for it in dbusers:
                            dbuser = it
                            break

                        userToTry = mysqlUtilities.mysqlUtilities.fetchuser(items.dbName)

                        if userToTry == 0 or userToTry == 1:
                            continue

                        try:
                            dbuser = DBUsers.objects.get(user=userToTry)
                        except:
                            try:
                                dbusers = DBUsers.objects.all().filter(user=userToTry)
                                for it in dbusers:
                                    dbuser = it
                                    break

                            except BaseException as msg:
                                logging.CyberCPLogFileWriter.writeToFile(
                                    'While creating backup for %s, we failed to backup database %s. Error message: %s' % (
                                        self.website.domain, items.dbName, str(msg)))
                                continue
                    except BaseException as msg:
                        logging.CyberCPLogFileWriter.writeToFile(
                            'While creating backup for %s, we failed to backup database %s. Error message: %s' % (
                                self.website.domain, items.dbName, str(msg)))
                        continue

                databases.append({'databaseName': str(items.dbName), 'databaseUser': str(userToTry), 'password': str(dbuser.password)})
                self.CheckIfSleepNeeded()
                mysqlUtilities.mysqlUtilities.createDatabaseBackup(items.dbName, self.BackupDataPath)

            DataJson['databases'] = databases
            DataJsonPath = '%s/%s' % (self.BackupPath, 'databases.json')

            writeToFile = open(DataJsonPath, 'w')
            writeToFile.write(json.dumps(DataJson))
            writeToFile.close()

            return 1, None
        except BaseException as msg:
            return 0, str(msg)

    def CloudBackups(self):

        import json
        if os.path.exists(backupUtilities.CloudBackupConfigPath):
            result = json.loads(open(backupUtilities.CloudBackupConfigPath, 'r').read())
            self.nice = result['nice']
            self.cpu = result['cpu']
            self.time = int(result['time'])
        else:
            self.nice = backupUtilities.NiceDefault
            self.cpu = backupUtilities.CPUDefault
            self.time = int(backupUtilities.time)

        self.BackupPath = self.extraArgs['path']
        self.website = Websites.objects.get(domain=self.extraArgs['domain'])

        command = 'mkdir -p %s' % (self.BackupPath)
        ProcessUtilities.executioner(command)

        logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                  'Starting backup generation..,0')
        if self.extraArgs['data']:
            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Generating backup for your data,5')
            result = self.BackupData()
            if result[0] == 0:
                logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                          'Failed to generate backups for data. Error: %s. [404], 0' % (result[1] ))
                return 0, self.BackupPath

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Data backup successfully generated,30')

        if self.extraArgs['emails']:
            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Generating backup for your emails,40')
            result = self.BackupEmails()
            if result[0] == 0:
                logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                          'Failed to generate backups for emails. Error: %s. [404], 0' % (result[1] ))
                return 0, self.BackupPath

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Emails backup successfully generated,60')

        if self.extraArgs['databases']:
            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Generating backup for your databases,60')
            result = self.BackupDatabases()
            if result[0] == 0:
                logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                          'Failed to generate backups for databases. Error: %s. [404], 0' % (result[1] ))
                return 0, self.BackupPath

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Databases backups successfully generated,30')

        logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                  'Creating final archive..,80')

        command = 'nice -n %s tar czf %s.tar.gz -C %s %s' % (self.nice, self.BackupPath, '/home/cyberpanel/backups/%s' % (self.extraArgs['domain']), self.BackupPath.split('/')[-1])
        ProcessUtilities.executioner(command)

        command = 'rm -rf %s' % (self.BackupPath)
        ProcessUtilities.executioner(command)

        finalPath = '%s.tar.gz' % (self.BackupPath)

        command = 'chown cyberpanel:cyberpanel %s' % (finalPath)
        ProcessUtilities.executioner(command)

        command = 'chmod 600:600 %s' % (finalPath)
        ProcessUtilities.executioner(command)

        if self.extraArgs['port'] != 0:
            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Sending file to destination server..,90')

            command = "scp -o StrictHostKeyChecking=no -P %s -i /root/.ssh/cyberpanel %s root@%s:/home/cyberpanel/backups/%s/" % (self.extraArgs['port'], finalPath, self.extraArgs['ip'], self.extraArgs['destinationDomain'])
            ProcessUtilities.outputExecutioner(command)

        logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], 'Completed [200].')

        return 1, self.BackupPath + '.tar.gz'

    ## Restore functions

    def SubmitCloudBackupRestore(self):
        try:
            import json
            if os.path.exists(backupUtilities.CloudBackupConfigPath):
                result = json.loads(open(backupUtilities.CloudBackupConfigPath, 'r').read())
                self.nice = result['nice']
                self.cpu = result['cpu']
                self.time = int(result['time'])
            else:
                self.nice = backupUtilities.NiceDefault
                self.cpu = backupUtilities.CPUDefault
                self.time = int(backupUtilities.time)

            self.BackupPath = '/home/cyberpanel/backups/%s/%s' % (self.extraArgs['domain'], self.extraArgs['backupFile'])
            self.website = Websites.objects.get(domain=self.extraArgs['domain'])

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Extracting main archive..,0')


            command = 'tar -xf %s -C %s' % (self.BackupPath, '/home/cyberpanel/backups/%s/' % (self.extraArgs['domain']))
            ProcessUtilities.executioner(command)

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Main Archive extracted,20')

            self.extractedPath = '/home/cyberpanel/backups/%s/%s' % (self.extraArgs['domain'], self.extraArgs['backupFile'].rstrip('.tar.gz'))

            self.dataPath = '%s/data' % (self.extractedPath)
            self.databasesPath = '%s/databases' % (self.extractedPath)
            self.emailsPath = '%s/emails' % (self.extractedPath)

            ## Data

            if os.path.exists(self.dataPath):
                try:
                    logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                              'Creating child domains if any..,20')
                    childDomains = json.loads(open('%s/data.json' % (self.extractedPath), 'r').read())['ChildDomains']

                    for child in childDomains:
                        try:
                            ch = ChildDomains.objects.get(domain=child['domain'])
                        except:
                            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                                      'Creating %s,20' % (child['domain']))
                            virtualHostUtilities.createDomain(self.website.domain, child['domain'], child['php'], child['path'], 1, 0, 0,
                                                              self.website.admin.userName, 0, "/home/cyberpanel/" + str(randint(1000, 9999)))

                except BaseException as msg:
                    logging.CyberCPLogFileWriter.writeToFile('%s [SubmitCloudBackupRestore:1533]' % str(msg))

                homePath = '/home/%s' % (self.website.domain)
                command = 'rm -rf %s' % (homePath)
                ProcessUtilities.executioner(command)

                if self.extraArgs['sourceDomain'] == 'None':
                    command = 'mv %s/%s %s' % (self.dataPath, self.website.domain, '/home')
                else:
                    command = 'mv %s/%s %s/%s' % (self.dataPath, self.extraArgs['sourceDomain'], '/home', self.extraArgs['domain'])

                ProcessUtilities.executioner(command)


                from filemanager.filemanager import FileManager

                fm = FileManager(None, None)
                fm.fixPermissions(self.website.domain)

            ## Emails

            if os.path.exists(self.emailsPath):
                try:
                    logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                              'Creating emails if any..,40')
                    emails = json.loads(open('%s/emails.json' % (self.extractedPath), 'r').read())['emails']
                    from mailServer.models import Domains, EUsers
                    emailDomain = Domains.objects.get(domain=self.website.domain)

                    for email in emails:
                        try:
                            eu = EUsers.objects.get(emailOwner=emailDomain, email=email['email'])
                        except:
                            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                                      'Creating %s,40' % (email['email']))
                            emailAcct = EUsers(emailOwner=emailDomain, email=email['email'], password=email['password'])
                            emailAcct.mail = 'maildir:/home/vmail/%s/%s/Maildir' % (self.website.domain, email['email'].split('@')[0])
                            emailAcct.save()

                        EmailsHome = '/home/vmail/%s' % (self.website.domain)

                        command = 'rm -rf %s' % (EmailsHome)
                        ProcessUtilities.executioner(command)

                        command = 'mv %s/%s /home/vmail' % (self.emailsPath, self.website.domain)
                        ProcessUtilities.executioner(command)

                        command = 'chown -R vmail:vmail %s' % (EmailsHome)
                        ProcessUtilities.executioner(command)



                except BaseException as msg:
                    logging.CyberCPLogFileWriter.writeToFile('%s [SubmitCloudBackupRestore:1533]' % str(msg))

            ## Databases

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Restoring databases if any..,70')

            databases = json.loads(open('%s/databases.json' % (self.extractedPath), 'r').read())['databases']

            for db in databases:

                logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                          'Restoring database %s..,70' % (db['databaseName']))

                mysqlUtilities.mysqlUtilities.submitDBDeletion(db['databaseName'])

                if mysqlUtilities.mysqlUtilities.createDatabase(db['databaseName'], db['databaseUser'], "cyberpanel") == 0:
                    raise BaseException("Failed to create Databases!")

                newDB = Databases(website=self.website, dbName=db['databaseName'], dbUser=db['databaseUser'])
                newDB.save()

                mysqlUtilities.mysqlUtilities.restoreDatabaseBackup(db['databaseName'], self.databasesPath, db['password'])

            if self.extraArgs['sourceDomain'] != 'None':
                if self.extraArgs['sourceDomain'] != self.extraArgs['domain']:

                    try:
                        command = 'wp --info'
                        outout = ProcessUtilities.outputExecutioner(command)

                        if not outout.find('WP-CLI root dir:') > -1:
                            from plogical.applicationInstaller import ApplicationInstaller
                            ai = ApplicationInstaller(None, None)
                            ai.installWPCLI()
                    except subprocess.CalledProcessError:
                        from plogical.applicationInstaller import ApplicationInstaller
                        ai = ApplicationInstaller(None, None)
                        ai.installWPCLI()

                    path = '/home/%s/public_html' % (self.extraArgs['domain'])
                    command = "wp search-replace '%s' '%s' --path=%s --allow-root" % (self.extraArgs['sourceDomain'], self.extraArgs['domain'], path)
                    ProcessUtilities.outputExecutioner(command)

                    command = "wp search-replace 'www.%s' '%s' --path=%s --allow-root" % (
                    self.extraArgs['sourceDomain'], self.extraArgs['domain'], path)
                    ProcessUtilities.outputExecutioner(command)

                    command = "wp search-replace 'www.%s' '%s' --path=%s --allow-root" % (
                        self.extraArgs['domain'], self.extraArgs['domain'], path)
                    ProcessUtilities.outputExecutioner(command)


            command = 'rm -rf %s' % (self.extractedPath)
            ProcessUtilities.executioner(command)

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], 'Completed [200].')
        except BaseException as msg:
            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], '%s [404].' % str(msg))

    ### Cloud Backup functions ends

    def fetchAWSKeys(self):
        path = '/home/cyberpanel/.aws'
        credentials = path + '/credentials'

        data = open(credentials, 'r').readlines()

        aws_access_key_id = data[1].split(' ')[2].strip(' ').strip('\n')
        aws_secret_access_key = data[2].split(' ')[2].strip(' ').strip('\n')
        region = data[3].split(' ')[2].strip(' ').strip('\n')

        return aws_access_key_id, aws_secret_access_key, region

    def SubmitS3BackupRestore(self):

        try:
            import json
            if os.path.exists(backupUtilities.CloudBackupConfigPath):
                result = json.loads(open(backupUtilities.CloudBackupConfigPath, 'r').read())
                self.nice = result['nice']
                self.cpu = result['cpu']
                self.time = int(result['time'])
            else:
                self.nice = backupUtilities.NiceDefault
                self.cpu = backupUtilities.CPUDefault
                self.time = int(backupUtilities.time)

            ### First Download file from S3

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                          'Starting file download from S3..,0')

            import boto3
            from s3Backups.models import BackupPlan
            plan = BackupPlan.objects.get(name=self.extraArgs['planName'])

            aws_access_key_id, aws_secret_access_key, region = self.fetchAWSKeys()

            if region.find('http') > -1:
                s3 = boto3.resource(
                    's3',
                    aws_access_key_id=aws_access_key_id,
                    aws_secret_access_key=aws_secret_access_key,
                    endpoint_url=region
                )
            else:
                s3 = boto3.resource(
                    's3',
                    aws_access_key_id=aws_access_key_id,
                    aws_secret_access_key=aws_secret_access_key,
                )

            self.BackupPath = '/home/cyberpanel/backups/%s/%s' % (self.extraArgs['domain'], self.extraArgs['backupFile'].split('/')[-1])

            s3.Bucket(plan.bucket).download_file(self.extraArgs['backupFile'], self.BackupPath)

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                          'File download completed..,5')


            self.website = Websites.objects.get(domain=self.extraArgs['domain'])

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Extracting main archive..,0')


            command = 'tar -xf %s -C %s' % (self.BackupPath, '/home/cyberpanel/backups/%s/' % (self.extraArgs['domain']))
            ProcessUtilities.executioner(command)

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Main Archive extracted,20')

            self.extractedPath = '/home/cyberpanel/backups/%s/%s' % (self.extraArgs['domain'], self.extraArgs['backupFile'].split('/')[-1].rstrip('.tar.gz'))

            self.dataPath = '%s/data' % (self.extractedPath)
            self.databasesPath = '%s/databases' % (self.extractedPath)
            self.emailsPath = '%s/emails' % (self.extractedPath)

            ## Data

            if os.path.exists(self.dataPath):
                try:
                    logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                              'Creating child domains if any..,20')
                    childDomains = json.loads(open('%s/data.json' % (self.extractedPath), 'r').read())['ChildDomains']

                    for child in childDomains:
                        try:
                            ch = ChildDomains.objects.get(domain=child['domain'])
                        except:
                            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                                      'Creating %s,20' % (child['domain']))
                            virtualHostUtilities.createDomain(self.website.domain, child['domain'], child['php'], child['path'], 1, 0, 0,
                                                              self.website.admin.userName, 0, "/home/cyberpanel/" + str(randint(1000, 9999)))

                except BaseException as msg:
                    logging.CyberCPLogFileWriter.writeToFile('%s [SubmitCloudBackupRestore:1533]' % str(msg))

                homePath = '/home/%s' % (self.website.domain)
                command = 'rm -rf %s' % (homePath)
                ProcessUtilities.executioner(command)

                command = 'mv %s/%s %s' % (self.dataPath, self.website.domain, '/home')
                ProcessUtilities.executioner(command)

                from filemanager.filemanager import FileManager

                fm = FileManager(None, None)
                fm.fixPermissions(self.website.domain)

            ## Emails

            if os.path.exists(self.emailsPath):
                try:
                    logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                              'Creating emails if any..,40')
                    emails = json.loads(open('%s/emails.json' % (self.extractedPath), 'r').read())['emails']
                    from mailServer.models import Domains, EUsers
                    emailDomain = Domains.objects.get(domain=self.website.domain)

                    for email in emails:
                        try:
                            eu = EUsers.objects.get(emailOwner=emailDomain, email=email['email'])
                        except:
                            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                                      'Creating %s,40' % (email['email']))
                            emailAcct = EUsers(emailOwner=emailDomain, email=email['email'], password=email['password'])
                            emailAcct.mail = 'maildir:/home/vmail/%s/%s/Maildir' % (self.website.domain, email['email'].split('@')[0])
                            emailAcct.save()

                        EmailsHome = '/home/vmail/%s' % (self.website.domain)

                        command = f'rm -rf {EmailsHome}'
                        ProcessUtilities.executioner(command)

                        command = 'mv %s/%s /home/vmail' % (self.emailsPath, self.website.domain)
                        ProcessUtilities.executioner(command)

                        command = 'chown -R vmail:vmail %s' % (EmailsHome)
                        ProcessUtilities.executioner(command)



                except BaseException as msg:
                    logging.CyberCPLogFileWriter.writeToFile('%s [SubmitCloudBackupRestore:1533]' % str(msg))

            ## Databases

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                      'Restoring databases if any..,70')

            databases = json.loads(open('%s/databases.json' % (self.extractedPath), 'r').read())['databases']

            for db in databases:

                logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'],
                                                          'Restoring database %s..,70' % (db['databaseName']))

                mysqlUtilities.mysqlUtilities.submitDBDeletion(db['databaseName'])

                if mysqlUtilities.mysqlUtilities.createDatabase(db['databaseName'], db['databaseUser'], "cyberpanel") == 0:
                    raise BaseException("Failed to create Databases!")

                newDB = Databases(website=self.website, dbName=db['databaseName'], dbUser=db['databaseUser'])
                newDB.save()

                mysqlUtilities.mysqlUtilities.restoreDatabaseBackup(db['databaseName'], self.databasesPath, db['password'])


            command = 'rm -rf %s' % (self.extractedPath)
            ProcessUtilities.executioner(command)

            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], 'Completed [200].')
        except BaseException as msg:
            logging.CyberCPLogFileWriter.statusWriter(self.extraArgs['tempStatusPath'], '%s [404].' % str(msg))

def submitBackupCreation(tempStoragePath, backupName, backupPath, backupDomain):
    try:
        ## /home/example.com/backup/backup-example.com-02.13.2018_10-24-52 -- tempStoragePath
        ## backup-example.com-02.13.2018_10-24-52 -- backup name
        ## /home/example.com/backup - backupPath
        ## /home/cyberpanel/1047.xml - metaPath
        ## /home/backup/<random_number> - CPHomeStorage

        status = os.path.join(backupPath, 'status')

        ### Lets first see if enough space for backups is available

        from plogical.IncScheduler import IncScheduler
        import json
        from plogical.getSystemInformation import SystemInformation
        #
        # IncScheduler.CalculateAndUpdateDiskUsage()

        try:

            website = Websites.objects.get(domain=backupDomain)
            DiskUsageOfSite = json.loads(website.config)['DiskUsage']
            used_disk, free_disk, percent_used = SystemInformation.GetRemainingDiskUsageInMBs()


            if float(free_disk) <= float(DiskUsageOfSite):
                command = f"echo 'Disk space exceeded the website size. [2065][5009]' > %s"
                ProcessUtilities.executioner(command, website.externalApp)
                return 0
        except:
            pass

        ###



        website = Websites.objects.get(domain=backupDomain)

        ##

        CPHomeStorage = f'/home/backup/{generate_pass(5)}'

        ### Now make this random directory to store data so taht we dont run any root file operations in user home dir

        command = f'mkdir -p {CPHomeStorage} && chown {website.externalApp}:{website.externalApp} {CPHomeStorage}'
        ProcessUtilities.executioner(command, 'root', True)

        ##

        schedulerPath = f'/home/cyberpanel/{backupDomain}-backup.txt'

        ##

        command = f'mkdir -p {tempStoragePath}'
        ProcessUtilities.executioner(command, website.externalApp)

        ##

        command = f'touch {status}'
        ProcessUtilities.executioner(command, website.externalApp)

        result = backupUtilities.prepareBackupMeta(backupDomain, backupName, tempStoragePath, backupPath)

        if result[0] == 0:
            writeToFile = open(schedulerPath, 'w')
            writeToFile.writelines('1325')
            writeToFile.close()
            command = "echo '%s [1084][5009]' > %s" % (str(result[1]), status)
            ProcessUtilities.executioner(command, website.externalApp)
            return 0


        command = 'chown %s:%s %s' % (website.externalApp, website.externalApp, result[2])
        ProcessUtilities.executioner(command)

        logging.CyberCPLogFileWriter.writeToFile(backupPath)
        logging.CyberCPLogFileWriter.writeToFile(tempStoragePath)

        execPath = "sudo nice -n 10 /usr/local/CyberCP/bin/python " + virtualHostUtilities.cyberPanel + "/plogical/backupUtilities.py"
        execPath = execPath + " startBackup --tempStoragePath " + tempStoragePath + " --backupName " \
                   + backupName + " --backupPath " + backupPath + ' --backupDomain ' + backupDomain + ' --metaPath %s' % (
                       result[2])

        output = ProcessUtilities.outputExecutioner(execPath, website.externalApp)

        if output.find('[5009]') > -1:
            logging.CyberCPLogFileWriter.writeToFile(output)
            writeToFile = open(schedulerPath, 'w')
            writeToFile.writelines(output)
            writeToFile.close()
            return 0

        ## Backing up databases

        command = f'chown cyberpanel:cyberpanel {result[2]}'
        ProcessUtilities.executioner(command)

        backupMetaData = ElementTree.parse(result[2])

        databases = backupMetaData.findall('Databases/database')

        for database in databases:

            dbName = database.find('dbName').text
            res = mysqlUtilities.mysqlUtilities.createDatabaseBackup(dbName, '/home/cyberpanel')
            if res == 0:
                ## This login can be further improved later.
                logging.CyberCPLogFileWriter.writeToFile('Failed to create database backup for %s. This could be false positive, moving on.' % (dbName))

            command = f'mv /home/cyberpanel/{dbName}.sql {CPHomeStorage}/{dbName}.sql'
            ProcessUtilities.executioner(command)


        ##

        #output = ProcessUtilities.outputExecutioner(execPath, website.externalApp)

        execPath = "sudo nice -n 10 /usr/local/CyberCP/bin/python " + virtualHostUtilities.cyberPanel + "/plogical/backupUtilities.py"
        execPath = execPath + " BackupRoot --tempStoragePath " + tempStoragePath + " --backupName " \
                   + backupName + " --backupPath " + backupPath + ' --backupDomain ' + backupDomain + ' --metaPath %s --externalApp %s' % (
                       result[2], website.externalApp) + f' --CPHomeStorage {CPHomeStorage}'

        ProcessUtilities.executioner(execPath, 'root')

        #command = 'chown -R %s:%s %s' % (website.externalApp, website.externalApp, backupPath)
        #ProcessUtilities.executioner(command)

        command = f'rm -f {result[2]}'
        ProcessUtilities.executioner(command, 'cyberpanel')

    except BaseException as msg:
        logging.CyberCPLogFileWriter.writeToFile(
            f"{str(msg)}  [submitBackupCreation]")

def cancelBackupCreation(backupCancellationDomain, fileName):
    try:

        path = f"/home/{backupCancellationDomain}/backup/pid"

        pid = open(path, "r").readlines()[0]

        try:
            os.kill(int(pid), signal.SIGKILL)
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(f"{str(msg)} [cancelBackupCreation]")

        backupPath = f"/home/{backupCancellationDomain}/backup/"

        tempStoragePath = backupPath + fileName

        try:
            os.remove(f"{tempStoragePath}.tar.gz")
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(f"{str(msg)} [cancelBackupCreation]")

        try:
            rmtree(tempStoragePath)
        except BaseException as msg:
            logging.CyberCPLogFileWriter.writeToFile(f"{str(msg)} [cancelBackupCreation]")

        status = open(backupPath + 'status', "w")
        status.write("Aborted manually. [1165][5009]")
        status.close()
    except BaseException as msg:
        logging.CyberCPLogFileWriter.writeToFile(
            f"{str(msg)}  [cancelBackupCreation]")
        print(f"0, {str(msg)}")

def submitRestore(backupFile, dir):
    try:

        p = Process(target=backupUtilities.startRestore, args=(backupFile, dir,))
        p.start()

        print("1,None")

    except BaseException as msg:
        logging.CyberCPLogFileWriter.writeToFile(
            str(msg) + "  [cancelBackupCreation]")
        print(f"0, {str(msg)}")

def submitDestinationCreation(ipAddress, password, port='22', user='root'):
    setupKeys = backupUtilities.setupSSHKeys(ipAddress, password, port, user)

    if setupKeys[0] == 1:
        backupUtilities.createBackupDir(ipAddress, port, user)
        print("1,None")
    else:
        print(setupKeys[1])

def getConnectionStatus(ipAddress):
    try:
        checkCon = backupUtilities.checkConnection(ipAddress)

        if checkCon[0] == 1:
            print("1,None")
        else:
            print(checkCon[1])

    except BaseException as msg:
        print(str(msg))

def FetchOCBackupsFolders(id, owner):
    # Load the private key
    private_key_path = '/root/.ssh/cyberpanel'
    keyPrivate = paramiko.RSAKey(filename=private_key_path)

    from IncBackups.models import OneClickBackups
    admin = Administrator.objects.get(userName=owner)
    ocb = OneClickBackups.objects.get(pk=id, owner=admin)

    nbd = NormalBackupDests.objects.get(name=ocb.sftpUser)
    ip = json.loads(nbd.config)['ip']

    # Connect to the remote server using the private key
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(ip, username=ocb.sftpUser, pkey=keyPrivate)

    # Command to list directories under the specified path
    command = f"ls -d cpbackups/*/"

    # Execute the command
    stdin, stdout, stderr = ssh.exec_command(command)

    # Read the results
    directories = stdout.read().decode().splitlines()

    # Print directories
    for directory in directories:
        print(directory)



def main():
    parser = argparse.ArgumentParser(description='CyberPanel Backup Generator')
    parser.add_argument('function', help='Specify a function to call!')
    parser.add_argument('--tempStoragePath', help='')
    parser.add_argument('--backupName', help='!')
    parser.add_argument('--backupPath', help='')
    parser.add_argument('--backupDomain', help='')
    parser.add_argument('--metaPath', help='')

    ## Destination Creation

    parser.add_argument('--ipAddress', help='')
    parser.add_argument('--password', help='')
    parser.add_argument('--port', help='')
    parser.add_argument('--user', help='')

    ## backup cancellation arguments

    parser.add_argument('--backupCancellationDomain', help='')
    parser.add_argument('--fileName', help='')

    ## backup restore arguments

    parser.add_argument('--backupFile', help='')
    parser.add_argument('--dir', help='')

    ### For Cloud Backups

    parser.add_argument('--data', help='')
    parser.add_argument('--emails', help='')
    parser.add_argument('--databases', help='')
    parser.add_argument('--path', help='')
    parser.add_argument('--ip', help='')
    parser.add_argument('--sourceDomain', help='')
    parser.add_argument('--destinationDomain', help='')

    ## FOR S3

    parser.add_argument('--planName', help='')
    parser.add_argument('--externalApp', help='')

    ### CPHomeStorage

    parser.add_argument('--CPHomeStorage', help='')

    ### id

    parser.add_argument('--id', help='')


    args = parser.parse_args()

    if args.function == "submitBackupCreation":
        submitBackupCreation(args.tempStoragePath, args.backupName, args.backupPath, args.backupDomain)
    elif args.function == "cancelBackupCreation":
        cancelBackupCreation(args.backupCancellationDomain, args.fileName)
    elif args.function == "submitRestore":
        submitRestore(args.backupFile, args.dir)
    elif args.function == "submitDestinationCreation":
        submitDestinationCreation(args.ipAddress, args.password, args.port, args.user)
    elif args.function == "getConnectionStatus":
        getConnectionStatus(args.ipAddress)
    elif args.function == "startBackup":
        backupUtilities.startBackup(args.tempStoragePath, args.backupName, args.backupPath, args.metaPath)
    elif args.function == "BackupRoot":
        backupUtilities.BackupRoot(args.tempStoragePath, args.backupName, args.backupPath, args.metaPath, args.externalApp, args.CPHomeStorage)
    elif args.function == 'CloudBackup':
        extraArgs = {}
        extraArgs['domain'] = args.backupDomain
        extraArgs['tempStatusPath'] = args.tempStoragePath
        extraArgs['data'] = int(args.data)
        extraArgs['emails'] = int(args.emails)
        extraArgs['databases'] = int(args.databases)
        extraArgs['path'] = args.path
        extraArgs['port'] = args.port
        extraArgs['ip'] = args.ip
        extraArgs['destinationDomain'] = args.destinationDomain
        bu = backupUtilities(extraArgs)
        bu.CloudBackups()

    elif args.function == 'SubmitCloudBackupRestore':
        extraArgs = {}
        extraArgs['domain'] = args.backupDomain
        extraArgs['tempStatusPath'] = args.tempStoragePath
        extraArgs['backupFile'] = args.backupFile
        extraArgs['sourceDomain'] = args.sourceDomain
        bu = backupUtilities(extraArgs)
        bu.SubmitCloudBackupRestore()
    elif args.function == 'SubmitS3BackupRestore':
        extraArgs = {}
        extraArgs['domain'] = args.backupDomain
        extraArgs['tempStatusPath'] = args.tempStoragePath
        extraArgs['backupFile'] = args.backupFile
        extraArgs['planName'] = args.planName
        bu = backupUtilities(extraArgs)
        bu.SubmitS3BackupRestore()

    elif args.function == 'FetchOCBackupsFolders':
        FetchOCBackupsFolders(args.id, args.user)

if __name__ == "__main__":
    main()