f75ed3aed6
Every change to the set of snapshots or trash entries writes an encrypted catalog generation bound to the repository and its position, with the hash of the previous generation. The server anchors the newest generation it has seen in its app config; on open, the location must show at least that generation and chain back to it, and every snapshot listed must exist. A rolled-back or tampered location is refused (the run fails and administrators are notified). Opening with the passphrase on a new server accepts the newest valid chain. occ backup:target:trust-current accepts a legitimately older state (e.g. restored from the provider's snapshot) after typing the location name; audited and announced to all administrators. Tests: chain advances, rollback, hidden snapshot, swapped generation, disaster recovery without anchor. Tested on NC34 by deleting the newest catalog generation on the SFTP location.
35 lines
1.2 KiB
PHP
35 lines
1.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
// SPDX-FileCopyrightText: 2026 Dillard Blom
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
namespace OCA\NgBackup\Db;
|
|
|
|
use OCA\NgBackup\AppInfo\Application;
|
|
use OCA\NgBackup\Repository\ICatalogAnchor;
|
|
use OCP\IAppConfig;
|
|
|
|
/** Keeps the newest catalog generation seen per repository in the app config (outside the location). */
|
|
class AppConfigCatalogAnchor implements ICatalogAnchor {
|
|
public function __construct(
|
|
private IAppConfig $appConfig,
|
|
) {
|
|
}
|
|
|
|
public function get(string $repositoryId): ?array {
|
|
$raw = $this->appConfig->getValueString(Application::APP_ID, $this->key($repositoryId), '', true);
|
|
$data = $raw === '' ? null : json_decode($raw, true);
|
|
return is_array($data) && isset($data['gen'], $data['hash']) ? ['gen' => (int)$data['gen'], 'hash' => (string)$data['hash']] : null;
|
|
}
|
|
|
|
public function set(string $repositoryId, int $gen, string $hash): void {
|
|
$this->appConfig->setValueString(Application::APP_ID, $this->key($repositoryId), json_encode(['gen' => $gen, 'hash' => $hash]), true);
|
|
}
|
|
|
|
private function key(string $repositoryId): string {
|
|
return 'catalog_' . preg_replace('/[^a-f0-9]/', '', $repositoryId);
|
|
}
|
|
}
|