diff --git a/CyberCP/secMiddleware.py b/CyberCP/secMiddleware.py index 68015c6fd..3f4e8b61b 100755 --- a/CyberCP/secMiddleware.py +++ b/CyberCP/secMiddleware.py @@ -60,7 +60,7 @@ class secMiddleware: if request.build_absolute_uri().find('saveSpamAssassinConfigurations') > -1 or request.build_absolute_uri().find('docker') > -1 or request.build_absolute_uri().find('cloudAPI') > -1 or request.build_absolute_uri().find('filemanager') > -1 or request.build_absolute_uri().find('verifyLogin') > -1 or request.build_absolute_uri().find('submitUserCreation') > -1: continue - if key == 'ports' or key == 'imageByPass' or key == 'passwordByPass' or key == 'cronCommand' or key == 'emailMessage' or key == 'configData' or key == 'rewriteRules' or key == 'modSecRules' or key == 'recordContentTXT' or key == 'SecAuditLogRelevantStatus' or key == 'fileContent': + if key == 'backupDestinations' or key == 'ports' or key == 'imageByPass' or key == 'passwordByPass' or key == 'cronCommand' or key == 'emailMessage' or key == 'configData' or key == 'rewriteRules' or key == 'modSecRules' or key == 'recordContentTXT' or key == 'SecAuditLogRelevantStatus' or key == 'fileContent': continue if value.find(';') > -1 or value.find('&&') > -1 or value.find('|') > -1 or value.find('...') > -1 \ or value.find("`") > -1 or value.find("$") > -1 or value.find("(") > -1 or value.find(")") > -1 \ diff --git a/IncBackups/IncBackups.py b/IncBackups/IncBackups.py new file mode 100644 index 000000000..792a8fd6e --- /dev/null +++ b/IncBackups/IncBackups.py @@ -0,0 +1,375 @@ +#!/usr/local/CyberCP/bin/python2 +import os,sys +sys.path.append('/usr/local/CyberCP') +import django +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings") +django.setup() +import threading as multi +from plogical.processUtilities import ProcessUtilities +import time +from .models import IncJob, JobSnapshots +from websiteFunctions.models import Websites +import plogical.randomPassword as randomPassword +from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging +from xml.etree.ElementTree import Element, SubElement +from xml.etree import ElementTree +from xml.dom import minidom +from backup.models import DBUsers +import plogical.mysqlUtilities as mysqlUtilities +from plogical.backupUtilities import backupUtilities +from plogical.dnsUtilities import DNS +from mailServer.models import Domains as eDomains +from random import randint + + +class IncJobs(multi.Thread): + + def __init__(self, function, extraArgs): + multi.Thread.__init__(self) + self.function = function + self.extraArgs = extraArgs + self.repoPath = '' + self.passwordFile = '' + self.statusPath = '' + self.website = '' + self.backupDestinations = '' + self.jobid = 0 + + def run(self): + + if self.function == 'createBackup': + self.createBackup() + + def prepareBackupMeta(self): + try: + + ######### Generating meta + + ## XML Generation + + metaFileXML = Element('metaFile') + + child = SubElement(metaFileXML, 'masterDomain') + child.text = self.website.domain + + child = SubElement(metaFileXML, 'phpSelection') + child.text = self.website.phpSelection + + child = SubElement(metaFileXML, 'externalApp') + child.text = self.website.externalApp + + childDomains = self.website.childdomains_set.all() + + databases = self.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: + try: + dbuser = DBUsers.objects.get(user=items.dbUser) + userToTry = items.dbUser + except: + dbusers = DBUsers.objects.all().filter(user=items.dbUser) + userToTry = items.dbUser + for it in dbusers: + dbuser = it + break + + userToTry = mysqlUtilities.mysqlUtilities.fetchuser(items.dbUser) + + try: + dbuser = DBUsers.objects.get(user=userToTry) + except: + dbusers = DBUsers.objects.all().filter(user=userToTry) + for it in dbusers: + dbuser = it + break + + databaseXML = Element('database') + + child = SubElement(databaseXML, 'dbName') + child.text = items.dbName + child = SubElement(databaseXML, 'dbUser') + child.text = userToTry + child = SubElement(databaseXML, 'password') + child.text = dbuser.password + + databasesXML.append(databaseXML) + + metaFileXML.append(databasesXML) + + ## Get Aliases + + aliasesXML = Element('Aliases') + + aliases = backupUtilities.getAliases(self.website.domain) + + for items in aliases: + child = SubElement(aliasesXML, 'alias') + child.text = items + + metaFileXML.append(aliasesXML) + + ## Finish Alias + + ## DNS Records XML + + try: + + dnsRecordsXML = Element("dnsrecords") + dnsRecords = DNS.getDNSRecords(self.website.domain) + + 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, msg: + logging.statusWriter(self.statusPath, '%s. [158:prepMeta]' % (str(msg)), 1) + + ## Email accounts XML + + try: + emailRecordsXML = Element('emails') + eDomain = eDomains.objects.get(domain=self.website.domain) + 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, msg: + logging.writeToFile(self.statusPath, '%s. [warning:179:prepMeta]' % (str(msg)), 1) + + ## 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-06-50-03-Thu-Feb-2018/meta.xml -- metaPath + + metaPath = '/home/cyberpanel/%s' % (str(randint(1000, 9999))) + + xmlpretty = prettify(metaFileXML).encode('ascii', 'ignore') + metaFile = open(metaPath, 'w') + metaFile.write(xmlpretty) + metaFile.close() + os.chmod(metaPath, 0640) + + ## meta generated + + logging.statusWriter(self.statusPath, 'Meta data is ready..', 1) + + metaPathNew = '/home/%s/meta.xml' % (self.website.domain) + command = 'mv %s %s' % (metaPath, metaPathNew) + ProcessUtilities.executioner(command) + + command = 'chown %s:%s %s' % (self.website.externalApp, self.website.externalApp, metaPathNew) + ProcessUtilities.executioner(command) + + return 1 + + except BaseException, msg: + logging.statusWriter(self.statusPath, "%s [207][5009]" % (str(msg)), 1) + return 0 + + def backupData(self): + try: + logging.statusWriter(self.statusPath, 'Backing up data..', 1) + + if self.backupDestinations == 'local': + backupPath = '/home/%s' % (self.website.domain) + command = 'restic -r %s backup %s --password-file %s --exclude %s' % (self.repoPath, backupPath, self.passwordFile, self.repoPath) + snapShotid = ProcessUtilities.outputExecutioner(command).split(' ')[-2] + + newSnapshot = JobSnapshots(job=self.jobid, type='data:%s' % (backupPath), snapshotid=snapShotid, destination=self.backupDestinations) + newSnapshot.save() + + + elif self.backupDestinations[:4] == 'sftp': + remotePath = '/home/backup/%s' % (self.website.domain) + backupPath = '/home/%s' % (self.website.domain) + command = 'export PATH=${PATH}:/usr/bin && restic -r %s:%s backup %s --password-file %s --exclude %s' % (self.backupDestinations, remotePath, backupPath, self.passwordFile, self.repoPath) + snapShotid = ProcessUtilities.outputExecutioner(command).split(' ')[-2] + newSnapshot = JobSnapshots(job=self.jobid, type='data:%s' % (remotePath), snapshotid=snapShotid, + destination=self.backupDestinations) + newSnapshot.save() + + logging.statusWriter(self.statusPath, 'Data for %s backed to %s.' % (self.website.domain, self.backupDestinations), 1) + return 1 + except BaseException, msg: + logging.statusWriter(self.statusPath,'%s. [IncJobs.backupData.223][5009]' % str(msg), 1) + return 0 + + def backupDatabases(self): + try: + logging.statusWriter(self.statusPath, 'Backing up databases..', 1) + + databases = self.website.databases_set.all() + + for items in databases: + if mysqlUtilities.mysqlUtilities.createDatabaseBackup(items.dbName, '/home/cyberpanel') == 0: + return 0 + + dbPath = '/home/cyberpanel/%s.sql' % (items.dbName) + + if self.backupDestinations == 'local': + command = 'restic -r %s backup %s --password-file %s' % (self.repoPath, dbPath, self.passwordFile) + snapShotid = ProcessUtilities.outputExecutioner(command).split(' ')[-2] + + newSnapshot = JobSnapshots(job=self.jobid, type='database:%s' % (items.dbName), snapshotid=snapShotid, destination=self.backupDestinations) + newSnapshot.save() + + elif self.backupDestinations[:4] == 'sftp': + remotePath = '/home/backup/%s' % (self.website.domain) + command = 'export PATH=${PATH}:/usr/bin && restic -r %s:%s backup %s --password-file %s --exclude %s' % ( + self.backupDestinations, remotePath, dbPath, self.passwordFile, self.repoPath) + snapShotid = ProcessUtilities.outputExecutioner(command).split(' ')[-2] + newSnapshot = JobSnapshots(job=self.jobid, type='database:%s' % (items.dbName), snapshotid=snapShotid, + destination=self.backupDestinations) + newSnapshot.save() + return 1 + except BaseException, msg: + logging.statusWriter(self.statusPath,'%s. [IncJobs.backupDatabases.269][5009]' % str(msg), 1) + return 0 + + def emailBackup(self): + try: + logging.statusWriter(self.statusPath, 'Backing up emails..', 1) + + backupPath = '/home/vmail/%s' % (self.website.domain) + + if os.path.exists(backupPath): + if self.backupDestinations == 'local': + logging.statusWriter(self.statusPath, 'hello world', 1) + command = 'restic -r %s backup %s --password-file %s' % ( + self.repoPath, backupPath, self.passwordFile) + snapShotid = ProcessUtilities.outputExecutioner(command).split(' ')[-2] + + newSnapshot = JobSnapshots(job=self.jobid, type='email:%s' % (backupPath), snapshotid=snapShotid, + destination=self.backupDestinations) + newSnapshot.save() + logging.statusWriter(self.statusPath, 'hello world 2', 1) + + elif self.backupDestinations[:4] == 'sftp': + remotePath = '/home/backup/%s' % (self.website.domain) + command = 'export PATH=${PATH}:/usr/bin && restic -r %s:%s backup %s --password-file %s --exclude %s' % ( + self.backupDestinations, remotePath, backupPath, self.passwordFile, self.repoPath) + snapShotid = ProcessUtilities.outputExecutioner(command).split(' ')[-2] + newSnapshot = JobSnapshots(job=self.jobid, type='email:%s' % (backupPath), snapshotid=snapShotid, + destination=self.backupDestinations) + newSnapshot.save() + + logging.statusWriter(self.statusPath, 'Emails for %s backed to %s.' % (self.website.domain, self.backupDestinations), 1) + return 1 + except BaseException, msg: + logging.statusWriter(self.statusPath,'%s. [IncJobs.backupDatabases.269][5009]' % str(msg), 1) + return 0 + + def initiateRepo(self): + try: + logging.statusWriter(self.statusPath, 'Will first initiate backup repo..', 1) + + if self.backupDestinations == 'local': + command = 'restic init --repo %s --password-file %s' % (self.repoPath, self.passwordFile) + ProcessUtilities.executioner(command, self.website.externalApp) + + elif self.backupDestinations[:4] == 'sftp': + remotePath = '/home/backup/%s' % (self.website.domain) + command = 'export PATH=${PATH}:/usr/bin && restic init --repo %s:%s --password-file %s' % (self.backupDestinations, remotePath, self.passwordFile) + ProcessUtilities.executioner(command) + + logging.statusWriter(self.statusPath, 'Repo %s initiated for %s.' % (self.backupDestinations, self.website.domain), 1) + return 1 + except BaseException, msg: + logging.statusWriter(self.statusPath,'%s. [IncJobs.initiateRepo.47][5009]' % str(msg), 1) + return 0 + + def createBackup(self): + self.statusPath = self.extraArgs['tempPath'] + website = self.extraArgs['website'] + self.backupDestinations = self.extraArgs['backupDestinations'] + websiteData = self.extraArgs['websiteData'] + websiteEmails = self.extraArgs['websiteEmails'] + websiteSSLs = self.extraArgs['websiteSSLs'] + websiteDatabases = self.extraArgs['websiteDatabases'] + + self.website = Websites.objects.get(domain=website) + + newJob = IncJob(website=self.website) + newJob.save() + + self.jobid = newJob + + self.passwordFile = '/home/%s/%s' % (self.website.domain, self.website.domain) + password = randomPassword.generate_pass() + + self.repoPath = '/home/%s/incbackup' % (self.website.domain) + + if not os.path.exists(self.passwordFile): + command = 'echo "%s" > %s' % (password, self.passwordFile) + ProcessUtilities.executioner(command, self.website.externalApp) + + + if self.initiateRepo() == 0: + return + + if self.prepareBackupMeta() == 0: + return + + if websiteData: + if self.backupData() == 0: + return + + if websiteDatabases: + if self.backupDatabases() == 0: + return + + + if websiteEmails: + if self.emailBackup() == 0: + return + + logging.statusWriter(self.statusPath, 'Completed', 1) \ No newline at end of file diff --git a/IncBackups/models.py b/IncBackups/models.py index 1dfab7604..877b97a56 100644 --- a/IncBackups/models.py +++ b/IncBackups/models.py @@ -1,6 +1,15 @@ -# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models +from websiteFunctions.models import Websites +from datetime import datetime -# Create your models here. +class IncJob(models.Model): + website = models.ForeignKey(Websites) + date = models.DateTimeField(default=datetime.now, blank=True) + +class JobSnapshots(models.Model): + job = models.ForeignKey(IncJob) + type = models.CharField(max_length=300) + snapshotid = models.CharField(max_length=50) + destination = models.CharField(max_length=200, default='') \ No newline at end of file diff --git a/IncBackups/static/IncBackups/IncBackups.js b/IncBackups/static/IncBackups/IncBackups.js index a144ea0dd..84766333d 100644 --- a/IncBackups/static/IncBackups/IncBackups.js +++ b/IncBackups/static/IncBackups/IncBackups.js @@ -6,50 +6,24 @@ app.controller('createIncrementalBackups', function ($scope, $http, $timeout) { $scope.backupButton = true; $scope.cyberpanelLoading = true; $scope.runningBackup = true; - $scope.cancelButton = true; - populateCurrentRecords(); - - $scope.cancelBackup = function () { - - var backupCancellationDomain = $scope.websiteToBeBacked; - - url = "/backup/cancelBackupCreation"; - - var data = { - backupCancellationDomain: backupCancellationDomain, - fileName: $scope.fileName, - }; - - var config = { - headers: { - 'X-CSRFToken': getCookie('csrftoken') - } - }; - - $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); - - }; $scope.fetchDetails = function () { getBackupStatus(); - populateCurrentRecords(); + $scope.populateCurrentRecords(); $scope.destination = false; $scope.runningBackup = true; - }; - function getBackupStatus() { $scope.cyberpanelLoadingBottom = false; - var websiteToBeBacked = $scope.websiteToBeBacked; - - url = "/backup/backupStatus"; + url = "/IncrementalBackups/getBackupStatus"; var data = { - websiteToBeBacked: websiteToBeBacked, + websiteToBeBacked: $scope.websiteToBeBacked, + tempPath: $scope.tempPath }; var config = { @@ -72,18 +46,16 @@ app.controller('createIncrementalBackups', function ($scope, $http, $timeout) { $scope.cyberpanelLoadingBottom = true; $scope.destination = false; $scope.runningBackup = false; - $scope.cancelButton = true; $scope.backupButton = false; $scope.cyberpanelLoading = true; $scope.fileName = response.data.fileName; $scope.status = response.data.status; - populateCurrentRecords(); + $scope.populateCurrentRecords(); return; } else { $scope.destination = true; $scope.backupButton = true; $scope.runningBackup = false; - $scope.cancelButton = false; $scope.fileName = response.data.fileName; $scope.status = response.data.status; @@ -94,7 +66,6 @@ app.controller('createIncrementalBackups', function ($scope, $http, $timeout) { $timeout.cancel(); $scope.cyberpanelLoadingBottom = true; $scope.cyberpanelLoading = true; - $scope.cancelButton = true; $scope.backupButton = false; } @@ -103,22 +74,18 @@ app.controller('createIncrementalBackups', function ($scope, $http, $timeout) { function cantLoadInitialDatas(response) { } - }; - + } $scope.destinationSelection = function () { $scope.backupButton = false; }; + $scope.populateCurrentRecords = function () { - function populateCurrentRecords() { - - var websiteToBeBacked = $scope.websiteToBeBacked; - - url = "/backup/getCurrentBackups"; + url = "/IncrementalBackups/fetchCurrentBackups"; var data = { - websiteToBeBacked: websiteToBeBacked, + websiteToBeBacked: $scope.websiteToBeBacked, }; var config = { @@ -132,31 +99,43 @@ app.controller('createIncrementalBackups', function ($scope, $http, $timeout) { function ListInitialDatas(response) { - - - if (response.data.fetchStatus == 1) { + if (response.data.status === 1) { $scope.records = JSON.parse(response.data.data); + } else { + new PNotify({ + title: 'Error!', + text: response.data.error_message, + type: 'error' + }); } - } function cantLoadInitialDatas(response) { + new PNotify({ + title: 'Operation Failed!', + text: 'Could not connect to server, please refresh this page', + type: 'error' + }); } }; - $scope.createBackup = function () { - var websiteToBeBacked = $scope.websiteToBeBacked; $scope.cyberpanelLoading = false; - url = "/backup/submitBackupCreation"; + url = "/IncrementalBackups/submitBackupCreation"; var data = { - websiteToBeBacked: websiteToBeBacked, + websiteToBeBacked: $scope.websiteToBeBacked, + backupDestinations: $scope.backupDestinations, + websiteData: $scope.websiteData, + websiteEmails: $scope.websiteEmails, + websiteSSLs: $scope.websiteSSLs, + websiteDatabases: $scope.websiteDatabases + }; var config = { @@ -171,8 +150,8 @@ app.controller('createIncrementalBackups', function ($scope, $http, $timeout) { function ListInitialDatas(response) { - - if (response.data.metaStatus === 1) { + if (response.data.status === 1) { + $scope.tempPath = response.data.tempPath; getBackupStatus(); } @@ -183,11 +162,10 @@ app.controller('createIncrementalBackups', function ($scope, $http, $timeout) { }; - $scope.deleteBackup = function (id) { - url = "/backup/deleteBackup"; + url = "/IncrementalBackups/deleteBackup"; var data = { backupID: id, @@ -206,22 +184,64 @@ app.controller('createIncrementalBackups', function ($scope, $http, $timeout) { function ListInitialDatas(response) { - if (response.data.deleteStatus == 1) { + if (response.data.status === 1) { - populateCurrentRecords(); + $scope.populateCurrentRecords(); - } else { - } } function cantLoadInitialDatas(response) { + } + }; + + $scope.restore = function (id) { + + $scope.cyberpanelLoading = false; + + + url = "/IncrementalBackups/fetchRestorePoints"; + + var data = { + id: id + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + $scope.cyberpanelLoading = true; + if (response.data.status === 1) { + $scope.jobs = JSON.parse(response.data.data); + } else { + new PNotify({ + title: 'Operation Failed!', + text: response.data.error_message, + type: 'error' + }); + } + } + function cantLoadInitialDatas(response) { + $scope.cyberpanelLoading = true; + new PNotify({ + title: 'Operation Failed!', + text: 'Could not connect to server, please refresh this page', + type: 'error' + }); + } }; @@ -256,9 +276,9 @@ app.controller('incrementalDestinations', function ($scope, $http) { url = "/IncrementalBackups/populateCurrentRecords"; var type = 'SFTP'; - if ($scope.destinationType === 'SFTP'){ + if ($scope.destinationType === 'SFTP') { type = 'SFTP'; - }else{ + } else { type = 'AWS'; } @@ -307,14 +327,14 @@ app.controller('incrementalDestinations', function ($scope, $http) { url = "/IncrementalBackups/addDestination"; - if(type === 'SFTP'){ + if (type === 'SFTP') { var data = { type: type, IPAddress: $scope.IPAddress, password: $scope.password, backupSSHPort: $scope.backupSSHPort }; - }else { + } else { var data = { type: type, AWS_ACCESS_KEY_ID: $scope.AWS_ACCESS_KEY_ID, diff --git a/IncBackups/templates/IncBackups/createBackup.html b/IncBackups/templates/IncBackups/createBackup.html index 23a65a281..6694ee2c5 100755 --- a/IncBackups/templates/IncBackups/createBackup.html +++ b/IncBackups/templates/IncBackups/createBackup.html @@ -1,52 +1,58 @@ - {% extends "baseTemplate/index.html" %} {% load i18n %} {% block title %}{% trans "Create Incremental Backup" %}{% endblock %} {% block content %} -{% load static %} + {% load static %} -{% get_current_language as LANGUAGE_CODE %} - + {% get_current_language as LANGUAGE_CODE %} + -
-
-

{% trans "Back up Website" %} - {% trans "Backup Docs" %}

-

{% trans "This page can be used to create incremental backups for your websites." %}

-
+
+
+

{% trans "Back up Website" %} - {% trans "Backup Docs" %} +

+

{% trans "This page can be used to create incremental backups for your websites." %}

+
-
-
-

- {% trans "Back up Website" %} -

-
+
+
+

+ {% trans "Back up Website" %} +

+
-
+ -
- -
- -
-
+
+ +
+ +
+
-
- -
- -
-
+
+ +
+ +
+
-
+
@@ -57,6 +63,15 @@
+
+
+ +
+
+
+ +
+ + + + +
+
+
+ +
- + -
- -
- - - - - - - - - - - - - - - - -
{% trans "File Name" %}{% trans "Status" %}
{% trans "Running" %}{$ fileName $}{$ status $}
-
-
- - - - -
- -
- -
-
- -
- -
- -
-
- - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - -
{% trans "ID" %}{% trans "File" %}{% trans "Date" %}{% trans "Size" %}{% trans "Status" %}{% trans "Delete" %}
-
-
- - - - -
- -
-
-

{% trans "Cannot delete website, Error message: " %}{$ errorMessage $}

+
+ +
+
+
-
-

Website {$ deletedWebsite $} {% trans "Successfully Deleted" %}

+ + + +
+ +
+ + + + + + + + + + + + + + + + + + + + +
{% trans "ID" %}{% trans "Date" %}{% trans "Restore" %}{% trans "Delete" %}
+ Restore Points + +
-
+
+ + + +
- - - - - - +
+ +
-
- - -
{% endblock %} \ No newline at end of file diff --git a/IncBackups/urls.py b/IncBackups/urls.py index e1fab2ab1..ba3445dfc 100644 --- a/IncBackups/urls.py +++ b/IncBackups/urls.py @@ -7,5 +7,9 @@ urlpatterns = [ url(r'^addDestination$', views.addDestination, name='addDestinationInc'), url(r'^populateCurrentRecords$', views.populateCurrentRecords, name='populateCurrentRecordsInc'), url(r'^removeDestination$', views.removeDestination, name='removeDestinationInc'), - + url(r'^fetchCurrentBackups$', views.fetchCurrentBackups, name='fetchCurrentBackupsInc'), + url(r'^submitBackupCreation$', views.submitBackupCreation, name='submitBackupCreationInc'), + url(r'^getBackupStatus$', views.getBackupStatus, name='getBackupStatusInc'), + url(r'^deleteBackup$', views.deleteBackup, name='deleteBackupInc'), + url(r'^fetchRestorePoints$', views.fetchRestorePoints, name='fetchRestorePointsInc'), ] \ No newline at end of file diff --git a/IncBackups/views.py b/IncBackups/views.py index 37a429bc4..fa5fd90fc 100644 --- a/IncBackups/views.py +++ b/IncBackups/views.py @@ -8,6 +8,13 @@ from plogical.processUtilities import ProcessUtilities from plogical.virtualHostUtilities import virtualHostUtilities import json import os +from loginSystem.models import Administrator +from websiteFunctions.models import Websites +from .models import IncJob, JobSnapshots +from .IncBackups import IncJobs +from random import randint +import time +from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging # Create your views here. @@ -23,7 +30,19 @@ def createBackup(request): return ACLManager.loadError() websitesName = ACLManager.findAllSites(currentACL, userID) - return defRenderer(request, 'IncBackups/createBackup.html', {'websiteList': websitesName}) + + destinations = [] + destinations.append('local') + + path = '/home/cyberpanel/sftp' + + for items in os.listdir(path): + destinations.append('sftp:%s' % (items)) + + for items in os.listdir(path): + destinations.append('s3:s3.amazonaws.com/%s' % (items)) + + return defRenderer(request, 'IncBackups/createBackup.html', {'websiteList': websitesName, 'destinations': destinations}) except BaseException, msg: return HttpResponse(str(msg)) @@ -242,4 +261,236 @@ def removeDestination(request): except BaseException, msg: final_dic = {'destStatus': 0, 'error_message': str(msg)} final_json = json.dumps(final_dic) + return HttpResponse(final_json) + +def fetchCurrentBackups(request): + try: + userID = request.session['userID'] + currentACL = ACLManager.loadedACL(userID) + admin = Administrator.objects.get(pk=userID) + + data = json.loads(request.body) + backupDomain = data['websiteToBeBacked'] + + if ACLManager.checkOwnership(backupDomain, admin, currentACL) == 1: + pass + else: + return ACLManager.loadErrorJson('fetchStatus', 0) + + if ACLManager.checkOwnership(backupDomain, admin, currentACL) == 1: + pass + else: + return ACLManager.loadErrorJson() + + website = Websites.objects.get(domain=backupDomain) + + backups = website.incjob_set.all().reverse() + + json_data = "[" + checker = 0 + + for items in backups: + + includes = "" + + jobs = items.jobsnapshots_set.all() + + for job in jobs: + includes = '%s,%s:%s' % (includes, job.type, job.snapshotid) + + dic = {'id': items.id, + 'date': str(items.date), + 'includes': includes + } + + if checker == 0: + json_data = json_data + json.dumps(dic) + checker = 1 + else: + json_data = json_data + ',' + json.dumps(dic) + + json_data = json_data + ']' + final_json = json.dumps({'status': 1, 'error_message': "None", "data": json_data}) + return HttpResponse(final_json) + except BaseException, msg: + final_dic = {'status': 0, 'error_message': str(msg)} + final_json = json.dumps(final_dic) + return HttpResponse(final_json) + +def submitBackupCreation(request): + try: + userID = request.session['userID'] + currentACL = ACLManager.loadedACL(userID) + admin = Administrator.objects.get(pk=userID) + + data = json.loads(request.body) + backupDomain = data['websiteToBeBacked'] + backupDestinations = data['backupDestinations'] + + if ACLManager.checkOwnership(backupDomain, admin, currentACL) == 1: + pass + else: + return ACLManager.loadErrorJson('metaStatus', 0) + + tempPath = "/home/cyberpanel/" + str(randint(1000, 9999)) + + try: + websiteData = data['websiteData'] + except: + websiteData = False + + try: + websiteEmails = data['websiteEmails'] + except: + websiteEmails = False + + try: + websiteSSLs = data['websiteSSLs'] + except: + websiteSSLs = False + + + try: + websiteDatabases = data['websiteDatabases'] + except: + websiteDatabases = False + + extraArgs = {} + extraArgs['website'] = backupDomain + extraArgs['tempPath'] = tempPath + extraArgs['backupDestinations'] = backupDestinations + extraArgs['websiteData'] = websiteData + extraArgs['websiteEmails'] = websiteEmails + extraArgs['websiteSSLs'] = websiteSSLs + extraArgs['websiteDatabases'] = websiteDatabases + + startJob = IncJobs('createBackup', extraArgs) + startJob.start() + + + time.sleep(2) + + final_json = json.dumps({'status': 1, 'error_message': "None", 'tempPath': tempPath}) + return HttpResponse(final_json) + + except BaseException, msg: + logging.writeToFile(str(msg)) + final_dic = {'status': 0, 'metaStatus': 0, 'error_message': str(msg)} + final_json = json.dumps(final_dic) + return HttpResponse(final_json) + +def getBackupStatus(request): + try: + userID = request.session['userID'] + data = json.loads(request.body) + + status = data['tempPath'] + backupDomain = data['websiteToBeBacked'] + + domain = Websites.objects.get(domain=backupDomain) + + ## file name read ends + + if os.path.exists(status): + command = "sudo cat " + status + status = ProcessUtilities.outputExecutioner(command, 'cyberpanel') + + if status.find("Completed") > -1: + + ### Removing Files + + command = 'sudo rm -f ' + status + ProcessUtilities.executioner(command, 'cyberpanel') + + final_json = json.dumps( + {'backupStatus': 1, 'error_message': "None", "status": status, "abort": 1}) + return HttpResponse(final_json) + + elif status.find("[5009]") > -1: + ## removing status file, so that backup can re-run + try: + command = 'sudo rm -f ' + status + ProcessUtilities.executioner(command, 'cyberpanel') + + except: + pass + + final_json = json.dumps( + {'backupStatus': 1, 'error_message': "None", "status": status, + "abort": 1}) + return HttpResponse(final_json) + else: + final_json = json.dumps( + {'backupStatus': 1, 'error_message': "None", "status": status, + "abort": 0}) + return HttpResponse(final_json) + else: + final_json = json.dumps({'backupStatus': 1, 'error_message': "None", "status": 1, "abort": 0}) + return HttpResponse(final_json) + + except BaseException, msg: + final_dic = {'backupStatus': 0, 'error_message': str(msg)} + final_json = json.dumps(final_dic) + logging.writeToFile(str(msg) + " [backupStatus]") + return HttpResponse(final_json) + +def deleteBackup(request): + try: + userID = request.session['userID'] + currentACL = ACLManager.loadedACL(userID) + + if ACLManager.currentContextPermission(currentACL, 'addDeleteDestinations') == 0: + return ACLManager.loadErrorJson('destStatus', 0) + + data = json.loads(request.body) + + id = data['backupID'] + + IncJob.objects.get(id=id).delete() + + final_dic = {'status': 1, 'error_message': 'None'} + final_json = json.dumps(final_dic) + return HttpResponse(final_json) + + except BaseException, msg: + final_dic = {'destStatus': 0, 'error_message': str(msg)} + final_json = json.dumps(final_dic) + return HttpResponse(final_json) + +def fetchRestorePoints(request): + try: + userID = request.session['userID'] + currentACL = ACLManager.loadedACL(userID) + admin = Administrator.objects.get(pk=userID) + + data = json.loads(request.body) + id = data['id'] + + incJob = IncJob.objects.get(id=id) + + backups = incJob.jobsnapshots_set.all() + + json_data = "[" + checker = 0 + + for items in backups: + + dic = {'id': items.id, + 'snapshotid': items.snapshotid, + 'type': items.type, + 'destination': items.destination, + } + + if checker == 0: + json_data = json_data + json.dumps(dic) + checker = 1 + else: + json_data = json_data + ',' + json.dumps(dic) + + json_data = json_data + ']' + final_json = json.dumps({'status': 1, 'error_message': "None", "data": json_data}) + return HttpResponse(final_json) + except BaseException, msg: + final_dic = {'status': 0, 'error_message': str(msg)} + final_json = json.dumps(final_dic) return HttpResponse(final_json) \ No newline at end of file diff --git a/managePHP/ubuntuphp70.xml b/managePHP/ubuntuphp70.xml index eff67d913..4e56290b2 100755 --- a/managePHP/ubuntuphp70.xml +++ b/managePHP/ubuntuphp70.xml @@ -117,7 +117,7 @@ - lsphp70-pecl-imagick + lsphp70-imagick Extension to create and modify images using ImageMagick 0 diff --git a/managePHP/ubuntuphp71.xml b/managePHP/ubuntuphp71.xml index f994a8562..a56a980d0 100755 --- a/managePHP/ubuntuphp71.xml +++ b/managePHP/ubuntuphp71.xml @@ -117,7 +117,7 @@ - lsphp71-pecl-imagick + lsphp71-imagick Extension to create and modify images using ImageMagick 0 diff --git a/managePHP/ubuntuphp72.xml b/managePHP/ubuntuphp72.xml index d0e01cd10..9914be67a 100755 --- a/managePHP/ubuntuphp72.xml +++ b/managePHP/ubuntuphp72.xml @@ -117,7 +117,7 @@ - lsphp72-pecl-imagick + lsphp72-imagick Extension to create and modify images using ImageMagick 0 diff --git a/managePHP/ubuntuphp73.xml b/managePHP/ubuntuphp73.xml index 895006c82..175b09399 100755 --- a/managePHP/ubuntuphp73.xml +++ b/managePHP/ubuntuphp73.xml @@ -117,7 +117,7 @@ - lsphp73-pecl-imagick + lsphp73-imagick Extension to create and modify images using ImageMagick 0 diff --git a/plogical/applicationInstaller.py b/plogical/applicationInstaller.py index dbfb16109..a016aeb74 100755 --- a/plogical/applicationInstaller.py +++ b/plogical/applicationInstaller.py @@ -7,7 +7,6 @@ django.setup() import threading as multi from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging import subprocess -import shlex from vhost import vhost from websiteFunctions.models import ChildDomains, Websites import randomPassword diff --git a/plogical/processUtilities.py b/plogical/processUtilities.py index 91adf24fa..1236ac477 100755 --- a/plogical/processUtilities.py +++ b/plogical/processUtilities.py @@ -189,11 +189,13 @@ class ProcessUtilities(multi.Thread): # for items in CommandArgs: # finalCommand = '%s %s' % (finalCommand, items) - #logging.writeToFile(command) + if user == None: + logging.writeToFile(ProcessUtilities.token + command) sock.sendall(ProcessUtilities.token + command) else: command = '%s-u %s %s' % (ProcessUtilities.token, user, command) + logging.writeToFile(command) command = command.replace('sudo', '') sock.sendall(command)