This commit is contained in:
usmannasir
2025-06-02 22:47:14 +05:00
parent 545faf20c7
commit cc981f47ff
2 changed files with 129 additions and 58 deletions

View File

@@ -566,58 +566,52 @@
{% endif %} {% endif %}
<!-- Fixed SSH Activity Modal --> <!-- Fixed SSH Activity Modal -->
<div ng-if="showSSHActivityModal" class="modal-backdrop" style=" <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)">
position: fixed; <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;">
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="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;"> <div style="font-size: 1.2rem; font-weight: 800; color: #4c5fad; letter-spacing: 0.5px;">
User Activity: <span style="color: #222;">{$ sshActivityUser $}</span> User Activity: <span style="color: #222;">{$ sshActivityUser $}</span>
</div> </div>
<button class="btn btn-sm btn-outline-primary" <button class="btn btn-sm btn-outline-primary" style="border-radius: 12px; font-size: 1.1rem; padding: 2px 12px; cursor: pointer;" ng-click="closeSSHActivityModal()">&times;</button>
style="border-radius: 12px; font-size: 1.1rem; padding: 2px 12px; cursor: pointer;"
ng-click="closeSSHActivityModal()">
&times;
</button>
</div> </div>
<div ng-if="loadingSSHActivity" style="text-align: center; color: #888; padding: 20px 0;">Loading activity...</div>
<div ng-if="loadingSSHActivity" style="text-align: center; color: #888; padding: 20px 0;"> <div ng-if="errorSSHActivity" style="color: #e53935; padding: 10px 0;">{$ errorSSHActivity $}</div>
Loading activity...
</div>
<div ng-if="errorSSHActivity" style="color: #e53935; padding: 10px 0;">
{$ errorSSHActivity $}
</div>
<div ng-if="!loadingSSHActivity && !errorSSHActivity"> <div ng-if="!loadingSSHActivity && !errorSSHActivity">
<div ng-if="sshActivity.processes.length === 0 && sshActivity.w.length === 0" <!-- GeoIP Details -->
style="text-align: center; color: #888; padding: 20px 0;"> <div ng-if="sshActivity.geoip && sshActivity.geoip.ip" style="background: #f8f9fa; border-radius: 10px; margin-bottom: 18px; padding: 14px 18px;">
No active processes found for this user. <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>
<!-- Disk Usage -->
<div ng-if="sshActivity.processes.length > 0"> <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: 8px;">Processes:</div> <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;"> <table class="table table-sm" style="font-size: 0.98rem;">
<thead> <thead>
<tr style="background: #e3eafc;"> <tr style="background: #e3eafc;">
@@ -625,6 +619,7 @@
<th>TTY</th> <th>TTY</th>
<th>Time</th> <th>Time</th>
<th>Command</th> <th>Command</th>
<th>CWD</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -633,14 +628,15 @@
<td style="font-family: 'Menlo', monospace;">{$ proc.tty $}</td> <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.time $}</td>
<td style="font-family: 'Menlo', monospace;">{$ proc.cmd $}</td> <td style="font-family: 'Menlo', monospace;">{$ proc.cmd $}</td>
<td style="font-family: 'Menlo', monospace; color: #4c5fad;">{$ proc.cwd $}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<!-- w output -->
<div ng-if="sshActivity.w.length > 0"> <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: 12px 0 8px 0;">w output:</div> <div style="font-weight: 700; color: #4c5fad; margin-bottom: 6px;">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> <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> </div>
</div> </div>

View File

@@ -21,6 +21,7 @@ from websiteFunctions.models import Websites, WPSites
from databases.models import Databases from databases.models import Databases
from mailServer.models import EUsers from mailServer.models import EUsers
from django.views.decorators.http import require_GET, require_POST from django.views.decorators.http import require_GET, require_POST
import pwd
# Create your views here. # Create your views here.
@@ -629,7 +630,7 @@ def getRecentSSHLogs(request):
@csrf_exempt @csrf_exempt
@require_POST @require_POST
def getSSHUserActivity(request): def getSSHUserActivity(request):
import json import json, os
from plogical.processUtilities import ProcessUtilities from plogical.processUtilities import ProcessUtilities
try: try:
user_id = request.session.get('userID') user_id = request.session.get('userID')
@@ -641,28 +642,95 @@ def getSSHUserActivity(request):
data = json.loads(request.body.decode('utf-8')) data = json.loads(request.body.decode('utf-8'))
user = data.get('user') user = data.get('user')
tty = data.get('tty') tty = data.get('tty')
login_ip = data.get('ip', '')
if not user: if not user:
return HttpResponse(json.dumps({'error': 'Missing user'}), content_type='application/json', status=400) return HttpResponse(json.dumps({'error': 'Missing user'}), content_type='application/json', status=400)
# Get processes for the user # 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: try:
ps_output = ProcessUtilities.outputExecutioner(ps_cmd) ps_output = ProcessUtilities.outputExecutioner(ps_cmd)
except Exception as e: except Exception as e:
ps_output = '' ps_output = ''
processes = [] processes = []
pid_map = {}
if ps_output: if ps_output:
for line in ps_output.strip().split('\n'): for line in ps_output.strip().split('\n'):
parts = line.split(None, 3) parts = line.split(None, 4)
if len(parts) == 4: if len(parts) == 5:
pid, tty_val, time_val, cmd = parts pid, ppid, tty_val, time_val, cmd = parts
if tty and tty not in tty_val: if tty and tty not in tty_val:
continue 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, 'pid': pid,
'ppid': ppid,
'tty': tty_val, 'tty': tty_val,
'time': time_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 # Optionally, get 'w' output for more info
w_cmd = f"w -h {user}" w_cmd = f"w -h {user}"
try: try:
@@ -673,6 +741,13 @@ def getSSHUserActivity(request):
if w_output: if w_output:
for line in w_output.strip().split('\n'): for line in w_output.strip().split('\n'):
w_lines.append(line) 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: except Exception as e:
return HttpResponse(json.dumps({'error': str(e)}), content_type='application/json', status=500) return HttpResponse(json.dumps({'error': str(e)}), content_type='application/json', status=500)