Review fixes: the derived key is wiped also when a key is damaged, each tidy-up step after a removal on its own
CI / unit (8.2) (push) Has been cancelled
CI / unit (8.3) (push) Has been cancelled
CI / unit (8.4) (push) Has been cancelled
CI / psalm (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / integration (mariadb, 32) (push) Has been cancelled
CI / integration (mariadb, 33) (push) Has been cancelled
CI / integration (mariadb, 34) (push) Has been cancelled
CI / integration (mariadb, 35) (push) Has been cancelled
CI / integration (pgsql, 32) (push) Has been cancelled
CI / integration (pgsql, 33) (push) Has been cancelled
CI / integration (pgsql, 34) (push) Has been cancelled
CI / integration (pgsql, 35) (push) Has been cancelled
CI / integration (sqlite, 32) (push) Has been cancelled
CI / integration (sqlite, 33) (push) Has been cancelled
CI / integration (sqlite, 34) (push) Has been cancelled
CI / integration (sqlite, 35) (push) Has been cancelled
CI / integration-targets (push) Has been cancelled
CI / integration-user (32) (push) Has been cancelled
CI / integration-user (33) (push) Has been cancelled
CI / integration-user (34) (push) Has been cancelled
CI / integration-user (35) (push) Has been cancelled
CI / integration-full-restore (push) Has been cancelled

- The key derived from the passphrase is wiped on every path, also when the key or nonce turns out damaged
- After a removal the pending flag and the cached index are tidied up independently; a failing log cannot stop the removal event
- Tests: a short salt or nonce gives the damaged-key error
This commit is contained in:
2026-11-09 02:33:50 +01:00
parent fb8e8d0694
commit 2a72acb70b
3 changed files with 39 additions and 8 deletions
+16 -5
View File
@@ -452,16 +452,27 @@ final class TargetService {
$this->mapper->delete($target);
// The location is gone now: tidying up must not fail the removal, or the caller would skip
// the removal event and a retry would no longer find the location
try {
$this->keys->setWrappedKeyPending($target->getId(), false);
// The cached index of its repository is only of use while a location points at it
$this->tidyUp($target, fn () => $this->keys->setWrappedKeyPending($target->getId(), false));
// The cached index of its repository is only of use while a location points at it
$this->tidyUp($target, function () use ($target): void {
$repositoryId = $target->getRepositoryId();
if ($repositoryId !== null && !array_filter($this->list(), fn (Target $t) => $t->getRepositoryId() === $repositoryId)) {
$this->indexCache->forget($repositoryId);
}
});
}
/** One tidy-up step after a removal: a failure is logged (if even that works) and never thrown. */
private function tidyUp(Target $target, callable $step): void {
try {
$step();
} catch (\Throwable $e) {
Server::get(\Psr\Log\LoggerInterface::class)->warning('NG Backup: location ' . $target->getName()
. ' removed, tidying up after it failed: ' . $e->getMessage(), ['exception' => $e]);
try {
Server::get(\Psr\Log\LoggerInterface::class)->warning('NG Backup: location ' . $target->getName()
. ' removed, tidying up after it failed: ' . $e->getMessage(), ['exception' => $e]);
} catch (\Throwable) {
// nothing left to tell it to
}
}
}