Add audit log backend stuff.

This commit is contained in:
flash 2018-07-17 19:17:57 +02:00
parent 41109793a7
commit c32525d489
8 changed files with 178 additions and 11 deletions

View file

@ -0,0 +1,66 @@
<?php
namespace Misuzu\DatabaseMigrations\AuditLogStruct;
use PDO;
function migrate_up(PDO $conn): void
{
$conn->exec('
ALTER TABLE `msz_permissions`
RENAME INDEX `user_id` TO `permissions_user_id_unique`,
RENAME INDEX `role_id` TO `permissions_role_id_unique`,
DROP FOREIGN KEY `role_id_foreign`,
DROP FOREIGN KEY `user_id_foreign`,
ADD CONSTRAINT `permissions_user_id_foreign`
FOREIGN KEY (`user_id`)
REFERENCES `msz_users` (`user_id`)
ON UPDATE CASCADE
ON DELETE CASCADE,
ADD CONSTRAINT `permissions_role_id_foreign`
FOREIGN KEY (`role_id`)
REFERENCES `msz_roles` (`role_id`)
ON UPDATE CASCADE
ON DELETE CASCADE
');
$conn->exec("
CREATE TABLE `msz_audit_log` (
`log_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT(10) UNSIGNED NULL DEFAULT NULL,
`log_action` VARCHAR(50) NOT NULL,
`log_params` TEXT NOT NULL,
`log_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`log_ip` VARBINARY(16) NULL DEFAULT NULL,
PRIMARY KEY (`log_id`),
INDEX `audit_log_user_id_foreign` (`user_id`),
CONSTRAINT `audit_log_user_id_foreign`
FOREIGN KEY (`user_id`)
REFERENCES `msz_users` (`user_id`)
ON UPDATE CASCADE
ON DELETE CASCADE
)
");
}
function migrate_down(PDO $conn): void
{
$conn->exec('DROP TABLE `msz_audit_log`');
$conn->exec('
ALTER TABLE `msz_permissions`
RENAME INDEX `permissions_user_id_unique` TO `user_id`,
RENAME INDEX `permissions_role_id_unique` TO `role_id`,
DROP FOREIGN KEY `permissions_user_id_foreign`,
DROP FOREIGN KEY `permissions_role_id_foreign`,
ADD CONSTRAINT `role_id_foreign`
FOREIGN KEY (`user_id`)
REFERENCES `msz_users` (`user_id`)
ON UPDATE CASCADE
ON DELETE CASCADE,
ADD CONSTRAINT `user_id_foreign`
FOREIGN KEY (`role_id`)
REFERENCES `msz_roles` (`role_id`)
ON UPDATE CASCADE
ON DELETE CASCADE
');
}

View file

@ -4,6 +4,7 @@ namespace Misuzu;
date_default_timezone_set('UTC'); date_default_timezone_set('UTC');
require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/src/audit_log.php';
require_once __DIR__ . '/src/changelog.php'; require_once __DIR__ . '/src/changelog.php';
require_once __DIR__ . '/src/colour.php'; require_once __DIR__ . '/src/colour.php';
require_once __DIR__ . '/src/comments.php'; require_once __DIR__ . '/src/comments.php';

View file

@ -113,8 +113,12 @@ switch ($_GET['v'] ?? null) {
$postChange->execute(); $postChange->execute();
if ($changeId < 1) { if ($changeId < 1) {
header('Location: ?v=change&c=' . Database::lastInsertId()); $changeId = Database::lastInsertId();
audit_log('CHANGELOG_ENTRY_CREATE', $app->getUserId(), [$changeId]);
header('Location: ?v=change&c=' . $changeId);
return; return;
} else {
audit_log('CHANGELOG_ENTRY_EDIT', $app->getUserId(), [$changeId]);
} }
} }
@ -122,7 +126,13 @@ switch ($_GET['v'] ?? null) {
$addTag = Database::prepare('REPLACE INTO `msz_changelog_change_tags` VALUES (:change_id, :tag_id)'); $addTag = Database::prepare('REPLACE INTO `msz_changelog_change_tags` VALUES (:change_id, :tag_id)');
$addTag->bindValue('change_id', $changeId); $addTag->bindValue('change_id', $changeId);
$addTag->bindValue('tag_id', $_POST['add_tag']); $addTag->bindValue('tag_id', $_POST['add_tag']);
$addTag->execute();
if ($addTag->execute()) {
audit_log('CHANGELOG_TAG_ADD', $app->getUserId(), [
$changeId,
$_POST['add_tag']
]);
}
} }
if (!empty($_POST['remove_tag']) && is_numeric($_POST['remove_tag'])) { if (!empty($_POST['remove_tag']) && is_numeric($_POST['remove_tag'])) {
@ -133,7 +143,13 @@ switch ($_GET['v'] ?? null) {
'); ');
$removeTag->bindValue('change_id', $changeId); $removeTag->bindValue('change_id', $changeId);
$removeTag->bindValue('tag_id', $_POST['remove_tag']); $removeTag->bindValue('tag_id', $_POST['remove_tag']);
$removeTag->execute();
if ($removeTag->execute()) {
audit_log('CHANGELOG_TAG_REMOVE', $app->getUserId(), [
$changeId,
$_POST['remove_tag']
]);
}
} }
} }
@ -267,8 +283,12 @@ switch ($_GET['v'] ?? null) {
$updateTag->execute(); $updateTag->execute();
if ($tagId < 1) { if ($tagId < 1) {
header('Location: ?v=tag&t=' . Database::lastInsertId()); $tagId = Database::lastInsertId();
audit_log('CHANGELOG_TAG_EDIT', $app->getUserId(), [$tagId]);
header('Location: ?v=tag&t=' . $tagId);
return; return;
} else {
audit_log('CHANGELOG_TAG_CREATE', $app->getUserId(), [$tagId]);
} }
} }
} }
@ -374,8 +394,12 @@ switch ($_GET['v'] ?? null) {
$updateAction->execute(); $updateAction->execute();
if ($actionId < 1) { if ($actionId < 1) {
header('Location: ?v=action&a=' . Database::lastInsertId()); $actionId = Database::lastInsertId();
audit_log('CHANGELOG_ACTION_CREATE', $app->getUserId(), [$actionId]);
header('Location: ?v=action&a=' . $actionId);
return; return;
} else {
audit_log('CHANGELOG_ACTION_EDIT', $app->getUserId(), [$actionId]);
} }
} }
} }

View file

@ -1,16 +1,22 @@
<?php <?php
require_once __DIR__ . '/../../misuzu.php'; require_once __DIR__ . '/../../misuzu.php';
$templating = $app->getTemplating(); $generalPerms = perms_get_user(MSZ_PERMS_GENERAL, $app->getUserId());
$tpl = $app->getTemplating();
switch ($_GET['v'] ?? null) { switch ($_GET['v'] ?? null) {
default: default:
case 'overview': case 'overview':
echo $templating->render('@manage.general.overview'); echo $tpl->render('@manage.general.overview');
break; break;
case 'logs': case 'logs':
echo 'soon'; if (!perms_check($generalPerms, MSZ_GENERAL_PERM_VIEW_LOGS)) {
echo render_error(403);
break;
}
var_dump(audit_log_list(0, 20));
break; break;
case 'emoticons': case 'emoticons':

View file

@ -196,6 +196,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
} }
$updateAccountFields['email'] = strtolower($_POST['email']['new']); $updateAccountFields['email'] = strtolower($_POST['email']['new']);
audit_log('PERSONAL_EMAIL_CHANGE', $app->getUserId(), [
$updateAccountFields['email'],
]);
} }
if (!empty($_POST['password']['new'])) { if (!empty($_POST['password']['new'])) {
@ -213,6 +217,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
} }
$updateAccountFields['password'] = user_password_hash($_POST['password']['new']); $updateAccountFields['password'] = user_password_hash($_POST['password']['new']);
audit_log('PERSONAL_PASSWORD_CHANGE', $app->getUserId());
} }
if (count($updateAccountFields) > 0) { if (count($updateAccountFields) > 0) {
@ -311,6 +317,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
} }
user_session_delete($session['session_id']); user_session_delete($session['session_id']);
audit_log('PERSONAL_SESSION_DESTROY', $app->getUserId(), [
$session['session_id'],
]);
break; break;
} }
} }

61
src/audit_log.php Normal file
View file

@ -0,0 +1,61 @@
<?php
use Misuzu\Database;
use Misuzu\Net\IPAddress;
function audit_log(
string $action,
int $userId = 0,
array $params = [],
IPAddress $ipAddress = null
): void {
$ipAddress = $ipAddress ?? IPAddress::remote();
for ($i = 0; $i < count($params); $i++) {
if (preg_match('#(-?[0-9]+)#', $params[$i])) {
$params[$i] = (int)$params[$i];
}
}
$addLog = Database::prepare('
INSERT INTO `msz_audit_log`
(`log_action`, `user_id`, `log_params`, `log_ip`)
VALUES
(:action, :user, :params, :log_ip)
');
$addLog->bindValue('action', $action);
$addLog->bindValue('user', $userId < 1 ? null : $userId);
$addLog->bindValue('params', json_encode($params));
$addLog->bindValue('log_ip', $ipAddress->getRaw());
$addLog->execute();
}
function audit_log_list(int $offset, int $take, int $userId = 0): array
{
$offset = max(0, $offset);
$take = max(1, $take);
$getLogs = Database::prepare(sprintf('
SELECT
l.`log_id`, l.`log_action`, l.`log_params`, l.`log_created`,
u.`user_id`, u.`username`,
INET6_NTOA(l.`log_ip`) as `log_ip`,
COALESCE(r.`role_colour`, CAST(0x40000000 AS UNSIGNED)) as `user_colour`
FROM `msz_audit_log` as l
LEFT JOIN `msz_users` as u
ON u.`user_id` = l.`user_id`
LEFT JOIN `msz_roles` as r
ON r.`role_id` = u.`display_role`
WHERE %s
ORDER BY l.`log_id` DESC
LIMIT :offset, :take
', $userId < 1 ? '1' : 'l.`user_id` = :user_id'));
if ($userId >= 1) {
$getLogs->bindValue('user_id');
}
$getLogs->bindValue('offset', $offset);
$getLogs->bindValue('take', $take);
return $getLogs->execute() ? $getLogs->fetchAll(PDO::FETCH_ASSOC) : [];
}

View file

@ -28,11 +28,11 @@ function manage_get_menu(int $userId): array
$menu['General'][] = '_'; $menu['General'][] = '_';
if (perms_check($perms['general'], MSZ_GENERAL_PERM_MANAGE_EMOTICONS)) { if (perms_check($perms['general'], MSZ_GENERAL_PERM_MANAGE_EMOTICONS)) {
$menu['General']['Emoticons'] = '/manage/users.php?v=emoticons'; $menu['General']['Emoticons'] = '/manage/index.php?v=emoticons';
} }
if (perms_check($perms['general'], MSZ_GENERAL_PERM_MANAGE_SETTINGS)) { if (perms_check($perms['general'], MSZ_GENERAL_PERM_MANAGE_SETTINGS)) {
$menu['General']['Settings'] = '/manage/users.php?v=settings'; $menu['General']['Settings'] = '/manage/index.php?v=settings';
} }
} }

View file

@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Flashii Broom Closet</title> <title>{{ globals.site_name|default('The') }} Broom Closet</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
<link href="/css/manage.css" rel="stylesheet"> <link href="/css/manage.css" rel="stylesheet">
<link href="/css/libraries.css" rel="stylesheet"> <link href="/css/libraries.css" rel="stylesheet">