Quelltext des aktuellen Standes
<?php
declare(strict_types=1);
use OpenNIT\Vault\TotpGenerator;
/**
* Hält fest, was die Erweiterungs-Schnittstelle beim Schreiben zusichert:
* Team-Einträge lassen sich mit dem Token bearbeiten, die Liste nennt das
* Schreibrecht je Eintrag, und ein eingegebenes 2FA-Secret wird in eine
* eindeutige Ablageform gebracht oder klar abgewiesen.
*/
return static function (): void {
$wurzel = dirname(__DIR__);
$quelle = (string)file_get_contents($wurzel . '/src/Controllers/VaultApiController.php');
// ----------------------------------------------------------------
// Schreibzugriff auf Team-Einträge ohne Web-Sitzung
// ----------------------------------------------------------------
test('Der Team-Schlüssel für Schreibzugriffe stammt aus dem Token, nicht aus der Web-Sitzung', function () use ($quelle) {
// Bearer-Aufrufe der Erweiterung führen keine Web-Sitzung; ein Team-
// Schlüssel aus der Sitzung wäre dort immer leer und jeder Team-Eintrag
// fälschlich schreibgeschützt.
assertSame(0, preg_match_all('/getTeamVaultKey\(/', $quelle));
assertTrue(str_contains($quelle, 'decryptTeamVaultKeys($userId, $vmk)[$teamId]'));
});
test('Die Eintragsliste nennt das Schreibrecht je Eintrag', function () use ($quelle) {
// Persönliche Einträge, Team-Einträge und die Zielliste nennen es.
assertTrue(preg_match_all("/'can_write'\s*=>/", $quelle) >= 3);
});
test('Das Ablaufdatum übersteht ein Bearbeiten aus der Erweiterung', function () use ($quelle) {
assertTrue(str_contains($quelle, "'expires_at' => \$expiresAt"));
});
// ----------------------------------------------------------------
// 2FA-Secret aus der Erweiterung
// ----------------------------------------------------------------
test('Ein Base32-Secret wird bereinigt und in Großbuchstaben abgelegt', function () {
assertSame('JBSWY3DPEHPK3PXP', TotpGenerator::normalizeSecret('jbsw y3dp-ehpk 3pxp'));
assertSame('JBSWY3DPEHPK3PXP', TotpGenerator::normalizeSecret(" JBSWY3DPEHPK3PXP====\n"));
});
test('Ein otpauth-Link liefert sein Secret', function () {
$link = 'otpauth://totp/OpenNIT:max%40example.org?secret=jbswy3dpehpk3pxp&issuer=OpenNIT&period=30&digits=6&algorithm=SHA1';
assertSame('JBSWY3DPEHPK3PXP', TotpGenerator::normalizeSecret($link));
assertSame('JBSWY3DPEHPK3PXP', TotpGenerator::normalizeSecret('OTPAUTH://totp/Dienst?secret=JBSWY3DPEHPK3PXP'));
});
test('Leere Eingabe bleibt leer', function () {
assertSame('', TotpGenerator::normalizeSecret(''));
assertSame('', TotpGenerator::normalizeSecret(" \t"));
});
test('Unbrauchbare Eingaben werden abgewiesen', function () {
// Zeichen außerhalb des Base32-Alphabets (0, 1, 8, 9, Umlaute)
assertSame(null, TotpGenerator::normalizeSecret('JBSWY3DP0189'));
assertSame(null, TotpGenerator::normalizeSecret('geheimß'));
// otpauth ohne Secret, für HOTP oder mit Parametern, die der Generator nicht rechnet
assertSame(null, TotpGenerator::normalizeSecret('otpauth://totp/Dienst?issuer=X'));
assertSame(null, TotpGenerator::normalizeSecret('otpauth://hotp/Dienst?secret=JBSWY3DPEHPK3PXP'));
assertSame(null, TotpGenerator::normalizeSecret('otpauth://totp/Dienst?secret=JBSWY3DPEHPK3PXP&algorithm=SHA256'));
assertSame(null, TotpGenerator::normalizeSecret('otpauth://totp/Dienst?secret=JBSWY3DPEHPK3PXP&digits=8'));
assertSame(null, TotpGenerator::normalizeSecret('otpauth://totp/Dienst?secret=JBSWY3DPEHPK3PXP&period=60'));
});
test('Das bereinigte Secret erzeugt denselben Code wie die Rohform', function () {
assertSame(
TotpGenerator::generate('JBSWY3DPEHPK3PXP'),
TotpGenerator::generate((string)TotpGenerator::normalizeSecret('jbsw y3dp ehpk 3pxp'))
);
});
};