Files
nextcloud-ng_backup/tests/Unit/Crypto/KeyRingTest.php
T
dillard 9b03f98d0d M5: deletion delay with trash, passphrase slots, ransomware documentation
- 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
2026-10-02 03:01:44 +02:00

52 lines
1.9 KiB
PHP

<?php
declare(strict_types=1);
namespace OCA\NgBackup\Tests\Unit\Crypto;
use OCA\NgBackup\Crypto\CryptoException;
use OCA\NgBackup\Crypto\KeyRing;
use PHPUnit\Framework\TestCase;
class KeyRingTest extends TestCase {
public function testWrapUnwrapKeepsKeys(): void {
$keys = KeyRing::generate();
$restored = KeyRing::unwrap($keys->wrap('pass phrase'), 'pass phrase');
$this->assertSame($keys->blobId('data'), $restored->blobId('data'));
$this->assertSame($keys->dataKey(), $restored->dataKey());
}
public function testWrongPassphrase(): void {
$wrapped = KeyRing::generate()->wrap('right');
$this->expectException(CryptoException::class);
KeyRing::unwrap($wrapped, 'wrong');
}
public function testBlobIdsAreKeyed(): void {
$this->assertNotSame(KeyRing::generate()->blobId('same'), KeyRing::generate()->blobId('same'));
$k = KeyRing::generate();
$this->assertSame($k->blobId('same'), $k->blobId('same'));
$this->assertMatchesRegularExpression('/^[0-9a-f]{64}$/', $k->blobId('x'));
}
public function testRejectsShortMasterKey(): void {
$this->expectException(\InvalidArgumentException::class);
new KeyRing('short');
}
public function testAnySlotOpensTheSameKey(): void {
$keys = KeyRing::generate();
$field = ['slots' => [
['slot' => 1, 'label' => 'Safe', 'key' => $keys->wrap('passphrase in the safe')],
['slot' => 2, 'label' => 'CTO', 'key' => $keys->wrap('passphrase of the cto')],
['slot' => 3, 'label' => 'Head of IT', 'key' => $keys->wrap('passphrase head of it')],
]];
foreach (['passphrase in the safe', 'passphrase of the cto', 'passphrase head of it'] as $p) {
$this->assertSame($keys->blobId('x'), KeyRing::unwrapAny($field, $p)->blobId('x'));
}
$this->assertSame($keys->blobId('x'), KeyRing::unwrapAny($keys->wrap('legacy single'), 'legacy single')->blobId('x'));
$this->expectException(CryptoException::class);
KeyRing::unwrapAny($field, 'nobody knows this');
}
}