mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-11-13 08:46:09 +01:00
ssh logs
This commit is contained in:
@@ -566,58 +566,52 @@
|
||||
{% endif %}
|
||||
|
||||
<!-- Fixed SSH Activity Modal -->
|
||||
<div ng-if="showSSHActivityModal" class="modal-backdrop" style="
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: rgba(0,0,0,0.5);
|
||||
z-index: 10000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
" ng-click="closeModalOnBackdrop($event)">
|
||||
<div class="modal-content" style="
|
||||
max-width: 90vw;
|
||||
max-height: 90vh;
|
||||
width: 600px;
|
||||
background: #fff;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 8px 40px rgba(44,62,80,0.18);
|
||||
padding: 32px 28px 24px 28px;
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
">
|
||||
<div ng-if="showSSHActivityModal" class="modal-backdrop" style="position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(0,0,0,0.5); z-index: 10000; display: flex; align-items: center; justify-content: center; padding: 20px; box-sizing: border-box;" ng-click="closeModalOnBackdrop($event)">
|
||||
<div class="modal-content" style="max-width: 90vw; max-height: 90vh; width: 600px; background: #fff; border-radius: 16px; box-shadow: 0 8px 40px rgba(44,62,80,0.18); padding: 32px 28px 24px 28px; position: relative; overflow-y: auto;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px;">
|
||||
<div style="font-size: 1.2rem; font-weight: 800; color: #4c5fad; letter-spacing: 0.5px;">
|
||||
User Activity: <span style="color: #222;">{$ sshActivityUser $}</span>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-outline-primary"
|
||||
style="border-radius: 12px; font-size: 1.1rem; padding: 2px 12px; cursor: pointer;"
|
||||
ng-click="closeSSHActivityModal()">
|
||||
×
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-primary" style="border-radius: 12px; font-size: 1.1rem; padding: 2px 12px; cursor: pointer;" ng-click="closeSSHActivityModal()">×</button>
|
||||
</div>
|
||||
|
||||
<div ng-if="loadingSSHActivity" style="text-align: center; color: #888; padding: 20px 0;">
|
||||
Loading activity...
|
||||
</div>
|
||||
|
||||
<div ng-if="errorSSHActivity" style="color: #e53935; padding: 10px 0;">
|
||||
{$ errorSSHActivity $}
|
||||
</div>
|
||||
|
||||
<div ng-if="loadingSSHActivity" style="text-align: center; color: #888; padding: 20px 0;">Loading activity...</div>
|
||||
<div ng-if="errorSSHActivity" style="color: #e53935; padding: 10px 0;">{$ errorSSHActivity $}</div>
|
||||
<div ng-if="!loadingSSHActivity && !errorSSHActivity">
|
||||
<div ng-if="sshActivity.processes.length === 0 && sshActivity.w.length === 0"
|
||||
style="text-align: center; color: #888; padding: 20px 0;">
|
||||
No active processes found for this user.
|
||||
<!-- GeoIP Details -->
|
||||
<div ng-if="sshActivity.geoip && sshActivity.geoip.ip" style="background: #f8f9fa; border-radius: 10px; margin-bottom: 18px; padding: 14px 18px;">
|
||||
<div style="font-weight: 700; color: #4c5fad; margin-bottom: 6px;">Login Location & ISP</div>
|
||||
<div style="font-size: 1.01rem; color: #333;">
|
||||
<span ng-if="sshActivity.geoip.city">{$ sshActivity.geoip.city $}, </span>
|
||||
<span ng-if="sshActivity.geoip.region">{$ sshActivity.geoip.region $}, </span>
|
||||
<span ng-if="sshActivity.geoip.country">{$ sshActivity.geoip.country $}</span><br/>
|
||||
<span ng-if="sshActivity.geoip.isp">ISP: {$ sshActivity.geoip.isp $}</span>
|
||||
<span ng-if="sshActivity.geoip.org">, Org: {$ sshActivity.geoip.org $}</span><br/>
|
||||
<span ng-if="sshActivity.geoip.as">ASN: {$ sshActivity.geoip.as $}</span><br/>
|
||||
<span style="color: #888; font-size: 0.97rem;">IP: {$ sshActivity.geoip.ip $}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="sshActivity.processes.length > 0">
|
||||
<div style="font-weight: 700; color: #4c5fad; margin-bottom: 8px;">Processes:</div>
|
||||
<!-- Disk Usage -->
|
||||
<div ng-if="sshActivity.disk_usage" style="background: #f8f9fa; border-radius: 10px; margin-bottom: 18px; padding: 14px 18px;">
|
||||
<div style="font-weight: 700; color: #4c5fad; margin-bottom: 6px;">Disk Usage</div>
|
||||
<div style="font-size: 1.01rem; color: #333;">Home Directory: <b>{$ sshActivity.disk_usage $}</b></div>
|
||||
</div>
|
||||
<!-- Shell History -->
|
||||
<div ng-if="sshActivity.shell_history && sshActivity.shell_history.length > 0" style="background: #f8f9fa; border-radius: 10px; margin-bottom: 18px; padding: 14px 18px;">
|
||||
<div style="font-weight: 700; color: #4c5fad; margin-bottom: 6px;">Shell History (last 10 commands)</div>
|
||||
<pre style="background: #fff; border-radius: 8px; padding: 10px 12px; color: #333; font-size: 0.97rem; white-space: pre-wrap; word-wrap: break-word; margin-bottom: 0;">{$ sshActivity.shell_history.join('\n') $}</pre>
|
||||
</div>
|
||||
<!-- Process Tree -->
|
||||
<div ng-if="sshActivity.process_tree && sshActivity.process_tree.length > 0" style="background: #f8f9fa; border-radius: 10px; margin-bottom: 18px; padding: 14px 18px;">
|
||||
<div style="font-weight: 700; color: #4c5fad; margin-bottom: 6px;">Process Tree</div>
|
||||
<ul style="list-style: none; padding-left: 0;">
|
||||
<li ng-repeat="proc in sshActivity.process_tree" style="font-family: 'Menlo', monospace; color: #333; padding-left: {$ proc.level * 18 $}px;">
|
||||
<span style="color: #888;">[{$ proc.pid $}]</span> {$ proc.cmd $} <span ng-if="proc.cwd" style="color: #4c5fad; font-size: 0.95em;">(cwd: {$ proc.cwd $})</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Processes Table -->
|
||||
<div ng-if="sshActivity.processes && sshActivity.processes.length > 0" style="background: #f8f9fa; border-radius: 10px; margin-bottom: 18px; padding: 14px 18px;">
|
||||
<div style="font-weight: 700; color: #4c5fad; margin-bottom: 6px;">Processes</div>
|
||||
<table class="table table-sm" style="font-size: 0.98rem;">
|
||||
<thead>
|
||||
<tr style="background: #e3eafc;">
|
||||
@@ -625,6 +619,7 @@
|
||||
<th>TTY</th>
|
||||
<th>Time</th>
|
||||
<th>Command</th>
|
||||
<th>CWD</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -633,14 +628,15 @@
|
||||
<td style="font-family: 'Menlo', monospace;">{$ proc.tty $}</td>
|
||||
<td style="font-family: 'Menlo', monospace;">{$ proc.time $}</td>
|
||||
<td style="font-family: 'Menlo', monospace;">{$ proc.cmd $}</td>
|
||||
<td style="font-family: 'Menlo', monospace; color: #4c5fad;">{$ proc.cwd $}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div ng-if="sshActivity.w.length > 0">
|
||||
<div style="font-weight: 700; color: #4c5fad; margin: 12px 0 8px 0;">w output:</div>
|
||||
<pre style="background: #f8f9fa; border-radius: 8px; padding: 10px 12px; color: #333; font-size: 0.97rem; white-space: pre-wrap; word-wrap: break-word;">{$ sshActivity.w.join('\n') $}</pre>
|
||||
<!-- w output -->
|
||||
<div ng-if="sshActivity.w.length > 0" style="background: #f8f9fa; border-radius: 10px; margin-bottom: 0; padding: 14px 18px;">
|
||||
<div style="font-weight: 700; color: #4c5fad; margin-bottom: 6px;">w output</div>
|
||||
<pre style="background: #fff; border-radius: 8px; padding: 10px 12px; color: #333; font-size: 0.97rem; white-space: pre-wrap; word-wrap: break-word; margin-bottom: 0;">{$ sshActivity.w.join('\n') $}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -21,6 +21,7 @@ from websiteFunctions.models import Websites, WPSites
|
||||
from databases.models import Databases
|
||||
from mailServer.models import EUsers
|
||||
from django.views.decorators.http import require_GET, require_POST
|
||||
import pwd
|
||||
|
||||
# Create your views here.
|
||||
|
||||
@@ -629,7 +630,7 @@ def getRecentSSHLogs(request):
|
||||
@csrf_exempt
|
||||
@require_POST
|
||||
def getSSHUserActivity(request):
|
||||
import json
|
||||
import json, os
|
||||
from plogical.processUtilities import ProcessUtilities
|
||||
try:
|
||||
user_id = request.session.get('userID')
|
||||
@@ -641,28 +642,95 @@ def getSSHUserActivity(request):
|
||||
data = json.loads(request.body.decode('utf-8'))
|
||||
user = data.get('user')
|
||||
tty = data.get('tty')
|
||||
login_ip = data.get('ip', '')
|
||||
if not user:
|
||||
return HttpResponse(json.dumps({'error': 'Missing user'}), content_type='application/json', status=400)
|
||||
# Get processes for the user
|
||||
ps_cmd = f"ps -u {user} -o pid,tty,time,cmd --no-headers"
|
||||
ps_cmd = f"ps -u {user} -o pid,ppid,tty,time,cmd --no-headers"
|
||||
try:
|
||||
ps_output = ProcessUtilities.outputExecutioner(ps_cmd)
|
||||
except Exception as e:
|
||||
ps_output = ''
|
||||
processes = []
|
||||
pid_map = {}
|
||||
if ps_output:
|
||||
for line in ps_output.strip().split('\n'):
|
||||
parts = line.split(None, 3)
|
||||
if len(parts) == 4:
|
||||
pid, tty_val, time_val, cmd = parts
|
||||
parts = line.split(None, 4)
|
||||
if len(parts) == 5:
|
||||
pid, ppid, tty_val, time_val, cmd = parts
|
||||
if tty and tty not in tty_val:
|
||||
continue
|
||||
processes.append({
|
||||
# Try to get CWD
|
||||
cwd = ''
|
||||
try:
|
||||
cwd_path = f"/proc/{pid}/cwd"
|
||||
if os.path.islink(cwd_path):
|
||||
cwd = os.readlink(cwd_path)
|
||||
except Exception:
|
||||
cwd = ''
|
||||
proc = {
|
||||
'pid': pid,
|
||||
'ppid': ppid,
|
||||
'tty': tty_val,
|
||||
'time': time_val,
|
||||
'cmd': cmd
|
||||
})
|
||||
'cmd': cmd,
|
||||
'cwd': cwd
|
||||
}
|
||||
processes.append(proc)
|
||||
pid_map[pid] = proc
|
||||
# Build process tree
|
||||
tree = []
|
||||
def build_tree(parent_pid, level=0):
|
||||
for proc in processes:
|
||||
if proc['ppid'] == parent_pid:
|
||||
proc_copy = proc.copy()
|
||||
proc_copy['level'] = level
|
||||
tree.append(proc_copy)
|
||||
build_tree(proc['pid'], level+1)
|
||||
build_tree('1', 0) # Start from init
|
||||
# Find main shell process for history
|
||||
shell_history = []
|
||||
try:
|
||||
shell_home = pwd.getpwnam(user).pw_dir
|
||||
except Exception:
|
||||
shell_home = f"/home/{user}"
|
||||
history_file = ''
|
||||
for shell in ['.bash_history', '.zsh_history']:
|
||||
path = os.path.join(shell_home, shell)
|
||||
if os.path.exists(path):
|
||||
history_file = path
|
||||
break
|
||||
if history_file:
|
||||
try:
|
||||
with open(history_file, 'r') as f:
|
||||
lines = f.readlines()
|
||||
shell_history = [l.strip() for l in lines[-10:]]
|
||||
except Exception:
|
||||
shell_history = []
|
||||
# Disk usage
|
||||
disk_usage = ''
|
||||
try:
|
||||
du_out = ProcessUtilities.outputExecutioner(f'du -sh {shell_home}')
|
||||
disk_usage = du_out.strip().split('\t')[0] if du_out else ''
|
||||
except Exception:
|
||||
disk_usage = ''
|
||||
# GeoIP details
|
||||
geoip = {}
|
||||
if login_ip and login_ip not in ['127.0.0.1', 'localhost']:
|
||||
try:
|
||||
geo = requests.get(f'http://ip-api.com/json/{login_ip}?fields=status,message,country,regionName,city,isp,org,as,query', timeout=2).json()
|
||||
if geo.get('status') == 'success':
|
||||
geoip = {
|
||||
'country': geo.get('country'),
|
||||
'region': geo.get('regionName'),
|
||||
'city': geo.get('city'),
|
||||
'isp': geo.get('isp'),
|
||||
'org': geo.get('org'),
|
||||
'as': geo.get('as'),
|
||||
'ip': geo.get('query')
|
||||
}
|
||||
except Exception:
|
||||
geoip = {}
|
||||
# Optionally, get 'w' output for more info
|
||||
w_cmd = f"w -h {user}"
|
||||
try:
|
||||
@@ -673,6 +741,13 @@ def getSSHUserActivity(request):
|
||||
if w_output:
|
||||
for line in w_output.strip().split('\n'):
|
||||
w_lines.append(line)
|
||||
return HttpResponse(json.dumps({'processes': processes, 'w': w_lines}), content_type='application/json')
|
||||
return HttpResponse(json.dumps({
|
||||
'processes': processes,
|
||||
'process_tree': tree,
|
||||
'shell_history': shell_history,
|
||||
'disk_usage': disk_usage,
|
||||
'geoip': geoip,
|
||||
'w': w_lines
|
||||
}), content_type='application/json')
|
||||
except Exception as e:
|
||||
return HttpResponse(json.dumps({'error': str(e)}), content_type='application/json', status=500)
|
||||
|
||||
Reference in New Issue
Block a user