075f2fac6f
- removed snapshots go to a trash on the location and their data is only freed after the deletion delay, which is chosen when the key is created (default 7 days, 1-365) and cannot be changed afterwards; any admin can bring them back (occ backup:trash, backup:trash:restore, web UI) - up to three passphrase slots open the same master key (like LUKS), so one person leaving or dying does not lock the company out; slot changes are written to every location, announced to all admins and require a new recovery kit confirmation, while backups keep running - occ backup:key:slots, backup:key:slot:add|replace|remove; key init takes --label and --delete-delay-days - web UI: deletion delay and first slot at key creation, slot management, trash per location with restore; all behind password confirmation - README: key, slots (safe / CTO / head of IT), and protection against ransomware: object lock in compliance mode (e.g. 90 days), credentials without delete rights, provider snapshots, off-site copy
73 lines
3.3 KiB
PHP
73 lines
3.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
// SPDX-FileCopyrightText: 2026 Dillard Blom
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
namespace OCA\NgBackup\Notification;
|
|
|
|
use OCA\NgBackup\AppInfo\Application;
|
|
use OCP\IURLGenerator;
|
|
use OCP\L10N\IFactory;
|
|
use OCP\Notification\INotification;
|
|
use OCP\Notification\INotifier;
|
|
use OCP\Notification\UnknownNotificationException;
|
|
|
|
class Notifier implements INotifier {
|
|
public function __construct(
|
|
private IFactory $l10n,
|
|
private IURLGenerator $url,
|
|
) {
|
|
}
|
|
|
|
public function getID(): string {
|
|
return Application::APP_ID;
|
|
}
|
|
|
|
public function getName(): string {
|
|
return $this->l10n->get(Application::APP_ID)->t('NG Backup');
|
|
}
|
|
|
|
public function prepare(INotification $notification, string $languageCode): INotification {
|
|
if ($notification->getApp() !== Application::APP_ID) {
|
|
throw new UnknownNotificationException();
|
|
}
|
|
$l = $this->l10n->get(Application::APP_ID, $languageCode);
|
|
$p = $notification->getSubjectParameters();
|
|
switch ($notification->getSubject()) {
|
|
case 'run_failed':
|
|
$notification->setParsedSubject($p['kind'] === 'restore'
|
|
? $l->t('Restore from %s failed', [$p['target']])
|
|
: $l->t('Backup to %s failed', [$p['target']]));
|
|
$notification->setParsedMessage((string)($p['error'] ?? ''));
|
|
break;
|
|
case 'backup_stale':
|
|
$notification->setParsedSubject($l->t('No successful backup to %1$s since %2$s', [$p['target'], $p['since']]));
|
|
$notification->setParsedMessage($l->t('Check the backup settings and the server log.'));
|
|
break;
|
|
case 'security_event':
|
|
$who = (string)($p['actor'] ?? '');
|
|
$notification->setParsedSubject(match ($p['event'] ?? '') {
|
|
'kit_downloaded' => $l->t('%s downloaded the backup recovery kit', [$who]),
|
|
'target_removed' => $l->t('%1$s removed backup location %2$s', [$who, $p['target'] ?? '']),
|
|
'append_only_off' => $l->t('%1$s turned off append-only for backup location %2$s', [$who, $p['target'] ?? '']),
|
|
'retention_changed' => $l->t('%1$s changed the backup retention to %2$s', [$who, $p['policy'] ?? '']),
|
|
'snapshots_forgotten' => $l->t('%1$s moved %2$s snapshots of %3$s to the trash; they are deleted permanently after %4$s unless restored', [$who, $p['count'] ?? '', $p['target'] ?? '', $p['until'] ?? '']),
|
|
'snapshot_untrashed' => $l->t('%1$s restored snapshot %2$s of %3$s from the trash', [$who, $p['snapshot'] ?? '', $p['target'] ?? '']),
|
|
'slot_added' => $l->t('%1$s added backup passphrase slot %2$s (%3$s); download and confirm the new recovery kit', [$who, $p['slot'] ?? '', $p['label'] ?? '']),
|
|
'slot_replaced' => $l->t('%1$s set a new passphrase for backup key slot %2$s (%3$s); download and confirm the new recovery kit', [$who, $p['slot'] ?? '', $p['label'] ?? '']),
|
|
'slot_removed' => $l->t('%1$s removed backup passphrase slot %2$s; download and confirm the new recovery kit', [$who, $p['slot'] ?? '']),
|
|
default => $l->t('NG Backup security event'),
|
|
});
|
|
$notification->setParsedMessage($l->t('If this was not you or another administrator, check who has admin access.'));
|
|
break;
|
|
default:
|
|
throw new UnknownNotificationException();
|
|
}
|
|
$notification->setLink($this->url->linkToRouteAbsolute('settings.AdminSettings.index', ['section' => 'ng_backup']));
|
|
$notification->setIcon($this->url->getAbsoluteURL($this->url->imagePath(Application::APP_ID, 'app-dark.svg')));
|
|
return $notification;
|
|
}
|
|
}
|