From 1db877ac79af7b16ccd5f4f3fb6c285534e24a31 Mon Sep 17 00:00:00 2001 From: RobThree Date: Fri, 20 Mar 2015 13:07:52 +0100 Subject: [PATCH] * Added unittests + travis-ci yml --- .travis.yml | 9 ++ TwoFactorAuth.phpproj | 3 + tests/TwoFactorAuthTest.php | 180 ++++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 .travis.yml create mode 100644 tests/TwoFactorAuthTest.php diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..657ca2b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: php + +php: + - 5.3 + - 5.4 + - 5.5 + - 5.6 + +script: phpunit tests diff --git a/TwoFactorAuth.phpproj b/TwoFactorAuth.phpproj index b91193c..c17df88 100644 --- a/TwoFactorAuth.phpproj +++ b/TwoFactorAuth.phpproj @@ -39,6 +39,7 @@ + @@ -46,8 +47,10 @@ + + diff --git a/tests/TwoFactorAuthTest.php b/tests/TwoFactorAuthTest.php new file mode 100644 index 0000000..36d409e --- /dev/null +++ b/tests/TwoFactorAuthTest.php @@ -0,0 +1,180 @@ +assertEquals('543160', $tfa->getCode('VMR466AB62ZBOKHE', 1426847216)); + $this->assertEquals('538532', $tfa->getCode('VMR466AB62ZBOKHE', 0)); + } + + /** + * @expectedException \RobThree\Auth\TwoFactorAuthException + */ + public function testCreateSecretThrowsOnInsecureRNGProvider() { + $rng = new TestRNGProvider(); + + $tfa = new \RobThree\Auth\TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng); + $tfa->createSecret(); + } + + public function testCreateSecretOverrideSecureDoesNotThrowOnInsecureRNG() { + $rng = new TestRNGProvider(); + + $tfa = new \RobThree\Auth\TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng); + $this->assertEquals('ABCDEFGHIJKLMNOP', $tfa->createSecret(80, false)); + } + + public function testCreateSecretDoesNotThrowOnSecureRNGProvider() { + $rng = new TestRNGProvider(true); + + $tfa = new \RobThree\Auth\TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng); + $this->assertEquals('ABCDEFGHIJKLMNOP', $tfa->createSecret()); + } + + public function testCreateSecretGeneratesDesiredAmountOfEntropy() { + $rng = new TestRNGProvider(true); + + $tfa = new \RobThree\Auth\TwoFactorAuth('Test', 6, 30, 'sha1', null, $rng); + $this->assertEquals('A', $tfa->createSecret(5)); + $this->assertEquals('AB', $tfa->createSecret(6)); + $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ', $tfa->createSecret(128)); + $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', $tfa->createSecret(160)); + $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', $tfa->createSecret(320)); + $this->assertEquals('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFGHIJKLMNOPQRSTUVWXYZ234567A', $tfa->createSecret(321)); + } + + + public function testVerifyCodeWorksCorrectly() { + + $tfa = new \RobThree\Auth\TwoFactorAuth('Test', 6, 30); + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847190)); + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 + 29)); //Test discrepancy + $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 + 30)); //Test discrepancy + $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 0, 1426847190 - 1)); //Test discrepancy + + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 0)); //Test discrepancy + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 35)); //Test discrepancy + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 - 35)); //Test discrepancy + + $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 + 65)); //Test discrepancy + $this->assertEquals(false, $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 1, 1426847205 - 65)); //Test discrepancy + + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 + 65)); //Test discrepancy + $this->assertEquals(true , $tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 - 65)); //Test discrepancy + } + + public function testTotpUriIsCorrect() { + $qr = new TestQrProvider(); + + $tfa = new \RobThree\Auth\TwoFactorAuth('Test&Issuer', 6, 30, 'sha1', $qr); + $data = $this->DecodeDataUri($tfa->getQRCodeImageAsDataUri('Test&Label', 'VMR466AB62ZBOKHE')); + $this->assertEquals('test/test', $data['mimetype']); + $this->assertEquals('base64', $data['encoding']); + $this->assertEquals('otpauth://totp/Test%26Label?secret=VMR466AB62ZBOKHE&issuer=Test%26Issuer&period=30&algorithm=SHA1&digits=6@200', $data['data']); + } + + /** + * @expectedException \RobThree\Auth\TwoFactorAuthException + */ + public function testGetQRCodeImageAsDataUriThrowsOnInvalidSize() { + $qr = new TestQrProvider(); + + $tfa = new \RobThree\Auth\TwoFactorAuth('Test', 6, 30, 'sha1', $qr); + $tfa->getQRCodeImageAsDataUri('Test', 'VMR466AB62ZBOKHE', 0); + } + + private function DecodeDataUri($datauri) { + if (preg_match('/data:(?P[\w\.\-\/]+);(?P\w+),(?P.*)/', $datauri, $m) === 1) { + return array( + 'mimetype' => $m['mimetype'], + 'encoding' => $m['encoding'], + 'data' => base64_decode($m['data']) + ); + } + return null; + } +} + +class TestRNGProvider implements \RobThree\Auth\Providers\Rng\IRNGProvider { + private $isSecure; + + function __construct($isSecure = false) { + $this->isSecure = $isSecure; + } + + public function getRandomBytes($bytecount) { + $result = ''; + for ($i=0; $i<$bytecount; $i++) + $result.=chr($i); + return $result; + + } + + public function isCryptographicallySecure() { + return $this->isSecure; + } +} + +class TestQrProvider implements \RobThree\Auth\Providers\Qr\IQRCodeProvider { + public function getQRCodeImage($qrtext, $size) { + return $qrtext . '@' . $size; + } + + public function getMimeType() { + return 'test/test'; + } +} \ No newline at end of file