mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-11-13 08:46:09 +01:00
ssh logs
This commit is contained in:
@@ -869,10 +869,6 @@ app.controller('OnboardingCP', function ($scope, $http, $timeout, $window) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.controller('dashboardStatsController', function ($scope, $http, $timeout) {
|
app.controller('dashboardStatsController', function ($scope, $http, $timeout) {
|
||||||
// Defensive: force modal hidden on load
|
|
||||||
$scope.showSessionModal = false;
|
|
||||||
$timeout(function() { $scope.showSessionModal = false; }, 200);
|
|
||||||
|
|
||||||
// Card values
|
// Card values
|
||||||
$scope.totalSites = 0;
|
$scope.totalSites = 0;
|
||||||
$scope.totalWPSites = 0;
|
$scope.totalWPSites = 0;
|
||||||
@@ -1201,54 +1197,41 @@ app.controller('dashboardStatsController', function ($scope, $http, $timeout) {
|
|||||||
pollAll();
|
pollAll();
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
// User Session Modal logic
|
// SSH User Activity Modal
|
||||||
$scope.showSessionModal = false;
|
$scope.showSSHActivityModal = false;
|
||||||
$scope.sessionUser = '';
|
$scope.sshActivity = { processes: [], w: [] };
|
||||||
$scope.sessionTTY = '';
|
$scope.sshActivityUser = '';
|
||||||
$scope.sessionWOutput = '';
|
$scope.loadingSSHActivity = false;
|
||||||
$scope.sessionTTYProcesses = '';
|
$scope.errorSSHActivity = '';
|
||||||
$scope.sessionProcesses = '';
|
$scope.viewSSHActivity = function(login) {
|
||||||
$scope.sessionLoading = false;
|
$scope.showSSHActivityModal = true;
|
||||||
$scope.sessionError = '';
|
$scope.sshActivity = { processes: [], w: [] };
|
||||||
|
$scope.sshActivityUser = login.user;
|
||||||
$scope.showUserSession = function(login) {
|
$scope.loadingSSHActivity = true;
|
||||||
$scope.sessionUser = login.user;
|
$scope.errorSSHActivity = '';
|
||||||
$scope.sessionTTY = login.tty || '';
|
var tty = '';
|
||||||
$scope.sessionWOutput = '';
|
// Try to extract tty from login.raw or login.session if available
|
||||||
$scope.sessionTTYProcesses = '';
|
|
||||||
$scope.sessionProcesses = '';
|
|
||||||
$scope.sessionLoading = true;
|
|
||||||
$scope.sessionError = '';
|
|
||||||
$scope.showSessionModal = true;
|
|
||||||
var postData = { user: login.user };
|
|
||||||
// Try to extract tty from login.raw or login.tty if available
|
|
||||||
if (login.raw) {
|
if (login.raw) {
|
||||||
var m = login.raw.match(/(pts\/[0-9]+)/);
|
var match = login.raw.match(/(pts\/[0-9]+)/);
|
||||||
if (m) postData.tty = m[1];
|
if (match) tty = match[1];
|
||||||
} else if (login.tty) {
|
}
|
||||||
postData.tty = login.tty;
|
$http.post('/baseTemplate/getSSHUserActivity', { user: login.user, tty: tty }).then(function(response) {
|
||||||
|
$scope.loadingSSHActivity = false;
|
||||||
|
if (response.data) {
|
||||||
|
$scope.sshActivity = response.data;
|
||||||
|
} else {
|
||||||
|
$scope.sshActivity = { processes: [], w: [] };
|
||||||
}
|
}
|
||||||
$http.post('/base/getUserSessionInfo', postData).then(function(response) {
|
|
||||||
$scope.sessionLoading = false;
|
|
||||||
var data = response.data;
|
|
||||||
$scope.sessionWOutput = data.w_output || '';
|
|
||||||
$scope.sessionTTYProcesses = data.tty_processes || '';
|
|
||||||
$scope.sessionProcesses = data.processes || '';
|
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
$scope.sessionLoading = false;
|
$scope.loadingSSHActivity = false;
|
||||||
$scope.sessionError = (err.data && err.data.error) ? err.data.error : 'Failed to fetch session info.';
|
$scope.errorSSHActivity = (err.data && err.data.error) ? err.data.error : 'Failed to fetch activity.';
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
$scope.closeSSHActivityModal = function() {
|
||||||
$scope.closeSessionModal = function() {
|
$scope.showSSHActivityModal = false;
|
||||||
$scope.showSessionModal = false;
|
$scope.sshActivity = { processes: [], w: [] };
|
||||||
$scope.sessionUser = '';
|
$scope.sshActivityUser = '';
|
||||||
$scope.sessionTTY = '';
|
$scope.loadingSSHActivity = false;
|
||||||
$scope.sessionWOutput = '';
|
$scope.errorSSHActivity = '';
|
||||||
$scope.sessionTTYProcesses = '';
|
|
||||||
$scope.sessionProcesses = '';
|
|
||||||
$scope.sessionLoading = false;
|
|
||||||
$scope.sessionError = '';
|
|
||||||
$timeout(function() { $scope.showSessionModal = false; }, 200);
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -512,7 +512,7 @@
|
|||||||
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Country</th>
|
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Country</th>
|
||||||
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Date</th>
|
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Date</th>
|
||||||
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Session</th>
|
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Session</th>
|
||||||
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Actions</th>
|
<th style="font-weight: 700; color: #4c5fad; background: #e3eafc;">Activity</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -523,9 +523,7 @@
|
|||||||
<td style="padding: 8px 8px; font-family: 'Menlo', 'Monaco', 'Consolas', monospace;">{$ login.date $}</td>
|
<td style="padding: 8px 8px; font-family: 'Menlo', 'Monaco', 'Consolas', monospace;">{$ login.date $}</td>
|
||||||
<td style="padding: 8px 8px;">{$ login.session $}</td>
|
<td style="padding: 8px 8px;">{$ login.session $}</td>
|
||||||
<td style="padding: 8px 8px;">
|
<td style="padding: 8px 8px;">
|
||||||
<button class="btn btn-xs btn-outline-primary view-session-btn" ng-click="showUserSession(login)" title="View Session" style="font-size: 0.98rem; font-weight: 600; border-radius: 16px; padding: 4px 14px; border: 2px solid #4c5fad; color: #4c5fad; background: #fff; transition: all 0.2s;">
|
<button class="btn btn-xs btn-outline-primary" style="padding: 4px 12px; font-size: 0.95rem; border-radius: 14px; font-weight: 600;" ng-click="viewSSHActivity(login)">View Activity</button>
|
||||||
<span style="font-size: 1.1rem; margin-right: 4px;">👁</span> View Session
|
|
||||||
</button>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -1038,31 +1036,6 @@
|
|||||||
.refresh-btn:hover .refresh-icon {
|
.refresh-btn:hover .refresh-icon {
|
||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* User Session Modal */
|
|
||||||
.view-session-btn:hover {
|
|
||||||
background: #4c5fad !important;
|
|
||||||
color: #fff !important;
|
|
||||||
border-color: #4c5fad !important;
|
|
||||||
transform: translateY(-2px);
|
|
||||||
box-shadow: 0 4px 15px rgba(76,95,173,0.10);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal.fade[ng-show] {
|
|
||||||
display: block !important;
|
|
||||||
opacity: 1;
|
|
||||||
pointer-events: auto;
|
|
||||||
z-index: 9999;
|
|
||||||
}
|
|
||||||
|
|
||||||
[ng-cloak] { display: none !important; }
|
|
||||||
.modal.fade[ng-show] {
|
|
||||||
display: block !important;
|
|
||||||
opacity: 1;
|
|
||||||
pointer-events: auto;
|
|
||||||
z-index: 9999;
|
|
||||||
transition: opacity 0.2s;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Chart.js (unchanged) -->
|
<!-- Chart.js (unchanged) -->
|
||||||
@@ -1118,35 +1091,42 @@
|
|||||||
}, 100);
|
}, 100);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- User Session Modal -->
|
<!-- Modal for SSH User Activity -->
|
||||||
<div id="userSessionModal" class="modal fade" tabindex="-1" role="dialog" ng-show="showSessionModal" ng-cloak style="background: rgba(44,62,80,0.25); transition: opacity 0.2s;">
|
<div ng-if="showSSHActivityModal" class="modal fade show" tabindex="-1" style="display: block; background: rgba(44,62,80,0.25); position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 9999;">
|
||||||
<div class="modal-dialog modal-lg" role="document" style="max-width: 800px;">
|
<div style="max-width: 540px; margin: 80px auto; background: #fff; border-radius: 16px; box-shadow: 0 8px 40px rgba(44,62,80,0.18); padding: 32px 28px 24px 28px; position: relative;">
|
||||||
<div class="modal-content" style="border-radius: 16px; box-shadow: 0 8px 32px rgba(44,62,80,0.18);">
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px;">
|
||||||
<div class="modal-header" style="background: #4c5fad; color: #fff; border-radius: 16px 16px 0 0;">
|
<div style="font-size: 1.2rem; font-weight: 800; color: #4c5fad; letter-spacing: 0.5px;">User Activity: <span style="color: #222;">{$ sshActivityUser $}</span></div>
|
||||||
<h5 class="modal-title" style="font-weight: 700;">User Session Info: <span style="font-family: monospace;">{$ sessionUser $}</span></h5>
|
<button class="btn btn-sm btn-outline-primary" style="border-radius: 12px; font-size: 1.1rem; padding: 2px 12px;" ng-click="closeSSHActivityModal()">×</button>
|
||||||
<button type="button" class="close" ng-click="closeSessionModal()" style="color: #fff; font-size: 1.8rem; background: none; border: none; outline: none;">×</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body" style="background: #f8fafc; max-height: 500px; overflow-y: auto;">
|
<div ng-if="loadingSSHActivity" style="text-align: center; color: #888; padding: 20px 0;">Loading activity...</div>
|
||||||
<div ng-if="sessionLoading" style="color: #888; text-align: center; padding: 30px 0;">Loading session info...</div>
|
<div ng-if="errorSSHActivity" style="color: #e53935; padding: 10px 0;">{$ errorSSHActivity $}</div>
|
||||||
<div ng-if="sessionError" style="color: #e53935; padding: 10px 0;">{$ sessionError $}</div>
|
<div ng-if="!loadingSSHActivity && !errorSSHActivity">
|
||||||
<div ng-if="!sessionLoading && !sessionError">
|
<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.</div>
|
||||||
<div style="margin-bottom: 18px;">
|
<div ng-if="sshActivity.processes.length > 0">
|
||||||
<strong>TTY:</strong> <span style="font-family: monospace;">{$ sessionTTY $}</span>
|
<div style="font-weight: 700; color: #4c5fad; margin-bottom: 8px;">Processes:</div>
|
||||||
</div>
|
<table class="table table-sm" style="font-size: 0.98rem;">
|
||||||
<div style="margin-bottom: 18px;">
|
<thead>
|
||||||
<strong>Current Command (w):</strong>
|
<tr style="background: #e3eafc;">
|
||||||
<pre style="background: #fff; border-radius: 8px; padding: 12px; font-size: 1rem; font-family: 'Menlo', 'Monaco', 'Consolas', monospace; color: #333;">{$ sessionWOutput $}</pre>
|
<th>PID</th>
|
||||||
</div>
|
<th>TTY</th>
|
||||||
<div style="margin-bottom: 18px;">
|
<th>Time</th>
|
||||||
<strong>TTY Processes:</strong>
|
<th>Command</th>
|
||||||
<pre style="background: #fff; border-radius: 8px; padding: 12px; font-size: 1rem; font-family: 'Menlo', 'Monaco', 'Consolas', monospace; color: #333;">{$ sessionTTYProcesses $}</pre>
|
</tr>
|
||||||
</div>
|
</thead>
|
||||||
<div>
|
<tbody>
|
||||||
<strong>All User Processes:</strong>
|
<tr ng-repeat="proc in sshActivity.processes">
|
||||||
<pre style="background: #fff; border-radius: 8px; padding: 12px; font-size: 1rem; font-family: 'Menlo', 'Monaco', 'Consolas', monospace; color: #333;">{$ sessionProcesses $}</pre>
|
<td style="font-family: 'Menlo', monospace;">{$ proc.pid $}</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.cmd $}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</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;">{$ sshActivity.w.join('\n') $}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,5 +21,5 @@ urlpatterns = [
|
|||||||
re_path(r'^getCPULoadGraph$', views.getCPULoadGraph, name='getCPULoadGraph'),
|
re_path(r'^getCPULoadGraph$', views.getCPULoadGraph, name='getCPULoadGraph'),
|
||||||
re_path(r'^getRecentSSHLogins$', views.getRecentSSHLogins, name='getRecentSSHLogins'),
|
re_path(r'^getRecentSSHLogins$', views.getRecentSSHLogins, name='getRecentSSHLogins'),
|
||||||
re_path(r'^getRecentSSHLogs$', views.getRecentSSHLogs, name='getRecentSSHLogs'),
|
re_path(r'^getRecentSSHLogs$', views.getRecentSSHLogs, name='getRecentSSHLogs'),
|
||||||
re_path(r'^getUserSessionInfo$', views.getUserSessionInfo, name='getUserSessionInfo'),
|
re_path(r'^getSSHUserActivity$', views.getSSHUserActivity, name='getSSHUserActivity'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -628,7 +628,10 @@ def getRecentSSHLogs(request):
|
|||||||
|
|
||||||
@csrf_exempt
|
@csrf_exempt
|
||||||
@require_POST
|
@require_POST
|
||||||
def getUserSessionInfo(request):
|
def getSSHUserActivity(request):
|
||||||
|
import json
|
||||||
|
from plogical.ACLManager import ACLManager
|
||||||
|
from plogical.processUtilities import ProcessUtilities
|
||||||
try:
|
try:
|
||||||
user_id = request.session.get('userID')
|
user_id = request.session.get('userID')
|
||||||
if not user_id:
|
if not user_id:
|
||||||
@@ -636,26 +639,41 @@ def getUserSessionInfo(request):
|
|||||||
currentACL = ACLManager.loadedACL(user_id)
|
currentACL = ACLManager.loadedACL(user_id)
|
||||||
if not currentACL.get('admin', 0):
|
if not currentACL.get('admin', 0):
|
||||||
return HttpResponse(json.dumps({'error': 'Admin only'}), content_type='application/json', status=403)
|
return HttpResponse(json.dumps({'error': 'Admin only'}), content_type='application/json', status=403)
|
||||||
from plogical.processUtilities import ProcessUtilities
|
|
||||||
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')
|
||||||
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)
|
||||||
result = {}
|
# Get processes for the user
|
||||||
|
ps_cmd = f"ps -u {user} -o pid,tty,time,cmd --no-headers"
|
||||||
try:
|
try:
|
||||||
result['processes'] = ProcessUtilities.outputExecutioner(f'ps -u {user}')
|
ps_output = ProcessUtilities.outputExecutioner(ps_cmd)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
result['processes'] = f'Error: {str(e)}'
|
ps_output = ''
|
||||||
if tty:
|
processes = []
|
||||||
|
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
|
||||||
|
if tty and tty not in tty_val:
|
||||||
|
continue
|
||||||
|
processes.append({
|
||||||
|
'pid': pid,
|
||||||
|
'tty': tty_val,
|
||||||
|
'time': time_val,
|
||||||
|
'cmd': cmd
|
||||||
|
})
|
||||||
|
# Optionally, get 'w' output for more info
|
||||||
|
w_cmd = f"w -h {user}"
|
||||||
try:
|
try:
|
||||||
result['tty_processes'] = ProcessUtilities.outputExecutioner(f'ps -ft {tty}')
|
w_output = ProcessUtilities.outputExecutioner(w_cmd)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
result['tty_processes'] = f'Error: {str(e)}'
|
w_output = ''
|
||||||
try:
|
w_lines = []
|
||||||
result['w_output'] = ProcessUtilities.outputExecutioner(f'w -h {user}')
|
if w_output:
|
||||||
except Exception as e:
|
for line in w_output.strip().split('\n'):
|
||||||
result['w_output'] = f'Error: {str(e)}'
|
w_lines.append(line)
|
||||||
return HttpResponse(json.dumps(result), content_type='application/json')
|
return HttpResponse(json.dumps({'processes': processes, '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)
|
||||||
|
|||||||
Reference in New Issue
Block a user