summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2025-07-23 16:02:41 +0200
committerSimon Rettberg2025-07-23 16:02:41 +0200
commitdb2c123ef4c3b9e044f4a7c38a0091ac7f443a52 (patch)
tree2ef33ea19850571fe88039037cd0c942d6d556a3
parent[baseconfig_bwlp/syslog] Update translations (diff)
downloadslx-admin-db2c123ef4c3b9e044f4a7c38a0091ac7f443a52.tar.gz
slx-admin-db2c123ef4c3b9e044f4a7c38a0091ac7f443a52.tar.xz
slx-admin-db2c123ef4c3b9e044f4a7c38a0091ac7f443a52.zip
[session] Add audit log view
Basic 1st version :)
-rw-r--r--inc/audit.inc.php7
-rw-r--r--modules-available/adduser/permissions/permissions.json3
-rw-r--r--modules-available/main/install.inc.php3
-rw-r--r--modules-available/session/lang/de/messages.json1
-rw-r--r--modules-available/session/lang/de/module.json1
-rw-r--r--modules-available/session/lang/de/template-tags.json12
-rw-r--r--modules-available/session/lang/en/messages.json3
-rw-r--r--modules-available/session/lang/en/module.json1
-rw-r--r--modules-available/session/lang/en/template-tags.json12
-rw-r--r--modules-available/session/page.inc.php83
-rw-r--r--modules-available/session/templates/audit-list.html65
-rw-r--r--modules-available/session/templates/change-password.html6
12 files changed, 175 insertions, 22 deletions
diff --git a/inc/audit.inc.php b/inc/audit.inc.php
index 443b5ca6..5a1c7691 100644
--- a/inc/audit.inc.php
+++ b/inc/audit.inc.php
@@ -64,9 +64,10 @@ class Audit
if ($key === 'prevent_autofill' || $key === 'password_fake'
|| $key === 'do' || $key === 'action' || $key === 'token')
continue; // These don't matter
- if (strpos($key, 'pass') !== false || strpos($key, 'token') !== false
- || substr($key, -3) === 'key' // privatekey, hmac-key, ...
- || substr($key, 0, 2) === 'pw') {
+ $lkey = strtolower($key);
+ if (strpos($lkey, 'pass') !== false || strpos($lkey, 'token') !== false
+ || substr($lkey, -3) === 'key' // privatekey, hmac-key, ...
+ || substr($lkey, 0, 2) === 'pw') {
$value = '*****'; // Censor
} elseif (is_array($value)) {
$value = self::processPostArray($value, $maxlen, $hadLongString);
diff --git a/modules-available/adduser/permissions/permissions.json b/modules-available/adduser/permissions/permissions.json
index e8fd0a5e..b06ce7f0 100644
--- a/modules-available/adduser/permissions/permissions.json
+++ b/modules-available/adduser/permissions/permissions.json
@@ -10,5 +10,8 @@
},
"user.view-list": {
"location-aware": false
+ },
+ "audit.show": {
+ "location-aware": false
}
} \ No newline at end of file
diff --git a/modules-available/main/install.inc.php b/modules-available/main/install.inc.php
index d5ce1992..ef8a9f91 100644
--- a/modules-available/main/install.inc.php
+++ b/modules-available/main/install.inc.php
@@ -96,7 +96,8 @@ $res[] = tableCreate('audit', "
`action` varchar(100) NOT NULL,
`data` mediumblob NOT NULL,
`response` smallint(3) unsigned DEFAULT NULL,
- PRIMARY KEY (`id`)
+ PRIMARY KEY (`id`),
+ KEY `dateline` (`dateline`)
");
// Update path
diff --git a/modules-available/session/lang/de/messages.json b/modules-available/session/lang/de/messages.json
index c75973f0..f0f15734 100644
--- a/modules-available/session/lang/de/messages.json
+++ b/modules-available/session/lang/de/messages.json
@@ -3,5 +3,6 @@
"pass-too-short": "Passwort zu kurz",
"password-changed": "Passwort erfolgreich ge\u00e4ndert",
"password-unchanged": "Passwort wurde nicht ge\u00e4ndert",
+ "user-not-found": "Unbekannte Nutzer-ID",
"wrong-password": "Falsches Passwort"
} \ No newline at end of file
diff --git a/modules-available/session/lang/de/module.json b/modules-available/session/lang/de/module.json
index afd14498..9333859e 100644
--- a/modules-available/session/lang/de/module.json
+++ b/modules-available/session/lang/de/module.json
@@ -1,5 +1,6 @@
{
"module_name": "Sitzungsverwaltung",
+ "page-title-audit-list": "Audit log",
"page-title-session-list": "Aktive Sitzungen",
"page_title": "Anmelden"
} \ No newline at end of file
diff --git a/modules-available/session/lang/de/template-tags.json b/modules-available/session/lang/de/template-tags.json
index 5c32788d..1c9a0480 100644
--- a/modules-available/session/lang/de/template-tags.json
+++ b/modules-available/session/lang/de/template-tags.json
@@ -1,14 +1,24 @@
{
+ "lang_action": "Aktion",
"lang_activeSessions": "Bekannte Sitzungen",
+ "lang_auditLogHeading": "Audit-Log",
+ "lang_auditLogIntro": "Hier sehen Sie das Protokoll der in dieser Administrationsoberfl\u00e4che ausgef\u00fchrten Aktionen.",
"lang_changePassword": "Passwort \u00e4ndern",
+ "lang_clearFilter": "L\u00f6schen",
"lang_currentPassword": "Aktuelles Passwort",
+ "lang_currentlyFilteredByUser": "Aktuell gefiltert Nach Nutzer",
"lang_enter": "Anmeldung",
"lang_expires": "L\u00e4uft bei Inaktivit\u00e4t ab",
"lang_fixedIpSession": "Sitzung an IP-Adresse binden",
"lang_killOtherSessions": "Alle meine anderen Sitzungen ausloggen",
"lang_lastAddress": "Letzter Zugriff von",
"lang_login": "Anmelden",
+ "lang_module": "Modul",
"lang_newPassword": "Neues Passwort",
+ "lang_params": "Parameter",
"lang_register": "Registrieren",
- "lang_repeatPassword": "Passwort wiederholen"
+ "lang_repeatPassword": "Passwort wiederholen",
+ "lang_responseCode": "HTTP-Code",
+ "lang_showAuditLog": "Audit-Log der Adminoberfl\u00e4che",
+ "lang_when": "Wann"
} \ No newline at end of file
diff --git a/modules-available/session/lang/en/messages.json b/modules-available/session/lang/en/messages.json
index a7b14d61..9c81729c 100644
--- a/modules-available/session/lang/en/messages.json
+++ b/modules-available/session/lang/en/messages.json
@@ -3,5 +3,6 @@
"pass-too-short": "Password too short",
"password-changed": "Password successfully changed",
"password-unchanged": "Password unchanged",
+ "user-not-found": "Unknown user id",
"wrong-password": "Wrong password"
-}
+} \ No newline at end of file
diff --git a/modules-available/session/lang/en/module.json b/modules-available/session/lang/en/module.json
index 2227d2ed..66b54fcd 100644
--- a/modules-available/session/lang/en/module.json
+++ b/modules-available/session/lang/en/module.json
@@ -1,5 +1,6 @@
{
"module_name": "Session management",
+ "page-title-audit-list": "Audit log",
"page-title-session-list": "Active sessions",
"page_title": "Log in"
} \ No newline at end of file
diff --git a/modules-available/session/lang/en/template-tags.json b/modules-available/session/lang/en/template-tags.json
index d7f8d98b..eb2c10bf 100644
--- a/modules-available/session/lang/en/template-tags.json
+++ b/modules-available/session/lang/en/template-tags.json
@@ -1,14 +1,24 @@
{
+ "lang_action": "Action",
"lang_activeSessions": "Known sessions",
+ "lang_auditLogHeading": "Audit log",
+ "lang_auditLogIntro": "This is the log of all actions performed on this admin interface.",
"lang_changePassword": "Change password",
+ "lang_clearFilter": "Clear",
"lang_currentPassword": "Current password",
+ "lang_currentlyFilteredByUser": "Currently filtered by user",
"lang_enter": "Enter",
"lang_expires": "Expires on no activity",
"lang_fixedIpSession": "Bind session to IP address",
"lang_killOtherSessions": "Log out all my other sessions",
"lang_lastAddress": "Last access from",
"lang_login": "Login",
+ "lang_module": "Module",
"lang_newPassword": "New password",
+ "lang_params": "Parameters",
"lang_register": "Register",
- "lang_repeatPassword": "Repeat password"
+ "lang_repeatPassword": "Repeat password",
+ "lang_responseCode": "HTTP code",
+ "lang_showAuditLog": "Show audit log of admin interface",
+ "lang_when": "When"
} \ No newline at end of file
diff --git a/modules-available/session/page.inc.php b/modules-available/session/page.inc.php
index c59af63a..d113f523 100644
--- a/modules-available/session/page.inc.php
+++ b/modules-available/session/page.inc.php
@@ -54,31 +54,86 @@ class Page_Session extends Page
}
Util::redirect('?do=session', 200);
} else {
- // No action, change title to session list
- Render::setTitle(Dictionary::translate('page-title-session-list'));
+ // No action, change title
+ switch (Request::get('show', false, 'string')) {
+ case 'audit':
+ Render::setTitle(Dictionary::translate('page-title-audit-list'));;
+ break;
+ default:
+ Render::setTitle(Dictionary::translate('page-title-session-list'));
+ }
}
}
protected function doRender()
{
if (User::isLoggedIn()) {
- $res = Database::simpleQuery("SELECT u.login, s.userid, s.dateline, s.lastip, s.fixedip
+ $show = Request::get('show', false, 'string');
+ if ($show === 'audit') {
+ self::showAudit();
+ } else {
+ self::showSessions();
+ }
+ } else {
+ Render::addTemplate('page-login');
+ }
+ }
+
+ private static function showSessions()
+ {
+ $res = Database::simpleQuery("SELECT u.login, s.userid, s.dateline, s.lastip, s.fixedip
FROM session s
INNER JOIN user u USING (userid)
ORDER BY dateline DESC");
- $sessions = [];
- $perm = User::hasPermission('.adduser.user.*');
- foreach ($res as $row) {
- if ($perm || $row['userid'] == User::getId()) {
- $row['dateline_s'] = Util::prettyTime($row['dateline']);
- $sessions[] = $row;
- }
+ $sessions = [];
+ $perm = User::hasPermission('.adduser.user.*');
+ foreach ($res as $row) {
+ if ($perm || $row['userid'] == User::getId()) {
+ $row['dateline_s'] = Util::prettyTime($row['dateline']);
+ $sessions[] = $row;
+ }
+ }
+ Render::addTemplate('change-password', [
+ 'sessions' => $sessions,
+ 'link' => User::hasPermission('.adduser.user.edit'),
+ 'audit' => User::hasPermission('.adduser.audit.show'),
+ ]);
+ }
+
+ private static function showAudit()
+ {
+ User::assertPermission('.adduser.audit.show');
+ $user = Request::get('user', 0, 'int');
+ $args = [];
+ $extra = '';
+ $username = null;
+ if ($user > 0) {
+ $args['userid'] = $user;
+ $extra .= ' WHERE a.userid = :userid';
+ $row = Database::queryFirst("SELECT login FROM user WHERE userid = :userid", ['userid' => $user]);
+ if ($row === false) {
+ Message::addError('user-not-found', $user);
+ Util::redirect('?do=session&show=audit', 404);
+ }
+ $username = $row['login'];
+ }
+ $res = Database::queryAll("SELECT u.userid, u.login,
+ a.action, a.dateline, a.ipaddr, a.data, a.module, a.response
+ FROM audit a
+ LEFT JOIN user u USING (userid)
+ $extra
+ ORDER BY dateline DESC
+ LIMIT 500", $args);
+ foreach ($res as &$row) {
+ $row['dateline_s'] = Util::prettyTime($row['dateline']);
+ if ($row['response'] < 200 || $row['response'] >= 400) {
+ $row['class'] = 'text-danger slx-bold';
+ }
+ if ($username !== null) {
+ unset($row['login']);
}
- Render::addTemplate('change-password', ['sessions' => $sessions,
- 'link' => User::hasPermission('.adduser.user.edit')]);
- } else {
- Render::addTemplate('page-login');
}
+ Render::addTemplate('audit-list', ['list' => $res, 'user' => $username]);
}
}
diff --git a/modules-available/session/templates/audit-list.html b/modules-available/session/templates/audit-list.html
new file mode 100644
index 00000000..0c79c52d
--- /dev/null
+++ b/modules-available/session/templates/audit-list.html
@@ -0,0 +1,65 @@
+<div class="page-header">
+ <h1>{{lang_auditLogHeading}}</h1>
+ <p>{{lang_auditLogIntro}}</p>
+</div>
+
+{{#user}}
+ <p>
+ {{lang_currentlyFilteredByUser}}: <b>{{user}}</b>
+ <a class="btn btn-xs btn-danger" href="?do=session&amp;show=audit">
+ <span class="glyphicon glyphicon-remove"></span>
+ {{lang_clearFilter}}
+ </a>
+ </p>
+{{/user}}
+
+<table class="table">
+ <tr>
+ <th>{{lang_when}}</th>
+ <th>{{lang_responseCode}}</th>
+ <th>{{lang_user}}</th>
+ <th>{{lang_module}}</th>
+ <th>{{lang_action}}</th>
+ <th>{{lang_params}}</th>
+ </tr>
+ {{#list}}
+ <tr>
+ <td class="text-nowrap">{{dateline_s}}</td>
+ <td class="{{class}}">{{response}}</td>
+ <td>
+ {{^login}}{{ipaddr}}{{/login}}
+ {{#login}}
+ <a href="?do=session&amp;show=audit&amp;user={{userid}}">{{login}}</a>
+ {{/login}}
+ </td>
+ <td class="text-nowrap">{{module}}</td>
+ <td class="text-nowrap">{{action}}</td>
+ <td><table class="slx-ellipsis"><tr><td class="json-stuff" data-toggle="modal" data-target="#myModal">{{data}}</td></tr></table></td>
+ </tr>
+ {{/list}}
+</table>
+
+<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+ <div class="modal-dialog modal-lg">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span
+ class="sr-only">{{lang_close}}</span></button>
+ <h4 class="modal-title" id="myModalLabel">{{lang_params}}</h4>
+ </div>
+ <div class="modal-body">
+ <pre id="details-body"></pre>
+ </div>
+ </div>
+ </div>
+</div>
+
+<script>
+ document.addEventListener('DOMContentLoaded', function() {
+ $('.json-stuff').click(function() {
+ var txt = $(this).text();
+ txt = JSON.stringify(JSON.parse(txt), null, 2);
+ $('#details-body').text(txt);
+ });
+ });
+</script> \ No newline at end of file
diff --git a/modules-available/session/templates/change-password.html b/modules-available/session/templates/change-password.html
index 9f19c695..10b0f43d 100644
--- a/modules-available/session/templates/change-password.html
+++ b/modules-available/session/templates/change-password.html
@@ -49,4 +49,8 @@
</tr>
{{/sessions}}
</tbody>
-</table> \ No newline at end of file
+</table>
+
+{{#audit}}
+ <a href="?do=session&amp;show=audit">{{lang_showAuditLog}} &raquo;</a>
+{{/audit}} \ No newline at end of file