TotpCompatibilityTest.php

main 66 lines · 1.9 KB Raw
Alex Alex Commit Initial commit 01/10/2026 09:20
1<?php
2
3declare(strict_types=1);
4
5namespace ZnoteX\Tests\Security;
6
7use PHPUnit\Framework\TestCase;
8
9require_once dirname(__DIR__, 2) . '/engine/function/rfc6238.php';
10
11final class TotpCompatibilityTest extends TestCase
12{
13 public function testBase32DecodesRfc4648Vectors(): void
14 {
15 $vectors = [
16 'MY======' => 'f',
17 'MZXQ====' => 'fo',
18 'MZXW6===' => 'foo',
19 'MZXW6YQ=' => 'foob',
20 'MZXW6YTB' => 'fooba',
21 'MZXW6YTBOI======' => 'foobar',
22 ];
23
24 foreach ($vectors as $encoded => $plain) {
25 $this->assertSame($plain, \Base32Static::decode($encoded));
26 }
27 }
28
29 public function testTwentyCharacterUnpaddedAuthenticatorSecretRoundTrips(): void
30 {
31 $plain = 'Hello World!';
32 $secret = \Base32Static::encode($plain, false);
33
34 $this->assertSame(20, strlen($secret));
35 $this->assertSame($plain, \Base32Static::decode($secret));
36 }
37
38 public function testLowercaseUnpaddedSecretsAreAccepted(): void
39 {
40 $this->assertSame('Hello World!', \Base32Static::decode('jbswy3dpeblw64tmmqqq'));
41 }
42
43 public function testMalformedBase32IsRejected(): void
44 {
45 $this->assertFalse(\Base32Static::decode('INVALID-SECRET'));
46 $this->assertFalse(\Base32Static::decode('M=ZXW6==='));
47 }
48
49 public function testAuthenticatorUriDeclaresPortableTotpParameters(): void
50 {
51 $url = \TokenAuth6238::getBarCodeUrl('account', 'localhost', 'JBSWY3DPEHPK3PXP', 'ZnoteX');
52 parse_str((string)parse_url($url, PHP_URL_QUERY), $qrQuery);
53 $this->assertArrayHasKey('data', $qrQuery);
54
55 $otpauth = (string)$qrQuery['data'];
56 $this->assertStringStartsWith('otpauth://totp/account%40localhost?', $otpauth);
57 parse_str((string)parse_url($otpauth, PHP_URL_QUERY), $totpQuery);
58
59 $this->assertSame('JBSWY3DPEHPK3PXP', $totpQuery['secret'] ?? null);
60 $this->assertSame('ZnoteX', $totpQuery['issuer'] ?? null);
61 $this->assertSame('SHA1', $totpQuery['algorithm'] ?? null);
62 $this->assertSame('6', $totpQuery['digits'] ?? null);
63 $this->assertSame('30', $totpQuery['period'] ?? null);
64 }
65}
66
Top