Files
CyberPanel/filemanager/filemanager.py
master3395 b6b0c1bf39 Fix File Manager: file deletion, special chars, upload auth (Root FM)
- Fix delete for domain and Root File Manager: use sudo helper when
  lscpd/executioner fails (TOKEN/sendCommand issues)
- Add safe-delete-path and safe-move-path helpers for base64 path handling
- Add ACLManager.isPathInsideHome and isFilePathSafeForShell for path validation
- Fix upload authorization for Root File Manager (domainName empty)
- Harden outputExecutioner result checks to prevent 500 on None
- Update Bootstrap CDN for CSP compatibility
- Improve error display and a11y focus management in modals
- Resolves #1670: files with special characters can be uploaded/deleted
2026-02-04 00:55:58 +01:00

1342 lines
66 KiB
Python

import os
import base64
from django.shortcuts import HttpResponse
import json
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
from plogical.processUtilities import ProcessUtilities
from websiteFunctions.models import Websites
from random import randint
from django.core.files.storage import FileSystemStorage
from plogical.acl import ACLManager
from filemanager.models import Trash
class FileManager:
modes = {'php': 'application/x-httpd-php', 'javascript': 'javascript', 'python': 'text/x-python',
'html': 'text/html', 'go': 'text/x-go', 'css': 'text/css', 'java': 'text/x-java', 'perl': 'text/x-perl',
'scss': 'text/x-sass'}
def __init__(self, request, data):
self.request = request
self.data = data
@staticmethod
def findMode(fileName):
if fileName.endswith('.php'):
return FileManager.modes['php']
elif fileName.endswith('.js'):
return FileManager.modes['javascript']
elif fileName.endswith('.py'):
return FileManager.modes['python']
elif fileName.endswith('.html'):
return FileManager.modes['html']
elif fileName.endswith('.go'):
return FileManager.modes['go']
elif fileName.endswith('.css'):
return FileManager.modes['css']
elif fileName.endswith('.pl') or fileName.endswith('.PL'):
return FileManager.modes['perl']
elif fileName.endswith('.java'):
return FileManager.modes['java']
elif fileName.endswith('.scss'):
return FileManager.modes['scss']
else:
return ""
@staticmethod
def findModeFiles(mode):
if mode == FileManager.modes['php']:
return """
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/javascript/javascript.min.js"
integrity="sha512-e3U/84Fo+2ZAnRhLkjStm2hYnkmZ/NRmeesZ/GHjDhcLh35eYTQxsfSeDppx6Se5aX0N6mrygH7tr4wugWsPeQ=="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/javascript-hint.min.js"
integrity="sha512-PPI9W6pViVZfJ5uvmYZsHbPwf7T+voS0OpohIrN8Q4CRCCa6JK39JJ0R16HHmyV7EQR8MTa+O56CpWjfKOxl0A=="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/css/css.min.js"
integrity="sha512-DG+5u//fVN9kpDgTGe78IJhJW8e5+tlrPaMgNqcrzyPXsn+GPaF2T62+X3ds7SuhFR9Qeb7XZ6kMD8X09FeJhA=="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/xml/xml.min.js"
integrity="sha512-k1HnoY9EXahEfPz7kq/lD9DltloKH9OrB9XNKYoUQrNz9epe5F4mQP5PfuIfeRfoXHkNrE0gF3Mx4LhC5BVl9Q=="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/htmlmixed/htmlmixed.min.js"
integrity="sha512-p15qsXPrhaUkH+/RPE6QzCmxUAPkCRw89ityx+tWC1lAYI6Et2L0UpN+iqifxUdt+ss1FQ+9CuzxpBeT9mR3/w=="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/clike/clike.min.js" integrity="sha512-HT3t3u7HfQ7USbSZa0Tk5caEnUfO8s58OWqMBwm96xaZAbA17rpnXXHDefR8ixVmSSVssbOv3W3OMh6mNX/XuQ==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/anyword-hint.min.js" integrity="sha512-wdYOcbX/zcS4tP3HEDTkdOI5UybyuRxJMQzDQIRcafRLY/oTDWyXO+P8SzuajQipcJXkb2vHcd1QetccSFAaVw==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/css-hint.min.js" integrity="sha512-iXuwWkAmdAUNuO5rUtzmJZ/LoeJoSG8ZeQVdcUBCkV0dxfe7bxfzQMKCwQ6uNNs0FZ9jmSrN/jzJX7G1bOs4Nw==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/html-hint.min.js" integrity="sha512-aGi2Yn9VkLP9HiwiMXfkY7KQoGfwDW6JiGUtPhiPJAL9J7+rwwPVWUtUYvHW+xp3yJ7F0UhTPoPumUZv3+E/Rg==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/sql-hint.min.js" integrity="sha512-zVNOyYBOmDcGRo9/Tz+rYW8vjhAO4D/jqbj9+IIb1xWMU1ROyNWPCeWcOoBTquOBBmdiue78xJg5kkdWzsZJog==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/xml-hint.min.js" integrity="sha512-XtLGFClKrm3hNY3bS01LPiIkF64i9CnlxCqj5O+TSQq7UW8kFhFIc3kOR3bJ98h4ThxFaKdJA9PpQC76LvD/oQ==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/php/php.min.js"
integrity="sha512-m8sosGXUwyH6Ppzoy+CoQ/r5zAwZRGdNFUgGH81E3RDQkFnAsE4cP1I3tokvZwgMsDZB5mHxs+7egAgvhaCcMw=="
crossorigin="anonymous"></script>
"""
elif mode == FileManager.modes['javascript']:
return """
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/show-hint.min.js"
integrity="sha512-ge9uKCpgPmuJY2e2zPXhpYCZfyb1/R7KOOfMZ3SzSX3ZayWpINs3sHnI8LGEHUf6UOFX/D03FVHgR36uRL8/Vw=="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/javascript/javascript.min.js"
integrity="sha512-e3U/84Fo+2ZAnRhLkjStm2hYnkmZ/NRmeesZ/GHjDhcLh35eYTQxsfSeDppx6Se5aX0N6mrygH7tr4wugWsPeQ=="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/javascript-hint.min.js"
integrity="sha512-PPI9W6pViVZfJ5uvmYZsHbPwf7T+voS0OpohIrN8Q4CRCCa6JK39JJ0R16HHmyV7EQR8MTa+O56CpWjfKOxl0A=="
crossorigin="anonymous"></script>
"""
elif mode == FileManager.modes['python']:
return """
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/python/python.min.js" integrity="sha512-DS+asaww1mE0V/N6YGVgoNIRj+yXB9hAV68vM6rVeWs0G+OyMd24LKrnS4Z+g26rgghU7qvGeEnRVUArV7nVog==" crossorigin="anonymous"></script>
"""
elif mode == FileManager.modes['html']:
return """
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/javascript/javascript.min.js"
integrity="sha512-e3U/84Fo+2ZAnRhLkjStm2hYnkmZ/NRmeesZ/GHjDhcLh35eYTQxsfSeDppx6Se5aX0N6mrygH7tr4wugWsPeQ=="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/javascript-hint.min.js"
integrity="sha512-PPI9W6pViVZfJ5uvmYZsHbPwf7T+voS0OpohIrN8Q4CRCCa6JK39JJ0R16HHmyV7EQR8MTa+O56CpWjfKOxl0A=="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/css/css.min.js"
integrity="sha512-DG+5u//fVN9kpDgTGe78IJhJW8e5+tlrPaMgNqcrzyPXsn+GPaF2T62+X3ds7SuhFR9Qeb7XZ6kMD8X09FeJhA=="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/xml/xml.min.js"
integrity="sha512-k1HnoY9EXahEfPz7kq/lD9DltloKH9OrB9XNKYoUQrNz9epe5F4mQP5PfuIfeRfoXHkNrE0gF3Mx4LhC5BVl9Q=="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/htmlmixed/htmlmixed.min.js"
integrity="sha512-p15qsXPrhaUkH+/RPE6QzCmxUAPkCRw89ityx+tWC1lAYI6Et2L0UpN+iqifxUdt+ss1FQ+9CuzxpBeT9mR3/w=="
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/anyword-hint.min.js" integrity="sha512-wdYOcbX/zcS4tP3HEDTkdOI5UybyuRxJMQzDQIRcafRLY/oTDWyXO+P8SzuajQipcJXkb2vHcd1QetccSFAaVw==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/css-hint.min.js" integrity="sha512-iXuwWkAmdAUNuO5rUtzmJZ/LoeJoSG8ZeQVdcUBCkV0dxfe7bxfzQMKCwQ6uNNs0FZ9jmSrN/jzJX7G1bOs4Nw==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/html-hint.min.js" integrity="sha512-aGi2Yn9VkLP9HiwiMXfkY7KQoGfwDW6JiGUtPhiPJAL9J7+rwwPVWUtUYvHW+xp3yJ7F0UhTPoPumUZv3+E/Rg==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/sql-hint.min.js" integrity="sha512-zVNOyYBOmDcGRo9/Tz+rYW8vjhAO4D/jqbj9+IIb1xWMU1ROyNWPCeWcOoBTquOBBmdiue78xJg5kkdWzsZJog==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/addon/hint/xml-hint.min.js" integrity="sha512-XtLGFClKrm3hNY3bS01LPiIkF64i9CnlxCqj5O+TSQq7UW8kFhFIc3kOR3bJ98h4ThxFaKdJA9PpQC76LvD/oQ==" crossorigin="anonymous"></script>
"""
elif mode == FileManager.modes['go']:
return """
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/go/go.min.js" integrity="sha512-DxeIplahS44UYHUdqtsLJ21g5xHilhuP7Y4i+NSsD7J4ow+LXIXLHsjvEpMqcTSg15rkaqBRIXEETAjq3yb5Cw==" crossorigin="anonymous"></script>
"""
elif mode == FileManager.modes['css']:
return """
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/css/css.min.js" integrity="sha512-DG+5u//fVN9kpDgTGe78IJhJW8e5+tlrPaMgNqcrzyPXsn+GPaF2T62+X3ds7SuhFR9Qeb7XZ6kMD8X09FeJhA==" crossorigin="anonymous"></script>
"""
elif mode == FileManager.modes['java']:
return """
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/clike/clike.min.js" integrity="sha512-HT3t3u7HfQ7USbSZa0Tk5caEnUfO8s58OWqMBwm96xaZAbA17rpnXXHDefR8ixVmSSVssbOv3W3OMh6mNX/XuQ==" crossorigin="anonymous"></script>
"""
elif mode == FileManager.modes['perl']:
return """
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/perl/perl.min.js" integrity="sha512-6rKFA1mIjmFqxMM/b0dtjQOWFRAoqKCmhb7/6u2KohJcP4poKbrUI08Yf5GXsK+rkCr2dQnppV7gMe2a0HGQBQ==" crossorigin="anonymous"></script>
"""
elif mode == FileManager.modes['scss']:
return """
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/mode/sass/sass.min.js" integrity="sha512-lFZETu8ovGFrFbFWAJnwgJrRcQ06C0BhjySIpBFPUatL/vqFz/mZIvXhlLtbOwbvRCp+XcLCmTEigKOJPN+YhA==" crossorigin="anonymous"></script>
"""
else:
return ''
@staticmethod
def findThemeFile(theme):
return '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.58.1/theme/%s.min.css" />' % (theme)
@staticmethod
def findAdditionalOptions(mode):
if mode == 'text/x-python':
return """<select ng-model="optionValue" ng-change="additionalOptions()">
<option>Python 2</option>
<option>Python 3</option>
</select>
"""
else:
return ""
def ajaxPre(self, status, errorMessage):
final_dic = {'status': status, 'error_message': errorMessage, 'uploadStatus': status}
final_json = json.dumps(final_dic)
return HttpResponse(final_json)
def returnPathEnclosed(self, path):
return "'" + path + "'"
def _moveViaPythonBase64(self, src_path, dest_path, user):
"""Fallback: use helper script or Python to move when mv fails (handles special chars)."""
try:
import subprocess
s_b64 = base64.b64encode(src_path.encode('utf-8')).decode('ascii')
d_b64 = base64.b64encode(dest_path.encode('utf-8')).decode('ascii')
helper = '/usr/local/CyberCP/bin/safe-move-path'
if os.path.isfile(helper) and os.access(helper, os.X_OK):
cmd = [helper, s_b64, d_b64]
if os.getuid() != 0:
cmd = ['sudo', '-n'] + cmd
try:
res = subprocess.run(cmd, capture_output=True, timeout=30)
if res.returncode == 0:
return True
except Exception as e:
logging.writeToFile(f"_moveViaPythonBase64 sudo helper failed: {str(e)}")
command = '%s %s %s' % (helper, s_b64, d_b64)
else:
code = "import shutil,base64,sys; s=base64.b64decode(sys.argv[1]).decode(); d=base64.b64decode(sys.argv[2]).decode(); shutil.move(s,d)"
command = "/usr/bin/python3 -c '%s' %s %s" % (code, s_b64, d_b64)
result = ProcessUtilities.executioner(command, user)
return result == 1
except Exception as e:
logging.writeToFile(f"_moveViaPythonBase64 failed: {str(e)}")
return False
def _deleteViaPythonBase64(self, path, user):
"""Fallback: use helper script or Python to delete when rm fails (handles special chars)."""
try:
import subprocess
p_b64 = base64.b64encode(path.encode('utf-8')).decode('ascii')
helper = '/usr/local/CyberCP/bin/safe-delete-path'
if os.path.isfile(helper) and os.access(helper, os.X_OK):
cmd = [helper, p_b64]
if os.getuid() != 0:
cmd = ['sudo', '-n'] + cmd
try:
res = subprocess.run(cmd, capture_output=True, timeout=30)
if res.returncode == 0:
return True
except Exception as e:
logging.writeToFile(f"_deleteViaPythonBase64 sudo helper failed: {str(e)}")
if os.path.isfile(helper) and os.access(helper, os.X_OK):
command = '%s %s' % (helper, p_b64)
else:
code = "import os,base64,sys,shutil; p=base64.b64decode(sys.argv[1]).decode(); (os.path.isfile(p) and os.remove(p)) or (os.path.isdir(p) and shutil.rmtree(p))"
command = "/usr/bin/python3 -c '%s' %s" % (code, p_b64)
result = ProcessUtilities.executioner(command, user)
return result == 1
except Exception as e:
logging.writeToFile(f"_deleteViaPythonBase64 failed: {str(e)}")
return False
def changeOwner(self, path):
try:
domainName = self.data['domainName']
website = Websites.objects.get(domain=domainName)
homePath = '/home/%s' % (domainName)
if not ACLManager.isPathInsideHome(path, homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = "chown -R " + website.externalApp + ':' + website.externalApp + ' ' + self.returnPathEnclosed(path)
ProcessUtilities.executioner(command, website.externalApp)
except:
print("Permisson not changed")
def listForTable(self):
try:
finalData = {}
finalData['status'] = 1
try:
domainName = self.data['domainName']
website = Websites.objects.get(domain=domainName)
pathCheck = '/home/%s' % (domainName)
if not ACLManager.isPathInsideHome(self.data['completeStartingPath'], pathCheck):
return self.ajaxPre(0, 'Not allowed to browse this path, going back home!')
command = "ls -la --group-directories-first " + self.returnPathEnclosed(
self.data['completeStartingPath'])
output = ProcessUtilities.outputExecutioner(command, website.externalApp).splitlines()
except:
pathCheck = '/'
if not ACLManager.isPathInsideHome(self.data['completeStartingPath'], pathCheck):
return self.ajaxPre(0, 'Not allowed to browse this path, going back home!')
command = "ls -la --group-directories-first " + self.returnPathEnclosed(
self.data['completeStartingPath'])
output = ProcessUtilities.outputExecutioner(command).splitlines()
counter = 0
for items in output:
try:
currentFile = items.split(' ')
currentFile = [a for a in currentFile if a != '']
if currentFile[-1] == '.' or currentFile[-1] == '..' or currentFile[0] == 'total':
continue
if len(currentFile) > 9:
fileName = currentFile[8:]
currentFile[-1] = " ".join(fileName)
dirCheck = 0
if currentFile[0][0] == 'd':
dirCheck = 1
size = str(int(int(currentFile[4]) / float(1024)))
lastModified = currentFile[5] + ' ' + currentFile[6] + ' ' + currentFile[7]
finalData[str(counter)] = [currentFile[-1], currentFile[-1], lastModified, size, currentFile[0],
dirCheck]
counter = counter + 1
except BaseException as msg:
logging.writeToFile(str(msg))
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def list(self):
try:
finalData = {}
finalData['status'] = 1
try:
domainName = self.data['domainName']
website = Websites.objects.get(domain=domainName)
command = "ls -la --group-directories-first " + self.returnPathEnclosed(
self.data['completeStartingPath'])
output = ProcessUtilities.outputExecutioner(command, website.externalApp).splitlines()
counter = 0
for items in output:
try:
currentFile = items.split(' ')
currentFile = [a for a in currentFile if a != '']
if currentFile[-1] == '.' or currentFile[-1] == '..' or currentFile[0] == 'total':
continue
if len(currentFile) > 9:
fileName = currentFile[8:]
currentFile[-1] = " ".join(fileName)
dirCheck = False
if currentFile[0][0] == 'd':
dirCheck = True
finalData[str(counter)] = [currentFile[-1],
self.data['completeStartingPath'] + '/' + currentFile[-1], dirCheck]
counter = counter + 1
except:
continue
except:
command = "ls -la --group-directories-first " + self.returnPathEnclosed(
self.data['completeStartingPath'])
output = ProcessUtilities.outputExecutioner(command).splitlines()
counter = 0
for items in output:
try:
currentFile = items.split(' ')
currentFile = [a for a in currentFile if a != '']
if currentFile[-1] == '.' or currentFile[-1] == '..' or currentFile[0] == 'total':
continue
if len(currentFile) > 9:
fileName = currentFile[8:]
currentFile[-1] = " ".join(fileName)
dirCheck = False
if currentFile[0][0] == 'd':
dirCheck = True
finalData[str(counter)] = [currentFile[-1],
self.data['completeStartingPath'] + '/' + currentFile[-1], dirCheck]
counter = counter + 1
except:
continue
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def createNewFile(self):
try:
finalData = {}
finalData['status'] = 1
try:
domainName = self.data['domainName']
website = Websites.objects.get(domain=domainName)
homePath = '/home/%s' % (domainName)
if not ACLManager.isPathInsideHome(self.data['fileName'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = "touch " + self.returnPathEnclosed(self.data['fileName'])
ProcessUtilities.executioner(command, website.externalApp)
self.changeOwner(self.returnPathEnclosed(self.data['fileName']))
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
except:
homePath = '/'
if not ACLManager.isPathInsideHome(self.data['fileName'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = "touch " + self.returnPathEnclosed(self.data['fileName'])
ProcessUtilities.executioner(command)
self.changeOwner(self.returnPathEnclosed(self.data['fileName']))
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def createNewFolder(self):
try:
finalData = {}
finalData['status'] = 1
try:
domainName = self.data['domainName']
website = Websites.objects.get(domain=domainName)
homePath = '/home/%s' % (domainName)
if not ACLManager.isPathInsideHome(self.data['folderName'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = "mkdir " + self.returnPathEnclosed(self.data['folderName'])
ProcessUtilities.executioner(command, website.externalApp)
self.changeOwner(self.returnPathEnclosed(self.data['folderName']))
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
except:
homePath = '/'
if not ACLManager.isPathInsideHome(self.data['folderName'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = "mkdir " + self.returnPathEnclosed(self.data['folderName'])
ProcessUtilities.executioner(command)
self.changeOwner(self.returnPathEnclosed(self.data['folderName']))
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def deleteFolderOrFile(self):
try:
finalData = {}
finalData['status'] = 1
domainName = self.data['domainName']
try:
try:
skipTrash = self.data['skipTrash']
except:
skipTrash = False
website = Websites.objects.get(domain=domainName)
self.homePath = '/home/%s' % (domainName)
logging.writeToFile(f"Attempting to delete files/folders for domain: {domainName}")
RemoveOK = 1
# Test if directory is writable
command = 'touch %s/public_html/hello.txt' % (self.homePath)
result = ProcessUtilities.outputExecutioner(command)
if result is None:
result = ''
if isinstance(result, (str, bytes)) and ('cannot touch' in str(result) or 'Permission denied' in str(result)):
RemoveOK = 0
logging.writeToFile(f"Directory {self.homePath} is not writable, removing chattr flags")
# Remove immutable flag from entire directory (executioner returns 1=success, 0=failure)
command = 'chattr -R -i %s' % (self.homePath)
result = ProcessUtilities.executioner(command)
if result != 1:
logging.writeToFile(f"Warning: Failed to remove chattr -i from {self.homePath}: {result}")
else:
logging.writeToFile(f"Successfully removed chattr -i from {self.homePath}")
else:
command = 'rm -f %s/public_html/hello.txt' % (self.homePath)
ProcessUtilities.executioner(command)
for item in self.data['fileAndFolders']:
itemPath = self.data['path'] + '/' + item
# Security check - prevent path traversal
if not ACLManager.isPathInsideHome(itemPath, self.homePath):
logging.writeToFile(f"Security violation: Attempted to delete outside home directory: {itemPath}")
return self.ajaxPre(0, 'Not allowed to delete files outside home directory!')
logging.writeToFile(f"Deleting: {itemPath}")
if skipTrash:
# Permanent deletion (executioner returns 1=success, 0=failure)
command = 'rm -rf ' + self.returnPathEnclosed(itemPath)
result = ProcessUtilities.executioner(command, website.externalApp)
if result != 1:
logging.writeToFile(f"Failed to delete {itemPath}: result={result}, trying Python fallback")
# Fallback: Python+base64 to handle special chars in paths
if not self._deleteViaPythonBase64(itemPath, website.externalApp):
return self.ajaxPre(0, f'Failed to delete {item}')
logging.writeToFile(f"Successfully deleted: {itemPath}")
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
else:
# Move to trash
trashPath = '%s/.trash' % (self.homePath)
# Ensure trash directory exists (executioner returns 1=success, 0=failure)
command = 'mkdir -p %s' % (trashPath)
result = ProcessUtilities.executioner(command, website.externalApp)
if result != 1:
logging.writeToFile(f"Failed to create trash directory: result={result}")
return self.ajaxPre(0, f'Failed to create trash directory')
# Save to trash database
try:
Trash(website=website, originalPath=self.returnPathEnclosed(self.data['path']),
fileName=self.returnPathEnclosed(item)).save()
except Exception as e:
logging.writeToFile(f"Failed to save trash record: {str(e)}")
# Move to trash (executioner returns 1=success, 0=failure)
command = 'mv %s %s' % (self.returnPathEnclosed(itemPath), trashPath)
result = ProcessUtilities.executioner(command, website.externalApp)
if result != 1:
logging.writeToFile(f"Failed to move to trash {itemPath}: result={result}, trying Python fallback")
# Fallback: Python+base64 to handle special chars in paths (e.g. lscpd/sendCommand)
if not self._moveViaPythonBase64(itemPath, trashPath, website.externalApp):
return self.ajaxPre(0, f'Failed to move {item} to trash')
logging.writeToFile(f"Successfully moved to trash: {itemPath}")
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
if RemoveOK == 0:
logging.writeToFile(f"Restoring chattr +i flags for {self.homePath}")
# Restore immutable flag to entire directory (executioner returns 1=success, 0=failure)
command = 'chattr -R +i %s' % (self.homePath)
result = ProcessUtilities.executioner(command)
if result != 1:
logging.writeToFile(f"Warning: Failed to restore chattr +i to {self.homePath}: result={result}")
else:
logging.writeToFile(f"Successfully restored chattr +i to {self.homePath}")
# Allow specific directories to remain mutable
mutable_dirs = ['/logs/', '/.trash/', '/backup/', '/incbackup/', '/lscache/', '/.cagefs/']
for dir_name in mutable_dirs:
dir_path = self.homePath + dir_name
command = 'chattr -R -i %s' % (dir_path)
result = ProcessUtilities.executioner(command)
if result != 1:
logging.writeToFile(f"Warning: Failed to remove chattr +i from {dir_path}: result={result}")
else:
logging.writeToFile(f"Successfully removed chattr +i from {dir_path}")
except Exception as e:
import traceback
logging.writeToFile(f"Error in deleteFolderOrFile for {domainName}: {str(e)}")
logging.writeToFile(traceback.format_exc())
try:
skipTrash = self.data['skipTrash']
except:
skipTrash = False
# Fallback to root path for system files (Root File Manager, domainName empty)
self.homePath = '/'
logging.writeToFile(f"Using fallback deletion for system files in {self.data['path']}")
RemoveOK = 1
# Test if we can write (use /tmp for root path since /public_html doesn't exist at /)
test_path = '/tmp' if self.homePath == '/' else (self.homePath + '/public_html')
command = 'touch %s/hello.txt' % (test_path)
result = ProcessUtilities.outputExecutioner(command)
if result is None:
result = ''
if isinstance(result, (str, bytes)) and ('cannot touch' in str(result) or 'Permission denied' in str(result)):
RemoveOK = 0
logging.writeToFile(f"Directory {self.homePath} is not writable, removing chattr flags")
command = 'chattr -R -i %s' % (self.homePath)
result = ProcessUtilities.executioner(command)
if result != 1:
logging.writeToFile(f"Warning: Failed to remove chattr -i from {self.homePath}: {result}")
else:
command = 'rm -f %s/hello.txt' % (test_path)
ProcessUtilities.executioner(command)
for item in self.data['fileAndFolders']:
base = self.data['path'].rstrip('/') or '/'
itemPath = base + '/' + item
# Security check for system files
if not ACLManager.isPathInsideHome(itemPath, self.homePath):
logging.writeToFile(f"Security violation: Attempted to delete outside allowed path: {itemPath}")
return self.ajaxPre(0, 'Not allowed to delete files outside allowed path!')
logging.writeToFile(f"Deleting system file: {itemPath}")
if skipTrash:
command = 'rm -rf ' + self.returnPathEnclosed(itemPath)
result = ProcessUtilities.executioner(command)
if result != 1:
logging.writeToFile(f"Failed to delete system file {itemPath}: result={result}, trying Python fallback")
if not self._deleteViaPythonBase64(itemPath, None):
return self.ajaxPre(0, f'Failed to delete {item}')
logging.writeToFile(f"Successfully deleted system file: {itemPath}")
if RemoveOK == 0:
logging.writeToFile(f"Restoring chattr +i flags for system path: {self.homePath}")
command = 'chattr -R +i %s' % (self.homePath)
result = ProcessUtilities.executioner(command)
if result != 1:
logging.writeToFile(f"Warning: Failed to restore chattr +i to system path {self.homePath}: result={result}")
else:
logging.writeToFile(f"Successfully restored chattr +i to system path {self.homePath}")
# Allow specific directories to remain mutable for system files
mutable_dirs = ['/logs/', '/.trash/', '/backup/', '/incbackup/', '/lscache/', '/.cagefs/']
for dir_name in mutable_dirs:
dir_path = self.homePath + dir_name
command = 'chattr -R -i %s' % (dir_path)
result = ProcessUtilities.executioner(command)
if result != 1:
logging.writeToFile(f"Warning: Failed to remove chattr +i from system {dir_path}: result={result}")
else:
logging.writeToFile(f"Successfully removed chattr +i from system {dir_path}")
logging.writeToFile(f"File deletion completed successfully for domain: {domainName}")
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
logging.writeToFile(f"Critical error in deleteFolderOrFile: {str(msg)}")
return self.ajaxPre(0, f"File deletion failed: {str(msg)}")
def restore(self):
try:
finalData = {}
finalData['status'] = 1
domainName = self.data['domainName']
try:
skipTrash = self.data['skipTrash']
except:
skipTrash = False
website = Websites.objects.get(domain=domainName)
self.homePath = '/home/%s' % (domainName)
for item in self.data['fileAndFolders']:
if not ACLManager.isPathInsideHome(self.data['path'] + '/' + item, self.homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
trashPath = '%s/.trash' % (self.homePath)
tItem = Trash.objects.get(website=website, fileName=self.returnPathEnclosed(item))
command = 'mv %s %s' % (self.returnPathEnclosed(trashPath + '/' + item), tItem.originalPath)
ProcessUtilities.executioner(command, website.externalApp)
tItem.delete()
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def copy(self):
try:
finalData = {}
finalData['status'] = 1
domainName = self.data['domainName']
try:
website = Websites.objects.get(domain=domainName)
homePath = '/home/%s' % (domainName)
if not ACLManager.isPathInsideHome(self.data['newPath'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
if len(self.data['fileAndFolders']) == 1:
if not ACLManager.isPathInsideHome(self.data['basePath'] + '/' + self.data['fileAndFolders'][0], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = 'yes| cp -Rf %s %s' % (
self.returnPathEnclosed(self.data['basePath'] + '/' + self.data['fileAndFolders'][0]),
self.data['newPath'])
ProcessUtilities.executioner(command, website.externalApp)
self.changeOwner(self.data['newPath'])
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
json_data = json.dumps(finalData)
return HttpResponse(json_data)
command = 'mkdir ' + self.returnPathEnclosed(self.data['newPath'])
ProcessUtilities.executioner(command, website.externalApp)
for item in self.data['fileAndFolders']:
if not ACLManager.isPathInsideHome(self.data['basePath'] + '/' + item, homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = '%scp -Rf ' % ('yes |') + self.returnPathEnclosed(
self.data['basePath'] + '/' + item) + ' ' + self.returnPathEnclosed(self.data['newPath'])
ProcessUtilities.executioner(command, website.externalApp)
self.changeOwner(self.data['newPath'])
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
except:
homePath = '/'
if not ACLManager.isPathInsideHome(self.data['newPath'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
if len(self.data['fileAndFolders']) == 1:
if not ACLManager.isPathInsideHome(self.data['basePath'] + '/' + self.data['fileAndFolders'][0], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = 'yes| cp -Rf %s %s' % (
self.returnPathEnclosed(self.data['basePath'] + '/' + self.data['fileAndFolders'][0]),
self.data['newPath'])
ProcessUtilities.executioner(command,)
self.changeOwner(self.data['newPath'])
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
json_data = json.dumps(finalData)
return HttpResponse(json_data)
command = 'mkdir ' + self.returnPathEnclosed(self.data['newPath'])
ProcessUtilities.executioner(command)
for item in self.data['fileAndFolders']:
if not ACLManager.isPathInsideHome(self.data['basePath'] + '/' + item, homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = '%scp -Rf ' % ('yes |') + self.returnPathEnclosed(
self.data['basePath'] + '/' + item) + ' ' + self.returnPathEnclosed(self.data['newPath'])
ProcessUtilities.executioner(command)
self.changeOwner(self.data['newPath'])
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def move(self):
try:
finalData = {}
finalData['status'] = 1
domainName = self.data['domainName']
try:
website = Websites.objects.get(domain=domainName)
homePath = '/home/%s' % (domainName)
command = 'mkdir ' + self.returnPathEnclosed(self.data['newPath'])
ProcessUtilities.executioner(command, website.externalApp)
for item in self.data['fileAndFolders']:
if not ACLManager.isPathInsideHome(self.data['basePath'] + '/' + item, homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
if not ACLManager.isPathInsideHome(self.data['newPath'] + '/' + item, homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = 'mv ' + self.returnPathEnclosed(
self.data['basePath'] + '/' + item) + ' ' + self.returnPathEnclosed(
self.data['newPath'] + '/' + item)
ProcessUtilities.executioner(command, website.externalApp)
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
#self.changeOwner(self.data['newPath'])
#self.fixPermissions(domainName)
except:
homePath = '/'
command = 'mkdir ' + self.returnPathEnclosed(self.data['newPath'])
ProcessUtilities.executioner(command)
for item in self.data['fileAndFolders']:
if not ACLManager.isPathInsideHome(self.data['basePath'] + '/' + item, homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
if not ACLManager.isPathInsideHome(self.data['newPath'] + '/' + item, homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = 'mv ' + self.returnPathEnclosed(
self.data['basePath'] + '/' + item) + ' ' + self.returnPathEnclosed(
self.data['newPath'] + '/' + item)
ProcessUtilities.executioner(command)
self.changeOwner(self.data['newPath'])
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def rename(self):
try:
finalData = {}
finalData['status'] = 1
domainName = self.data['domainName']
try:
website = Websites.objects.get(domain=domainName)
homePath = '/home/%s' % (domainName)
if not ACLManager.isPathInsideHome(self.data['basePath'] + '/' + self.data['existingName'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
if not ACLManager.isPathInsideHome(self.data['basePath'] + '/' + self.data['newFileName'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = 'mv ' + self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['existingName']) + ' ' + self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['newFileName'])
ProcessUtilities.executioner(command, website.externalApp)
self.changeOwner(self.data['basePath'] + '/' + self.data['newFileName'])
except:
homePath = '/'
if not ACLManager.isPathInsideHome(self.data['basePath'] + '/' + self.data['existingName'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
if not ACLManager.isPathInsideHome(self.data['basePath'] + '/' + self.data['newFileName'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = 'mv ' + self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['existingName']) + ' ' + self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['newFileName'])
ProcessUtilities.executioner(command)
self.changeOwner(self.data['basePath'] + '/' + self.data['newFileName'])
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def readFileContents(self):
try:
finalData = {}
finalData['status'] = 1
domainName = self.data['domainName']
try:
website = Websites.objects.get(domain=domainName)
pathCheck = '/home/%s' % (domainName)
if not ACLManager.isPathInsideHome(self.data['fileName'], pathCheck):
return self.ajaxPre(0, 'Not allowed.')
# Ensure proper UTF-8 handling for file reading
# Use explicit UTF-8 locale for the cat command
command = 'LANG=C.UTF-8 LC_ALL=C.UTF-8 cat ' + self.returnPathEnclosed(self.data['fileName'])
finalData['fileContents'] = ProcessUtilities.outputExecutioner(command, website.externalApp)
except:
pathCheck = '/'
if not ACLManager.isPathInsideHome(self.data['fileName'], pathCheck):
return self.ajaxPre(0, 'Not allowed.')
# Ensure proper UTF-8 handling for file reading
# Use explicit UTF-8 locale for the cat command
command = 'LANG=C.UTF-8 LC_ALL=C.UTF-8 cat ' + self.returnPathEnclosed(self.data['fileName'])
finalData['fileContents'] = ProcessUtilities.outputExecutioner(command)
# Ensure proper UTF-8 encoding in JSON response
json_data = json.dumps(finalData, ensure_ascii=False)
return HttpResponse(json_data, content_type='application/json; charset=utf-8')
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def writeFileContents(self):
try:
finalData = {}
finalData['status'] = 1
try:
self.data['home'] = '/home/%s' % (self.data['domainName'])
ACLManager.CreateSecureDir()
tempPath = '%s/%s' % ('/usr/local/CyberCP/tmp', str(randint(1000, 9999)))
domainName = self.data['domainName']
website = Websites.objects.get(domain=domainName)
writeToFile = open(tempPath, 'wb')
writeToFile.write(self.data['fileContent'].encode('utf-8'))
writeToFile.close()
command = 'chown %s:%s %s' % (website.externalApp, website.externalApp, tempPath)
ProcessUtilities.executioner(command)
command = 'cp %s %s' % (tempPath, self.returnPathEnclosed(self.data['fileName']))
ProcessUtilities.executioner(command, website.externalApp)
os.remove(tempPath)
except:
self.data['home'] = '/'
ACLManager.CreateSecureDir()
tempPath = '%s/%s' % ('/usr/local/CyberCP/tmp', str(randint(1000, 9999)))
writeToFile = open(tempPath, 'wb')
writeToFile.write(self.data['fileContent'].encode('utf-8'))
writeToFile.close()
command = 'cp %s %s' % (tempPath, self.returnPathEnclosed(self.data['fileName']))
ProcessUtilities.executioner(command)
os.remove(tempPath)
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def upload(self):
try:
finalData = {}
finalData['uploadStatus'] = 1
finalData['answer'] = 'File transfer completed.'
ACLManager.CreateSecureDir()
UploadPath = '/usr/local/CyberCP/tmp/'
## Random file name
RanddomFileName = str(randint(1000, 9999))
myfile = self.request.FILES['file']
fs = FileSystemStorage()
try:
filename = fs.save(RanddomFileName, myfile)
finalData['fileName'] = fs.url(filename)
except BaseException as msg:
logging.writeToFile('%s. [375:upload]' % (str(msg)))
domainName = self.data['domainName']
try:
pathCheck = '/home/%s' % (self.data['domainName'])
website = Websites.objects.get(domain=domainName)
command = 'ls -la %s' % (self.data['completePath'])
result = ProcessUtilities.outputExecutioner(command, website.externalApp)
#
if result.find('->') > -1:
return self.ajaxPre(0, "Symlink attack.")
uploadPathFull = self.data['completePath'] + '/' + myfile.name
if not ACLManager.isFilePathSafeForShell(uploadPathFull):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
if not ACLManager.isPathInsideHome(uploadPathFull, pathCheck):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = 'cp ' + self.returnPathEnclosed(
UploadPath + RanddomFileName) + ' ' + self.returnPathEnclosed(
self.data['completePath'] + '/' + myfile.name)
ProcessUtilities.executioner(command, website.externalApp)
self.changeOwner(self.returnPathEnclosed(self.data['completePath'] + '/' + myfile.name))
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
try:
os.remove(UploadPath + RanddomFileName)
except:
pass
except:
pathCheck = '/'
command = 'ls -la %s' % (self.data['completePath'])
result = ProcessUtilities.outputExecutioner(command)
logging.writeToFile("upload file res %s" % result)
uploadPathFull = self.data['completePath'] + '/' + myfile.name
if not ACLManager.isFilePathSafeForShell(uploadPathFull):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
if not ACLManager.isPathInsideHome(uploadPathFull, pathCheck):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = 'cp ' + self.returnPathEnclosed(
UploadPath + RanddomFileName) + ' ' + self.returnPathEnclosed(
self.data['completePath'] + '/' + myfile.name)
ProcessUtilities.executioner(command)
self.changeOwner(self.returnPathEnclosed(self.data['completePath'] + '/' + myfile.name))
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
try:
os.remove(UploadPath + RanddomFileName)
except:
pass
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
try:
os.remove(UploadPath + RanddomFileName)
except:
pass
return self.ajaxPre(0, str(msg))
def extract(self):
try:
finalData = {}
finalData['status'] = 1
domainName = self.data['domainName']
try:
website = Websites.objects.get(domain=domainName)
homePath = '/home/%s' % (domainName)
if not ACLManager.isPathInsideHome(self.data['extractionLocation'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
if not ACLManager.isPathInsideHome(self.data['fileToExtract'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
if self.data['extractionType'] == 'zip':
command = 'unzip -o ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' -d ' + self.returnPathEnclosed(self.data['extractionLocation'])
elif self.data['extractionType'] == '7z':
command = '7z x ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' -o' + self.returnPathEnclosed(self.data['extractionLocation']) + ' -y'
elif self.data['extractionType'] == 'rar':
# Try unrar first (free), fallback to 7z if unrar not available
command = 'unrar x ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' ' + self.returnPathEnclosed(self.data['extractionLocation']) + ' -y'
else:
command = 'tar -xf ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' -C ' + self.returnPathEnclosed(self.data['extractionLocation'])
ProcessUtilities.executioner(command, website.externalApp)
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
#self.fixPermissions(domainName)
except:
homePath = '/'
if not ACLManager.isPathInsideHome(self.data['extractionLocation'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
if not ACLManager.isPathInsideHome(self.data['fileToExtract'], homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
if self.data['extractionType'] == 'zip':
command = 'unzip -o ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' -d ' + self.returnPathEnclosed(self.data['extractionLocation'])
elif self.data['extractionType'] == '7z':
command = '7z x ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' -o' + self.returnPathEnclosed(self.data['extractionLocation']) + ' -y'
elif self.data['extractionType'] == 'rar':
# Try unrar first (free), fallback to 7z if unrar not available
command = 'unrar x ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' ' + self.returnPathEnclosed(self.data['extractionLocation']) + ' -y'
else:
command = 'tar -xf ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' -C ' + self.returnPathEnclosed(self.data['extractionLocation'])
ProcessUtilities.executioner(command)
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def compress(self):
try:
finalData = {}
finalData['status'] = 1
domainName = self.data['domainName']
try:
website = Websites.objects.get(domain=domainName)
if self.data['compressionType'] == 'zip':
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.zip')
command = 'zip -r ' + compressedFileName + ' '
elif self.data['compressionType'] == '7z':
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.7z')
command = '7z a -t7z ' + compressedFileName + ' '
elif self.data['compressionType'] == 'rar':
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.rar')
# Use 7z to create RAR format (7z can create RAR archives)
command = '7z a -trar ' + compressedFileName + ' '
else:
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.tar.gz')
command = 'tar -czvf ' + compressedFileName + ' '
homePath = '/home/%s' % (domainName)
for item in self.data['listOfFiles']:
if not ACLManager.isPathInsideHome(self.data['basePath'] + item, homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = '%s%s ' % (command, self.returnPathEnclosed(item))
finalCommand = 'cd %s && %s' % (self.data['basePath'], command)
ProcessUtilities.executioner(finalCommand, website.externalApp)
self.changeOwner(self.data['compressedFileName'])
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
except:
if self.data['compressionType'] == 'zip':
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.zip')
command = 'zip -r ' + compressedFileName + ' '
elif self.data['compressionType'] == '7z':
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.7z')
command = '7z a -t7z ' + compressedFileName + ' '
elif self.data['compressionType'] == 'rar':
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.rar')
# Use 7z to create RAR format (7z can create RAR archives)
command = '7z a -trar ' + compressedFileName + ' '
else:
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.tar.gz')
command = 'tar -czvf ' + compressedFileName + ' '
homePath = '/'
for item in self.data['listOfFiles']:
if not ACLManager.isPathInsideHome(self.data['basePath'] + item, homePath):
return self.ajaxPre(0, 'Not allowed to move in this path, please choose location inside home!')
command = '%s%s ' % (command, self.returnPathEnclosed(item))
finalCommand = 'cd %s && %s' % (self.data['basePath'], command)
res = ProcessUtilities.outputExecutioner(finalCommand, "root")
logging.writeToFile("compress file res %s"%res)
self.changeOwner(self.data['compressedFileName'])
## Update disk usage in background
command = "/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py UpdateDiskUsageForceDomain --domainName %s" % (domainName)
ProcessUtilities.popenExecutioner(command)
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def changePermissions(self):
try:
finalData = {}
finalData['status'] = 1
domainName = self.data['domainName']
website = Websites.objects.get(domain=domainName)
if self.data['recursive'] == 1:
command = 'chmod -R ' + self.data['newPermissions'] + ' ' + self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['permissionsPath'])
else:
command = 'chmod ' + self.data['newPermissions'] + ' ' + self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['permissionsPath'])
ProcessUtilities.executioner(command, website.externalApp)
json_data = json.dumps(finalData)
return HttpResponse(json_data)
except BaseException as msg:
return self.ajaxPre(0, str(msg))
def fixPermissions(self, domainName):
website = Websites.objects.get(domain=domainName)
externalApp = website.externalApp
if ProcessUtilities.decideDistro() == ProcessUtilities.centos or ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
groupName = 'nobody'
else:
groupName = 'nogroup'
### symlink checks
command = 'ls -la /home/%s' % domainName
result = ProcessUtilities.outputExecutioner(command)
if result.find('->') > -1:
final_json = json.dumps(
{'status': 0, 'logstatus': 0,
'error_message': "Symlink attack."})
return HttpResponse(final_json)
command = 'chown %s:%s /home/%s' % (website.externalApp, website.externalApp, domainName)
ProcessUtilities.popenExecutioner(command)
### Sym link checks
command = 'ls -la /home/%s/public_html/' % domainName
result = ProcessUtilities.outputExecutioner(command)
if result.find('->') > -1:
final_json = json.dumps(
{'status': 0, 'logstatus': 0,
'error_message': "Symlink attack."})
return HttpResponse(final_json)
command = 'chown -R -P %s:%s /home/%s/public_html/*' % (externalApp, externalApp, domainName)
ProcessUtilities.popenExecutioner(command)
command = 'chown -R -P %s:%s /home/%s/public_html/.[^.]*' % (externalApp, externalApp, domainName)
ProcessUtilities.popenExecutioner(command)
# command = "chown root:%s /home/" % (groupName) + domainName + "/logs"
# ProcessUtilities.popenExecutioner(command)
command = "find %s -type d -exec chmod 0755 {} \;" % ("/home/" + domainName + "/public_html")
ProcessUtilities.popenExecutioner(command)
command = "find %s -type f -exec chmod 0644 {} \;" % ("/home/" + domainName + "/public_html")
ProcessUtilities.popenExecutioner(command)
command = 'chown %s:%s /home/%s/public_html' % (externalApp, groupName, domainName)
ProcessUtilities.executioner(command)
command = 'chmod 750 /home/%s/public_html' % (domainName)
ProcessUtilities.executioner(command)
for childs in website.childdomains_set.all():
command = 'ls -la %s' % childs.path
result = ProcessUtilities.outputExecutioner(command)
if result.find('->') > -1:
final_json = json.dumps(
{'status': 0, 'logstatus': 0,
'error_message': "Symlink attack."})
return HttpResponse(final_json)
command = "find %s -type d -exec chmod 0755 {} \;" % (childs.path)
ProcessUtilities.popenExecutioner(command)
command = "find %s -type f -exec chmod 0644 {} \;" % (childs.path)
ProcessUtilities.popenExecutioner(command)
command = 'chown -R -P %s:%s %s/*' % (externalApp, externalApp, childs.path)
ProcessUtilities.popenExecutioner(command)
command = 'chown -R -P %s:%s %s/.[^.]*' % (externalApp, externalApp, childs.path)
ProcessUtilities.popenExecutioner(command)
command = 'chmod 755 %s' % (childs.path)
ProcessUtilities.popenExecutioner(command)
command = 'chown %s:%s %s' % (externalApp, groupName, childs.path)
ProcessUtilities.popenExecutioner(command)