From 0798faa7f189312bad6bb766eb872e71dd6dae7a Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 21 Feb 2017 20:03:48 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=8C=20=D1=83=D0=BA=D0=B0=D0=B7=D1=8B=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=B4=D0=BB=D0=B8=D0=BD=D1=83=20=D0=B3=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D1=80=D0=B8=D1=80=D1=83=D0=B5=D0=BC=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20otp=5Fsecret?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/models/profile/TwoFactorAuthForm.php | 13 ++++++++++-- .../models/profile/TwoFactorAuthFormTest.php | 21 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/api/models/profile/TwoFactorAuthForm.php b/api/models/profile/TwoFactorAuthForm.php index 907e686..02c1734 100644 --- a/api/models/profile/TwoFactorAuthForm.php +++ b/api/models/profile/TwoFactorAuthForm.php @@ -128,8 +128,17 @@ class TwoFactorAuthForm extends ApiForm { return $writer->writeString($content, Encoder::DEFAULT_BYTE_MODE_ECODING, ErrorCorrectionLevel::H); } - protected function setOtpSecret(): void { - $this->account->otp_secret = trim(Base32::encode(random_bytes(32)), '='); + /** + * otp_secret кодируется в Base32, т.к. после кодирования в результурющей строке нет символов, + * которые можно перепутать (1 и l, O и 0, и т.д.). Отрицательной стороной является то, что итоговая + * строка составляет 160% от исходной. Поэтому, генерируя исходный приватный ключ, мы должны обеспечить + * ему такую длину, чтобы 160% его длины было равно запрошенному значению + * + * @throws ErrorException + */ + protected function setOtpSecret(int $length = 24): void { + $randomBytesLength = ceil($length / 1.6); + $this->account->otp_secret = substr(trim(Base32::encode(random_bytes($randomBytesLength)), '='), 0, $length); if (!$this->account->save()) { throw new ErrorException('Cannot set account otp_secret'); } diff --git a/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php b/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php index a160805..5bb61d4 100644 --- a/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php +++ b/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php @@ -6,8 +6,10 @@ use common\helpers\Error as E; use common\models\Account; use OTPHP\TOTP; use tests\codeception\api\unit\TestCase; +use tests\codeception\common\_support\ProtectedCaller; class TwoFactorAuthFormTest extends TestCase { + use ProtectedCaller; public function testGetCredentials() { /** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */ @@ -162,4 +164,23 @@ class TwoFactorAuthFormTest extends TestCase { $this->assertEquals('Ely.by', $totp->getIssuer()); } + public function testSetOtpSecret() { + /** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */ + $account = $this->getMockBuilder(Account::class) + ->setMethods(['save']) + ->getMock(); + + $account->expects($this->exactly(2)) + ->method('save') + ->willReturn(true); + + $model = new TwoFactorAuthForm($account); + $this->callProtected($model, 'setOtpSecret'); + $this->assertEquals(24, strlen($model->getAccount()->otp_secret)); + + $model = new TwoFactorAuthForm($account); + $this->callProtected($model, 'setOtpSecret', 25); + $this->assertEquals(25, strlen($model->getAccount()->otp_secret)); + } + }