Initial commit for v2.4.3

This commit is contained in:
usmannasir
2025-08-01 14:56:30 +05:00
commit 6dd7114f6d
4521 changed files with 1795978 additions and 0 deletions

166
WebTerminal/CPWebSocket.py Normal file
View File

@@ -0,0 +1,166 @@
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import sys
import os
sys.path.append('/usr/local/CyberCP')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings")
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
import paramiko
import os
import json
import threading as multi
import time
import asyncio
from plogical.processUtilities import ProcessUtilities
class SSHServer(multi.Thread):
OKGREEN = '\033[92m'
ENDC = '\033[0m'
DEFAULT_PORT = 22
@staticmethod
def findSSHPort():
try:
sshData = ProcessUtilities.outputExecutioner('cat /etc/ssh/sshd_config').split('\n')
for items in sshData:
if items.find('Port') > -1 and items[0] != '#':
if items[0] == 0:
pass
else:
SSHServer.DEFAULT_PORT = int(items.split(' ')[1])
logging.writeToFile('SSH Port for WebTerminal Connection: %s' % (SSHServer.DEFAULT_PORT))
except BaseException as msg:
logging.writeToFile('%s. [SSHServer.findSSHPort]' % (str(msg)))
def loadPublicKey(self):
pubkey = '/root/.ssh/cyberpanel.pub'
data = open(pubkey, 'r').read()
authFile = '/root/.ssh/authorized_keys'
checker = 1
try:
authData = open(authFile, 'r').read()
if authData.find(data) > -1:
checker = 0
except:
pass
if checker:
writeToFile = open(authFile, 'a')
writeToFile.writelines(data)
writeToFile.close()
def __init__(self, websocket):
multi.Thread.__init__(self)
self.sshclient = paramiko.SSHClient()
self.sshclient.load_system_host_keys()
self.sshclient.set_missing_host_key_policy(paramiko.AutoAddPolicy())
k = paramiko.RSAKey.from_private_key_file('/root/.ssh/cyberpanel')
## Load Public Key
self.loadPublicKey()
self.sshclient.connect('127.0.0.1', SSHServer.DEFAULT_PORT, username='root', pkey=k)
self.shell = self.sshclient.invoke_shell(term='xterm')
self.shell.settimeout(0)
self.websocket = websocket
self.color = 0
def recvData(self):
asyncio.set_event_loop(asyncio.new_event_loop())
while True:
try:
if self.websocket.running:
if os.path.exists(self.verifyPath) and self.filePassword == self.password:
if self.shell.recv_ready():
self.websocket.write_message(self.shell.recv(9000).decode("utf-8"))
else:
time.sleep(0.001)
else:
return 0
else:
return 0
except BaseException as msg:
print('%s. [recvData]' % str(msg))
time.sleep(0.001)
def run(self):
try:
self.recvData()
except BaseException as msg:
print('%s. [SSHServer.run]' % (str(msg)))
class WSHandler(tornado.websocket.WebSocketHandler):
def open(self):
print('connected')
self.running = 1
self.sh = SSHServer(self)
self.shell = self.sh.shell
self.sh.start()
self.init = 1
print('connect ok')
def on_message(self, message):
try:
print('handle message')
data = json.loads(message)
if self.init:
self.sh.verifyPath = str(data['data']['verifyPath'])
self.sh.password = str(data['data']['password'])
self.sh.filePassword = open(self.sh.verifyPath, 'r').read()
self.init = 0
else:
if os.path.exists(self.sh.verifyPath):
if self.sh.filePassword == self.sh.password:
self.shell.send(str(data['data']))
except BaseException as msg:
print('%s. [WebTerminalServer.handleMessage]' % (str(msg)))
def on_close(self):
print('connection closed')
def check_origin(self, origin):
return True
application = tornado.web.Application([
(r'/', WSHandler),
])
if __name__ == "__main__":
pidfile = '/usr/local/CyberCP/WebTerminal/pid'
writeToFile = open(pidfile, 'w')
writeToFile.write(str(os.getpid()))
writeToFile.close()
# SSHServer.findSSHPort()
#
# http_server = tornado.httpserver.HTTPServer(application, ssl_options={
# "certfile": "/usr/local/lscp/conf/cert.pem",
# "keyfile": "/usr/local/lscp/conf/key.pem",
# }, )
#
# ADDR = '0.0.0.0'
# http_server.listen(5678, ADDR)
# print('*** Websocket Server Started at %s***' % ADDR)
#
# import signal
# def close_sig_handler(signal, frame):
# http_server.stop()
# sys.exit()
#
# signal.signal(signal.SIGINT, close_sig_handler)
#
# tornado.ioloop.IOLoop.instance().start()

0
WebTerminal/__init__.py Normal file
View File

6
WebTerminal/admin.py Normal file
View File

@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
# Register your models here.

8
WebTerminal/apps.py Normal file
View File

@@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
from django.apps import AppConfig
class WebterminalConfig(AppConfig):
name = 'WebTerminal'

12
WebTerminal/cpssh.service Normal file
View File

@@ -0,0 +1,12 @@
[Unit]
Description = CyberPanel SSH Websocket Daemon
[Service]
Type=forking
ExecStart = /usr/local/CyberCP/bin/python /usr/local/CyberCP/WebTerminal/servCTRL.py start
ExecStop = /usr/local/CyberCP/bin/python /usr/local/CyberCP/WebTerminal/servCTRL.py stop
Restart = /usr/local/CyberCP/bin/python /usr/local/CyberCP/WebTerminal/servCTRL.py restart
Restart=on-abnormal
[Install]
WantedBy=default.target

View File

6
WebTerminal/models.py Normal file
View File

@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
from django.db import models
# Create your models here.

View File

@@ -0,0 +1,8 @@
bcrypt==3.1.7
cffi==1.13.1
cryptography==3.2.1
paramiko==2.6.0
pycparser==2.19
PyNaCl==1.3.0
six==1.12.0
websockets==9.1

51
WebTerminal/servCTRL.py Normal file
View File

@@ -0,0 +1,51 @@
import subprocess
import shlex
import argparse
import os
class servCTRL:
pidfile = '/usr/local/CyberCP/WebTerminal/pid'
def prepareArguments(self):
parser = argparse.ArgumentParser(description='CyberPanel Policy Control Parser!')
parser.add_argument('function', help='Specific a operation to perform!')
return parser.parse_args()
def start(self):
if os.path.exists(servCTRL.pidfile):
self.stop()
command = '/usr/local/CyberCP/bin/python /usr/local/CyberCP/WebTerminal/CPWebSocket.py'
subprocess.Popen(shlex.split(command))
def stop(self):
try:
path = servCTRL.pidfile
command = 'kill -9 %s' % (open(path, 'r').read())
subprocess.Popen(shlex.split(command))
except:
pass
def main():
policy = servCTRL()
args = policy.prepareArguments()
## Website functions
if args.function == "start":
policy.start()
elif args.function == "stop":
policy.stop()
elif args.function == "restart":
policy.stop()
policy.start()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,132 @@
var charWidth = 6.2;
var charHeight = 15.2;
/**
* for full screen
* @returns {{w: number, h: number}}
*/
function getTerminalSize() {
var width = window.innerWidth;
var height = window.innerHeight;
return {
w: Math.floor(width / charWidth),
h: Math.floor(height / charHeight)
};
}
function openTerminal(options) {
if (!$.isEmptyObject($('.terminal')[0])) {
alert("Please refresh this page.");
return
}
var client = new WSSHClient();
var term = new Terminal({cols: 120, rows: 30, screenKeys: true, useStyle: true});
term.on('data', function (data) {
client.sendClientData(data);
});
term.open();
$('.terminal').detach().appendTo('#term');
$("#term").show();
term.write('Connecting...' + '\r\n');
client.connect({
onError: function (error) {
term.write('Error connecting to backend.\r\n');
//term.destroy();
},
onConnect: function () {
client.sendInitData(options);
term.write('connection established..\r\n');
},
onClose: function (e) {
term.write("\r\nconnection closed.")
//term.destroy();
},
onData: function (data) {
term.write(data);
}
})
}
function store(options) {
window.localStorage.host = options.host;
window.localStorage.port = options.port;
window.localStorage.username = options.username;
window.localStorage.ispwd = options.ispwd;
window.localStorage.secret = options.secret
}
function check() {
return validResult["host"] && validResult["port"] && validResult["username"];
}
function connect() {
var remember = $("#remember").is(":checked");
var options = {
verifyPath: $("#verifyPath").text(),
password: $("#password").text()
};
if (remember) {
store(options)
}
openTerminal(options)
}
app.controller('webTerminal', function ($scope, $http, $window) {
$scope.cyberpanelLoading = true;
connect();
$scope.restartSSH = function (name) {
$scope.cyberpanelLoading = false;
url = "/Terminal/restart";
var data = {
name: name
};
var config = {
headers: {
'X-CSRFToken': getCookie('csrftoken')
}
};
$http.post(url, data, config).then(ListInitialDatas, cantLoadInitialDatas);
function ListInitialDatas(response) {
$scope.cyberpanelLoading = true;
if (response.data.status === 1) {
new PNotify({
title: 'Success',
text: 'Successfully restarted SSH server, refreshing the page now..',
type: 'success'
});
$window.location.href = '/Terminal/';
} 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'
});
}
};
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
function WSSHClient() {
};
WSSHClient.prototype._generateEndpoint = function () {
var protocol = 'wss://';
var host = window.location.host.split(':')[0];
var endpoint = protocol + host + ':5678';
return endpoint;
};
WSSHClient.prototype.connect = function (options) {
var endpoint = this._generateEndpoint();
if (window.WebSocket) {
this._connection = new WebSocket(endpoint);
}
else if (window.MozWebSocket) {
this._connection = MozWebSocket(endpoint);
}
else {
options.onError('WebSocket Not Supported');
return;
}
this._connection.onerror = function (evt) {
options.onError(evt);
};
this._connection.onopen = function () {
options.onConnect();
};
this._connection.onmessage = function (evt) {
var data = evt.data.toString()
options.onData(data);
};
this._connection.onclose = function (evt) {
options.onClose(evt);
};
};
WSSHClient.prototype.send = function (data) {
this._connection.send(JSON.stringify(data));
};
WSSHClient.prototype.sendInitData = function (options) {
var data = {
hostname: options.host,
port: options.port,
username: options.username,
ispwd: options.ispwd,
secret: options.secret
};
this._connection.send(JSON.stringify({"tp": "init", "data": options}))
}
WSSHClient.prototype.sendClientData = function (data) {
this._connection.send(JSON.stringify({"tp": "client", "data": data, 'verifyPath': $("#verifyPath").text(), 'password': $("#password").text()}))
}
var client = new WSSHClient();

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -0,0 +1,51 @@
{% extends "baseTemplate/index.html" %}
{% load i18n %}
{% block title %}{% trans "Terminal - CyberPanel" %}{% endblock %}
{% block content %}
{% load static %}
{% get_current_language as LANGUAGE_CODE %}
<!-- Current language: {{ LANGUAGE_CODE }} -->
<div class="container">
<div id="page-title">
<h2>{% trans "Terminal" %} - <a target="_blank" href="https://cyberpanel.net/docs/web-terminal/"
style="height: 23px;line-height: 21px;"
class="btn btn-border btn-alt border-red btn-link font-red"
title=""><span>{% trans "Web Terminal Docs" %}</span></a></h2>
<p>{% trans "Execute your terminal commands." %}</p>
</div>
<div ng-controller="webTerminal" class="row">
<div class="panel">
<div class="panel-body">
<h3 class="content-box-header">
{% trans "Web Terminal" %} -
<button ng-click="restartSSH()" class="btn btn-alt btn-hover btn-blue-alt mx-5 my-10">
<span>{% trans "Reboot SSH Server" %}</span>
<i class="glyph-icon icon-arrow-right"></i>
</button>
<img ng-hide="cyberpanelLoading"
src="{% static 'images/loading.gif' %}">
</h3>
<div class="col-md-12">
<form class="form-horizontal bordered-row panel-body">
<div class="form-group">
<div id="term" class="col-sm-12">
</div>
</div>
</form>
</div>
<div style="display: none" id="verifyPath">{{ verifyPath }}</div>
<div style="display: none" id="password">{{ password }}</div>
</div>
</div>
</div>
</div>
{% endblock %}

6
WebTerminal/tests.py Normal file
View File

@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
from django.test import TestCase
# Create your tests here.

7
WebTerminal/urls.py Normal file
View File

@@ -0,0 +1,7 @@
from django.urls import path
from . import views
urlpatterns = [
path('', views.terminal, name='terminal'),
path('restart', views.restart, name='restart'),
]

69
WebTerminal/views.py Normal file
View File

@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
from django.shortcuts import render, redirect, HttpResponse
from plogical.acl import ACLManager
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
from loginSystem.views import loadLoginPage
from random import randint
import os
from plogical.httpProc import httpProc
from plogical.processUtilities import ProcessUtilities
from plogical.firewallUtilities import FirewallUtilities
from firewall.models import FirewallRules
import json
import plogical.randomPassword
# Create your views here.
def terminal(request):
password = plogical.randomPassword.generate_pass()
verifyPath = "/home/cyberpanel/" + str(randint(100000, 999999))
writeToFile = open(verifyPath, 'w')
writeToFile.write(password)
writeToFile.close()
## setting up ssh server
path = '/etc/systemd/system/cpssh.service'
curPath = '/usr/local/CyberCP/WebTerminal/cpssh.service'
if not os.path.exists(path):
command = 'mv %s %s' % (curPath, path)
ProcessUtilities.executioner(command)
command = 'systemctl start cpssh'
ProcessUtilities.executioner(command)
FirewallUtilities.addRule('tcp', '5678', '0.0.0.0/0')
newFWRule = FirewallRules(name='terminal', proto='tcp', port='5678', ipAddress='0.0.0.0/0')
newFWRule.save()
proc = httpProc(request, 'WebTerminal/WebTerminal.html',
{'verifyPath': verifyPath, 'password': password}, 'admin')
return proc.render()
def restart(request):
try:
userID = request.session['userID']
currentACL = ACLManager.loadedACL(userID)
if currentACL['admin'] == 1:
pass
else:
return ACLManager.loadErrorJson()
command = 'systemctl restart cpssh'
ProcessUtilities.executioner(command)
data_ret = {'status': 1, 'error_message': 'None'}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)
except BaseException as msg:
data_ret = {'status': 0, 'error_message': str(msg)}
json_data = json.dumps(data_ret)
return HttpResponse(json_data)