diff --git a/IncBackups/__init__.py b/IncBackups/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/IncBackups/admin.py b/IncBackups/admin.py new file mode 100644 index 000000000..13be29d96 --- /dev/null +++ b/IncBackups/admin.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.contrib import admin + +# Register your models here. diff --git a/IncBackups/apps.py b/IncBackups/apps.py new file mode 100644 index 000000000..5511373f4 --- /dev/null +++ b/IncBackups/apps.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class IncbackupsConfig(AppConfig): + name = 'IncBackups' diff --git a/IncBackups/migrations/__init__.py b/IncBackups/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/IncBackups/models.py b/IncBackups/models.py new file mode 100644 index 000000000..1dfab7604 --- /dev/null +++ b/IncBackups/models.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models + +# Create your models here. diff --git a/IncBackups/static/IncBackups/IncBackups.js b/IncBackups/static/IncBackups/IncBackups.js new file mode 100644 index 000000000..a144ea0dd --- /dev/null +++ b/IncBackups/static/IncBackups/IncBackups.js @@ -0,0 +1,417 @@ +//*** Backup site ****// + +app.controller('createIncrementalBackups', function ($scope, $http, $timeout) { + + $scope.destination = true; + $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.destination = false; + $scope.runningBackup = true; + + }; + + + function getBackupStatus() { + + $scope.cyberpanelLoadingBottom = false; + + var websiteToBeBacked = $scope.websiteToBeBacked; + + url = "/backup/backupStatus"; + + var data = { + websiteToBeBacked: websiteToBeBacked, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + + if (response.data.backupStatus === 1) { + + if (response.data.abort === 1) { + $timeout.cancel(); + $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(); + return; + } else { + $scope.destination = true; + $scope.backupButton = true; + $scope.runningBackup = false; + $scope.cancelButton = false; + + $scope.fileName = response.data.fileName; + $scope.status = response.data.status; + $timeout(getBackupStatus, 2000); + + } + } else { + $timeout.cancel(); + $scope.cyberpanelLoadingBottom = true; + $scope.cyberpanelLoading = true; + $scope.cancelButton = true; + $scope.backupButton = false; + } + + } + + function cantLoadInitialDatas(response) { + } + + }; + + + $scope.destinationSelection = function () { + $scope.backupButton = false; + }; + + + function populateCurrentRecords() { + + var websiteToBeBacked = $scope.websiteToBeBacked; + + url = "/backup/getCurrentBackups"; + + var data = { + websiteToBeBacked: websiteToBeBacked, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + + if (response.data.fetchStatus == 1) { + $scope.records = JSON.parse(response.data.data); + } + + + } + + function cantLoadInitialDatas(response) { + } + + }; + + + $scope.createBackup = function () { + + var websiteToBeBacked = $scope.websiteToBeBacked; + $scope.cyberpanelLoading = false; + + + url = "/backup/submitBackupCreation"; + + var data = { + websiteToBeBacked: websiteToBeBacked, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + + if (response.data.metaStatus === 1) { + getBackupStatus(); + } + + } + + function cantLoadInitialDatas(response) { + } + + }; + + + $scope.deleteBackup = function (id) { + + + url = "/backup/deleteBackup"; + + var data = { + backupID: id, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + + + if (response.data.deleteStatus == 1) { + + populateCurrentRecords(); + + + } else { + + } + + } + + function cantLoadInitialDatas(response) { + + + } + + + }; + + +}); + +///** Backup site ends **/// + + +app.controller('incrementalDestinations', function ($scope, $http) { + $scope.cyberpanelLoading = true; + $scope.sftpHide = true; + $scope.awsHide = true; + + $scope.fetchDetails = function () { + + if ($scope.destinationType === 'SFTP') { + $scope.sftpHide = false; + $scope.populateCurrentRecords(); + } else { + $scope.sftpHide = true; + $scope.awsHide = false; + $scope.populateCurrentRecords(); + } + }; + + $scope.populateCurrentRecords = function () { + + $scope.cyberpanelLoading = false; + + + url = "/IncrementalBackups/populateCurrentRecords"; + + var type = 'SFTP'; + if ($scope.destinationType === 'SFTP'){ + type = 'SFTP'; + }else{ + type = 'AWS'; + } + + var data = { + type: type + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + $scope.cyberpanelLoading = true; + if (response.data.status === 1) { + $scope.records = JSON.parse(response.data.data); + } else { + new PNotify({ + title: 'Operation Failed!', + text: response.data.error_message, + type: 'error' + }); + } + + } + + function cantLoadInitialDatas(response) { + $scope.cyberpanelLoading = true; + new PNotify({ + title: 'Operation Failed!', + text: 'Could not connect to server, please refresh this page', + type: 'error' + }); + } + + }; + + $scope.addDestination = function (type) { + $scope.cyberpanelLoading = false; + + + url = "/IncrementalBackups/addDestination"; + + if(type === 'SFTP'){ + var data = { + type: type, + IPAddress: $scope.IPAddress, + password: $scope.password, + backupSSHPort: $scope.backupSSHPort + }; + }else { + var data = { + type: type, + AWS_ACCESS_KEY_ID: $scope.AWS_ACCESS_KEY_ID, + AWS_SECRET_ACCESS_KEY: $scope.AWS_SECRET_ACCESS_KEY, + }; + } + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + $scope.cyberpanelLoading = true; + $scope.populateCurrentRecords(); + if (response.data.status === 1) { + new PNotify({ + title: 'Success!', + text: 'Destination successfully added.', + type: 'success' + }); + } else { + new PNotify({ + title: 'Operation Failed!', + text: response.data.error_message, + type: 'error' + }); + } + + } + + function cantLoadInitialDatas(response) { + $scope.cyberpanelLoading = true; + new PNotify({ + title: 'Operation Failed!', + text: 'Could not connect to server, please refresh this page', + type: 'error' + }); + } + + }; + + $scope.removeDestination = function (type, ipAddress) { + $scope.cyberpanelLoading = false; + + + url = "/IncrementalBackups/removeDestination"; + + var data = { + type: type, + IPAddress: ipAddress, + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + + $http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas); + + + function ListInitialDatas(response) { + $scope.cyberpanelLoading = true; + $scope.populateCurrentRecords(); + if (response.data.status === 1) { + new PNotify({ + title: 'Success!', + text: 'Destination successfully removed.', + type: 'success' + }); + } else { + new PNotify({ + title: 'Operation Failed!', + text: response.data.error_message, + type: 'error' + }); + } + + } + + function cantLoadInitialDatas(response) { + $scope.cyberpanelLoading = true; + new PNotify({ + title: 'Operation Failed!', + text: 'Could not connect to server, please refresh this page', + type: 'error' + }); + } + + }; + + +}); \ No newline at end of file diff --git a/IncBackups/templates/IncBackups/createBackup.html b/IncBackups/templates/IncBackups/createBackup.html new file mode 100755 index 000000000..23a65a281 --- /dev/null +++ b/IncBackups/templates/IncBackups/createBackup.html @@ -0,0 +1,186 @@ + +{% extends "baseTemplate/index.html" %} +{% load i18n %} +{% block title %}{% trans "Create Incremental Backup" %}{% endblock %} +{% block content %} + +{% load static %} + +{% 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 "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" %}

+
+
+ + + +
+ + +
+ + + +
+
+
+ + +
+ + +{% endblock %} \ No newline at end of file diff --git a/IncBackups/templates/IncBackups/incrementalDestinations.html b/IncBackups/templates/IncBackups/incrementalDestinations.html new file mode 100755 index 000000000..602cad196 --- /dev/null +++ b/IncBackups/templates/IncBackups/incrementalDestinations.html @@ -0,0 +1,186 @@ +{% extends "baseTemplate/index.html" %} +{% load i18n %} +{% block title %}{% trans "Set up Back up Destinations" %}{% endblock %} +{% block content %} + + {% load static %} + + + {% get_current_language as LANGUAGE_CODE %} + + +
+
+

{% trans "Set up Incremental Back up Destinations" %} - {% trans "Remote Backups" %} +

+

{% trans "On this page you can set up your Back up destinations. (SFTP and AWS)" %}

+
+ +
+
+

+ {% trans "Set up Back up Destinations." %} +

+
+ + +
+ +
+ +
+ +
+
+ + + +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ + +
+
+ + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + +
{% trans "IP" %}{% trans "Port" %}{% trans "Delete" %}
+
+
+
+ + + + + + + + +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ + +
+
+ + + + + + + + +
+ +
+ + + + + + + + + + + + + + + +
{% trans "AWS_ACCESS_KEY_ID" %}{% trans "Delete" %}
+
+
+
+ + + + + + + +
+ + +
+
+
+ + +
+ + +{% endblock %} \ No newline at end of file diff --git a/IncBackups/tests.py b/IncBackups/tests.py new file mode 100644 index 000000000..5982e6bcd --- /dev/null +++ b/IncBackups/tests.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.test import TestCase + +# Create your tests here. diff --git a/IncBackups/urls.py b/IncBackups/urls.py new file mode 100644 index 000000000..e1fab2ab1 --- /dev/null +++ b/IncBackups/urls.py @@ -0,0 +1,11 @@ +from django.conf.urls import url +import views + +urlpatterns = [ + url(r'^createBackup$', views.createBackup, name='createBackupInc'), + url(r'^backupDestinations$', views.backupDestinations, name='backupDestinationsInc'), + url(r'^addDestination$', views.addDestination, name='addDestinationInc'), + url(r'^populateCurrentRecords$', views.populateCurrentRecords, name='populateCurrentRecordsInc'), + url(r'^removeDestination$', views.removeDestination, name='removeDestinationInc'), + +] \ No newline at end of file diff --git a/IncBackups/views.py b/IncBackups/views.py new file mode 100644 index 000000000..37a429bc4 --- /dev/null +++ b/IncBackups/views.py @@ -0,0 +1,245 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.shortcuts import render +from plogical.acl import ACLManager +from django.shortcuts import HttpResponse +from plogical.processUtilities import ProcessUtilities +from plogical.virtualHostUtilities import virtualHostUtilities +import json +import os +# Create your views here. + + +def defRenderer(request, templateName, args): + return render(request, templateName, args) + +def createBackup(request): + try: + userID = request.session['userID'] + currentACL = ACLManager.loadedACL(userID) + + if ACLManager.currentContextPermission(currentACL, 'createBackup') == 0: + return ACLManager.loadError() + + websitesName = ACLManager.findAllSites(currentACL, userID) + return defRenderer(request, 'IncBackups/createBackup.html', {'websiteList': websitesName}) + except BaseException, msg: + return HttpResponse(str(msg)) + +def backupDestinations(request): + try: + userID = request.session['userID'] + currentACL = ACLManager.loadedACL(userID) + + if ACLManager.currentContextPermission(currentACL, 'addDeleteDestinations') == 0: + return ACLManager.loadError() + + return defRenderer(request, 'IncBackups/incrementalDestinations.html', {}) + except BaseException, msg: + return HttpResponse(str(msg)) + +def addDestination(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) + + + + if data['type'] == 'SFTP': + + ipAddress = data['IPAddress'] + password = data['password'] + + ipFile = '/home/cyberpanel/sftp/%s' % (ipAddress) + + try: + port = data['backupSSHPort'] + except: + port = "22" + + if os.path.exists(ipFile): + final_dic = {'status': 0, 'error_message': 'This destination already exists.'} + final_json = json.dumps(final_dic) + return HttpResponse(final_json) + + + try: + os.mkdir('/home/cyberpanel/sftp') + except: + pass + + + execPath = "/usr/local/CyberCP/bin/python2 " + virtualHostUtilities.cyberPanel + "/plogical/backupUtilities.py" + execPath = execPath + " submitDestinationCreation --ipAddress " + ipAddress + " --password " \ + + password + " --port " + port + + output = ProcessUtilities.outputExecutioner(execPath) + + if output.find('1,') > -1: + + content = '%s\n%s' % (ipAddress, port) + writeToFile = open(ipFile, 'w') + writeToFile.write(content) + writeToFile.close() + + command = 'cat /root/.ssh/config' + currentConfig = ProcessUtilities.outputExecutioner(command) + + tmpFile = '/home/cyberpanel/sshconfig' + + writeToFile = open(tmpFile, 'w') + writeToFile.write(currentConfig) + + content = """Host %s + IdentityFile ~/.ssh/cyberpanel + Port %s + """ % (ipAddress, port) + writeToFile.write(content) + writeToFile.close() + + + command = 'mv %s /root/.ssh/config' % (tmpFile) + ProcessUtilities.executioner(command) + + command = 'chown root:root /root/.ssh/config' + ProcessUtilities.executioner(command) + + final_dic = {'status': 1, 'error_message': 'None'} + final_json = json.dumps(final_dic) + return HttpResponse(final_json) + + + else: + final_dic = {'status': 0, 'error_message': output} + final_json = json.dumps(final_dic) + return HttpResponse(final_json) + else: + aws = '/home/cyberpanel/aws' + + try: + os.mkdir(aws) + except: + pass + + AWS_ACCESS_KEY_ID = data['AWS_ACCESS_KEY_ID'] + AWS_SECRET_ACCESS_KEY = data['AWS_SECRET_ACCESS_KEY'] + + awsFile = '/home/cyberpanel/aws/%s' % (AWS_ACCESS_KEY_ID) + + writeToFile = open(awsFile, 'w') + writeToFile.write(AWS_SECRET_ACCESS_KEY) + writeToFile.close() + + final_dic = {'status': 1} + final_json = json.dumps(final_dic) + 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 populateCurrentRecords(request): + try: + userID = request.session['userID'] + currentACL = ACLManager.loadedACL(userID) + + if ACLManager.currentContextPermission(currentACL, 'addDeleteDestinations') == 0: + return ACLManager.loadErrorJson('fetchStatus', 0) + + data = json.loads(request.body) + + if data['type'] == 'SFTP': + + path = '/home/cyberpanel/sftp' + + if os.path.exists(path): + + json_data = "[" + checker = 0 + + for items in os.listdir(path): + fullPath = '/home/cyberpanel/sftp/%s' % (items) + + data = open(fullPath, 'r').readlines() + dic = { + 'ip': data[0].strip('\n'), + 'port': data[1], + } + + if checker == 0: + json_data = json_data + json.dumps(dic) + checker = 1 + else: + json_data = json_data + ',' + json.dumps(dic) + else: + final_json = json.dumps({'status': 1, 'error_message': "None", "data": ''}) + return HttpResponse(final_json) + else: + path = '/home/cyberpanel/aws' + + if os.path.exists(path): + + json_data = "[" + checker = 0 + + for items in os.listdir(path): + dic = { + 'AWS_ACCESS_KEY_ID': items + } + + if checker == 0: + json_data = json_data + json.dumps(dic) + checker = 1 + else: + json_data = json_data + ',' + json.dumps(dic) + else: + final_json = json.dumps({'status': 1, 'error_message': "None", "data": ''}) + return HttpResponse(final_json) + + 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 removeDestination(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) + + ipAddress = data['IPAddress'] + + if data['type'] == 'SFTP': + ipFile = '/home/cyberpanel/sftp/%s' % (ipAddress) + else: + ipFile = '/home/cyberpanel/aws/%s' % (ipAddress) + + + os.remove(ipFile) + + 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) \ No newline at end of file diff --git a/plogical/backupUtilities.py b/plogical/backupUtilities.py index 1c0a170c5..1ac44073e 100755 --- a/plogical/backupUtilities.py +++ b/plogical/backupUtilities.py @@ -752,6 +752,7 @@ class backupUtilities: expectation.append("password:") expectation.append("Password:") expectation.append("Permission denied") + expectation.append("100%") command = "scp -o StrictHostKeyChecking=no -P "+ port +" /root/.ssh/cyberpanel.pub root@" + IPAddress + ":/root/.ssh/authorized_keys" setupKeys = pexpect.spawn(command, timeout=3) @@ -770,6 +771,8 @@ class backupUtilities: setupKeys.wait() elif index == 2: return [0, 'Please enable password authentication on your remote server.'] + elif index == 3: + pass else: raise BaseException @@ -802,6 +805,7 @@ class backupUtilities: expectation.append("password:") expectation.append("Password:") expectation.append("Permission denied") + expectation.append("File exists") command = "ssh -o StrictHostKeyChecking=no -p "+ port +" root@"+IPAddress+' "mkdir /root/.ssh || rm -f /root/.ssh/temp && rm -f /root/.ssh/authorized_temp && cp /root/.ssh/authorized_keys /root/.ssh/temp"' setupKeys = pexpect.spawn(command, timeout=3) @@ -816,6 +820,8 @@ class backupUtilities: setupKeys.sendline(password) elif index == 2: return [0, 'Please enable password authentication on your remote server.'] + elif index == 3: + pass else: raise BaseException