Skip to content

Commit

Permalink
feat: Write critical operations to the audit log
Browse files Browse the repository at this point in the history
Signed-off-by: Hoang Pham <hoangmaths96@gmail.com>
  • Loading branch information
hweihwang committed Apr 2, 2024
1 parent b881e80 commit 7eca1c1
Show file tree
Hide file tree
Showing 14 changed files with 368 additions and 9 deletions.
16 changes: 16 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,25 @@
use Exception;
use OCA\Analytics\Datasource\DatasourceEvent;
use OCA\Tables\Capabilities;
use OCA\Tables\Event\RowDeletedEvent;
use OCA\Tables\Event\TableDeletedEvent;
use OCA\Tables\Event\TableOwnershipTransferredEvent;
use OCA\Tables\Event\ViewDeletedEvent;
use OCA\Tables\Listener\AnalyticsDatasourceListener;
use OCA\Tables\Listener\BeforeTemplateRenderedListener;
use OCA\Tables\Listener\LoadAdditionalListener;
use OCA\Tables\Listener\TablesReferenceListener;
use OCA\Tables\Listener\UserDeletedListener;
use OCA\Tables\Listener\WhenRowDeletedAuditLogListener;
use OCA\Tables\Listener\WhenTableDeletedAuditLogListener;
use OCA\Tables\Listener\WhenTableTransferredAuditLogListener;
use OCA\Tables\Listener\WhenViewDeletedAuditLogListener;
use OCA\Tables\Middleware\PermissionMiddleware;
use OCA\Tables\Reference\ContentReferenceProvider;
use OCA\Tables\Reference\ReferenceProvider;
use OCA\Tables\Search\SearchTablesProvider;
use OCA\Tables\Service\Support\AuditLogServiceInterface;
use OCA\Tables\Service\Support\DefaultAuditLogService;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
Expand Down Expand Up @@ -47,11 +57,17 @@ public function register(IRegistrationContext $context): void {
throw new Exception('Cannot include autoload. Did you run install dependencies using composer?');
}

$context->registerService(AuditLogServiceInterface::class, fn($c) => $c->query(DefaultAuditLogService::class));

$context->registerEventListener(BeforeUserDeletedEvent::class, UserDeletedListener::class);
$context->registerEventListener(DatasourceEvent::class, AnalyticsDatasourceListener::class);
$context->registerEventListener(RenderReferenceEvent::class, TablesReferenceListener::class);
$context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class);
$context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class);
$context->registerEventListener(TableDeletedEvent::class, WhenTableDeletedAuditLogListener::class);
$context->registerEventListener(ViewDeletedEvent::class, WhenViewDeletedAuditLogListener::class);
$context->registerEventListener(RowDeletedEvent::class, WhenRowDeletedAuditLogListener::class);
$context->registerEventListener(TableOwnershipTransferredEvent::class, WhenTableTransferredAuditLogListener::class);

$context->registerSearchProvider(SearchTablesProvider::class);

Expand Down
26 changes: 26 additions & 0 deletions lib/Event/RowDeletedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Event;

use OCA\Tables\Db\Row2;
use OCP\EventDispatcher\Event;

final class RowDeletedEvent extends Event
{
public function __construct(protected Row2 $row, protected string $userId)
{
parent::__construct();
}

public function getRow(): Row2
{
return $this->row;
}

public function getUserId(): string
{
return $this->userId;
}
}
26 changes: 26 additions & 0 deletions lib/Event/TableDeletedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Event;

use OCA\Tables\Db\Table;
use OCP\EventDispatcher\Event;

final class TableDeletedEvent extends Event
{
public function __construct(protected Table $table, protected string $userId)
{
parent::__construct();
}

public function getTable(): Table
{
return $this->table;
}

public function getUserId(): string
{
return $this->userId;
}
}
31 changes: 31 additions & 0 deletions lib/Event/TableOwnershipTransferredEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Event;

use OCA\Tables\Db\Table;
use OCP\EventDispatcher\Event;

final class TableOwnershipTransferredEvent extends Event
{
public function __construct(protected Table $table, protected string $toUserId, protected ?string $fromUserId = null)
{
parent::__construct();
}

public function getTable(): Table
{
return $this->table;
}

public function getFromUserId(): string
{
return $this->fromUserId;
}

public function getToUserId(): string
{
return $this->toUserId;
}
}
26 changes: 26 additions & 0 deletions lib/Event/ViewDeletedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Event;

use OCA\Tables\Db\View;
use OCP\EventDispatcher\Event;

final class ViewDeletedEvent extends Event
{
public function __construct(protected View $view, protected string $userId)
{
parent::__construct();
}

public function getView(): View
{
return $this->view;
}

public function getUserId(): string
{
return $this->userId;
}
}
33 changes: 33 additions & 0 deletions lib/Listener/WhenRowDeletedAuditLogListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Listener;

use OCA\Tables\Event\RowDeletedEvent;
use OCA\Tables\Service\Support\AuditLogServiceInterface;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;

final class WhenRowDeletedAuditLogListener implements IEventListener
{
public function __construct(protected AuditLogServiceInterface $auditLogService)
{
}

public function handle(Event $event): void
{
if (!($event instanceof RowDeletedEvent)) {
return;
}

$row = $event->getRow();
$userId = $event->getUserId();
$rowId = $row->getId();

$this->auditLogService->log("Row with ID: $rowId was deleted by user with ID: $userId", [
'row' => $row->jsonSerialize(),
'userId' => $userId,
]);
}
}
32 changes: 32 additions & 0 deletions lib/Listener/WhenTableDeletedAuditLogListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Listener;

use OCA\Tables\Event\TableDeletedEvent;
use OCA\Tables\Service\Support\AuditLogServiceInterface;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;

final class WhenTableDeletedAuditLogListener implements IEventListener
{
public function __construct(protected AuditLogServiceInterface $auditLogService)
{
}

public function handle(Event $event): void
{
if (!($event instanceof TableDeletedEvent)) {
return;
}

$table = $event->getTable();
$userId = $event->getUserId();

$this->auditLogService->log("Table with ID: $table->id was deleted by user with ID: $userId", [
'table' => $table->jsonSerialize(),
'userId' => $userId,
]);
}
}
34 changes: 34 additions & 0 deletions lib/Listener/WhenTableTransferredAuditLogListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Listener;

use OCA\Tables\Event\TableOwnershipTransferredEvent;
use OCA\Tables\Service\Support\AuditLogServiceInterface;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;

final class WhenTableTransferredAuditLogListener implements IEventListener
{
public function __construct(protected AuditLogServiceInterface $auditLogService)
{
}

public function handle(Event $event): void
{
if (!($event instanceof TableOwnershipTransferredEvent)) {
return;
}

$table = $event->getTable();
$fromUserId = $event->getFromUserId();
$toUserId = $event->getToUserId();

$this->auditLogService->log("Table with ID: $table->id was transferred from user with ID: $fromUserId to user with ID: $toUserId", [
'table' => $table->jsonSerialize(),
'fromUserId' => $fromUserId,
'toUserId' => $toUserId,
]);
}
}
32 changes: 32 additions & 0 deletions lib/Listener/WhenViewDeletedAuditLogListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Listener;

use OCA\Tables\Event\ViewDeletedEvent;
use OCA\Tables\Service\Support\AuditLogServiceInterface;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;

final class WhenViewDeletedAuditLogListener implements IEventListener
{
public function __construct(protected AuditLogServiceInterface $auditLogService)
{
}

public function handle(Event $event): void
{
if (!($event instanceof ViewDeletedEvent)) {
return;
}

$view = $event->getView();
$userId = $event->getUserId();

$this->auditLogService->log("View with ID: $view->id was deleted by user with ID: $userId", [
'view' => $view->jsonSerialize(),
'userId' => $userId,
]);
}
}
29 changes: 26 additions & 3 deletions lib/Service/RowService.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
use OCA\Tables\Errors\InternalError;
use OCA\Tables\Errors\NotFoundError;
use OCA\Tables\Errors\PermissionError;
use OCA\Tables\Event\RowDeletedEvent;
use OCA\Tables\ResponseDefinitions;
use OCA\Tables\Service\ColumnTypes\IColumnTypeBusiness;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\DB\Exception;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Server;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
Expand All @@ -33,13 +35,25 @@ class RowService extends SuperService {
private Row2Mapper $row2Mapper;
private array $tmpRows = []; // holds already loaded rows as a small cache

public function __construct(PermissionsService $permissionsService, LoggerInterface $logger, ?string $userId,
ColumnMapper $columnMapper, ViewMapper $viewMapper, TableMapper $tableMapper, Row2Mapper $row2Mapper) {
protected IEventDispatcher $eventDispatcher;

public function __construct(
PermissionsService $permissionsService,
LoggerInterface $logger,
?string $userId,
ColumnMapper $columnMapper,
ViewMapper $viewMapper,
TableMapper $tableMapper,
Row2Mapper $row2Mapper,
IEventDispatcher $eventDispatcher
)
{
parent::__construct($logger, $userId, $permissionsService);
$this->columnMapper = $columnMapper;
$this->viewMapper = $viewMapper;
$this->tableMapper = $tableMapper;
$this->row2Mapper = $row2Mapper;
$this->eventDispatcher = $eventDispatcher;
}

/**
Expand Down Expand Up @@ -450,7 +464,16 @@ public function delete(int $id, ?int $viewId, string $userId): Row2 {
}

try {
return $this->filterRowResult($view ?? null, $this->row2Mapper->delete($item));
$deletedRow = $this->row2Mapper->delete($item);

$event = new RowDeletedEvent(
row: $item,
userId: $userId
);

$this->eventDispatcher->dispatchTyped($event);

return $this->filterRowResult($view ?? null, $deletedRow);
} catch (Exception $e) {
$this->logger->error($e->getMessage(), ['exception' => $e]);
throw new InternalError(get_class($this) . ' - ' . __FUNCTION__ . ': '.$e->getMessage());
Expand Down
10 changes: 10 additions & 0 deletions lib/Service/Support/AuditLogServiceInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Service\Support;

interface AuditLogServiceInterface
{
public function log(string $message, array $context): void;
}
22 changes: 22 additions & 0 deletions lib/Service/Support/DefaultAuditLogService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace OCA\Tables\Service\Support;

use OCP\EventDispatcher\IEventDispatcher;
use OCP\Log\Audit\CriticalActionPerformedEvent;

final class DefaultAuditLogService implements AuditLogServiceInterface
{
public function __construct(private IEventDispatcher $eventDispatcher)
{
}

public function log(string $message, array $context): void
{
$auditEvent = new CriticalActionPerformedEvent($message, $context);

$this->eventDispatcher->dispatchTyped($auditEvent);
}
}
Loading

0 comments on commit 7eca1c1

Please sign in to comment.