mirror of
https://github.com/elyby/accounts.git
synced 2025-05-31 14:11:46 +05:30
Merge branch 'develop'
This commit is contained in:
@@ -40,7 +40,7 @@ test:backend:
|
|||||||
php vendor/bin/codecept run -c tests
|
php vendor/bin/codecept run -c tests
|
||||||
|
|
||||||
test:frontend:
|
test:frontend:
|
||||||
image: node:5.12
|
image: node:8.2.1
|
||||||
stage: test
|
stage: test
|
||||||
cache:
|
cache:
|
||||||
paths:
|
paths:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM registry.ely.by/elyby/accounts-php:1.3.0
|
FROM registry.ely.by/elyby/accounts-php:1.4.0
|
||||||
|
|
||||||
# Вносим конфигурации для крона и воркеров
|
# Вносим конфигурации для крона и воркеров
|
||||||
COPY docker/cron/* /etc/cron.d/
|
COPY docker/cron/* /etc/cron.d/
|
||||||
@@ -46,7 +46,7 @@ RUN mkdir -p api/runtime api/web/assets console/runtime \
|
|||||||
# Билдим фронт
|
# Билдим фронт
|
||||||
&& cd frontend \
|
&& cd frontend \
|
||||||
&& ln -s /var/www/frontend/node_modules $PWD/node_modules \
|
&& ln -s /var/www/frontend/node_modules $PWD/node_modules \
|
||||||
&& npm run build:quite --quiet \
|
&& npm run build:quiet \
|
||||||
&& rm node_modules \
|
&& rm node_modules \
|
||||||
# Копируем билд наружу, чтобы его не затёрло volume в dev режиме
|
# Копируем билд наружу, чтобы его не затёрло volume в dev режиме
|
||||||
&& cp -r ./dist /var/www/dist \
|
&& cp -r ./dist /var/www/dist \
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM registry.ely.by/elyby/accounts-php:1.3.0-dev
|
FROM registry.ely.by/elyby/accounts-php:1.4.0-dev
|
||||||
|
|
||||||
# Вносим конфигурации для крона и воркеров
|
# Вносим конфигурации для крона и воркеров
|
||||||
COPY docker/cron/* /etc/cron.d/
|
COPY docker/cron/* /etc/cron.d/
|
||||||
@@ -43,7 +43,7 @@ RUN mkdir -p api/runtime api/web/assets console/runtime \
|
|||||||
# Билдим фронт
|
# Билдим фронт
|
||||||
&& cd frontend \
|
&& cd frontend \
|
||||||
&& ln -s /var/www/frontend/node_modules $PWD/node_modules \
|
&& ln -s /var/www/frontend/node_modules $PWD/node_modules \
|
||||||
&& npm run build:quite --quiet \
|
&& npm run build:quiet \
|
||||||
&& rm node_modules \
|
&& rm node_modules \
|
||||||
# Копируем билд наружу, чтобы его не затёрло volume в dev режиме
|
# Копируем билд наружу, чтобы его не затёрло volume в dev режиме
|
||||||
&& cp -r ./dist /var/www/dist \
|
&& cp -r ./dist /var/www/dist \
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ class AccessTokenStorage extends AbstractStorage implements AccessTokenInterface
|
|||||||
|
|
||||||
public function get($token) {
|
public function get($token) {
|
||||||
$result = Json::decode((new Key($this->dataTable, $token))->getValue());
|
$result = Json::decode((new Key($this->dataTable, $token))->getValue());
|
||||||
|
if ($result === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
$token = new AccessTokenEntity($this->server);
|
$token = new AccessTokenEntity($this->server);
|
||||||
$token->setId($result['id']);
|
$token->setId($result['id']);
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ use BaconQrCode\Encoder\Encoder;
|
|||||||
use BaconQrCode\Renderer\Color\Rgb;
|
use BaconQrCode\Renderer\Color\Rgb;
|
||||||
use BaconQrCode\Renderer\Image\Svg;
|
use BaconQrCode\Renderer\Image\Svg;
|
||||||
use BaconQrCode\Writer;
|
use BaconQrCode\Writer;
|
||||||
use Base32\Base32;
|
|
||||||
use common\components\Qr\ElyDecorator;
|
use common\components\Qr\ElyDecorator;
|
||||||
use common\helpers\Error as E;
|
use common\helpers\Error as E;
|
||||||
use common\models\Account;
|
use common\models\Account;
|
||||||
use OTPHP\TOTP;
|
use OTPHP\TOTP;
|
||||||
|
use ParagonIE\ConstantTime\Encoding;
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\base\ErrorException;
|
use yii\base\ErrorException;
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ class TwoFactorAuthForm extends ApiForm {
|
|||||||
parent::__construct($config);
|
parent::__construct($config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rules() {
|
public function rules(): array {
|
||||||
$bothScenarios = [self::SCENARIO_ACTIVATE, self::SCENARIO_DISABLE];
|
$bothScenarios = [self::SCENARIO_ACTIVATE, self::SCENARIO_DISABLE];
|
||||||
return [
|
return [
|
||||||
['timestamp', 'integer', 'on' => [self::SCENARIO_ACTIVATE]],
|
['timestamp', 'integer', 'on' => [self::SCENARIO_ACTIVATE]],
|
||||||
@@ -63,7 +63,7 @@ class TwoFactorAuthForm extends ApiForm {
|
|||||||
$provisioningUri = $this->getTotp()->getProvisioningUri();
|
$provisioningUri = $this->getTotp()->getProvisioningUri();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'qr' => base64_encode($this->drawQrCode($provisioningUri)),
|
'qr' => 'data:image/svg+xml,' . trim($this->drawQrCode($provisioningUri)),
|
||||||
'uri' => $provisioningUri,
|
'uri' => $provisioningUri,
|
||||||
'secret' => $this->account->otp_secret,
|
'secret' => $this->account->otp_secret,
|
||||||
];
|
];
|
||||||
@@ -124,18 +124,19 @@ class TwoFactorAuthForm extends ApiForm {
|
|||||||
* @return TOTP
|
* @return TOTP
|
||||||
*/
|
*/
|
||||||
public function getTotp(): TOTP {
|
public function getTotp(): TOTP {
|
||||||
$totp = new TOTP($this->account->email, $this->account->otp_secret);
|
$totp = TOTP::create($this->account->otp_secret);
|
||||||
|
$totp->setLabel($this->account->email);
|
||||||
$totp->setIssuer('Ely.by');
|
$totp->setIssuer('Ely.by');
|
||||||
|
|
||||||
return $totp;
|
return $totp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function drawQrCode(string $content): string {
|
public function drawQrCode(string $content): string {
|
||||||
|
$content = $this->forceMinimalQrContentLength($content);
|
||||||
|
|
||||||
$renderer = new Svg();
|
$renderer = new Svg();
|
||||||
$renderer->setHeight(256);
|
|
||||||
$renderer->setWidth(256);
|
|
||||||
$renderer->setForegroundColor(new Rgb(32, 126, 92));
|
|
||||||
$renderer->setMargin(0);
|
$renderer->setMargin(0);
|
||||||
|
$renderer->setForegroundColor(new Rgb(32, 126, 92));
|
||||||
$renderer->addDecorator(new ElyDecorator());
|
$renderer->addDecorator(new ElyDecorator());
|
||||||
|
|
||||||
$writer = new Writer($renderer);
|
$writer = new Writer($renderer);
|
||||||
@@ -154,10 +155,27 @@ class TwoFactorAuthForm extends ApiForm {
|
|||||||
*/
|
*/
|
||||||
protected function setOtpSecret(int $length = 24): void {
|
protected function setOtpSecret(int $length = 24): void {
|
||||||
$randomBytesLength = ceil($length / 1.6);
|
$randomBytesLength = ceil($length / 1.6);
|
||||||
$this->account->otp_secret = substr(trim(Base32::encode(random_bytes($randomBytesLength)), '='), 0, $length);
|
$randomBase32 = trim(Encoding::base32EncodeUpper(random_bytes($randomBytesLength)), '=');
|
||||||
|
$this->account->otp_secret = substr($randomBase32, 0, $length);
|
||||||
if (!$this->account->save()) {
|
if (!$this->account->save()) {
|
||||||
throw new ErrorException('Cannot set account otp_secret');
|
throw new ErrorException('Cannot set account otp_secret');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* В используемой либе для рендеринга QR кода нет возможности указать QR code version.
|
||||||
|
* http://www.qrcode.com/en/about/version.html
|
||||||
|
* По какой-то причине 7 и 8 версии не читаются вовсе, с логотипом или без.
|
||||||
|
* Поэтому нужно иначально привести строку к длинне 9 версии (91), добавляя к концу
|
||||||
|
* строки необходимое количество символов "#". Этот символ используется, т.к. нашим
|
||||||
|
* контентом является ссылка и чтобы не вводить лишние параметры мы помечаем добавочную
|
||||||
|
* часть как хеш часть и все программы для чтения QR кодов продолжают свою работу.
|
||||||
|
*
|
||||||
|
* @param string $content
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function forceMinimalQrContentLength(string $content): string {
|
||||||
|
return str_pad($content, 91, '#');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace api\validators;
|
|||||||
use common\helpers\Error as E;
|
use common\helpers\Error as E;
|
||||||
use common\models\Account;
|
use common\models\Account;
|
||||||
use OTPHP\TOTP;
|
use OTPHP\TOTP;
|
||||||
|
use RangeException;
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\base\InvalidConfigException;
|
use yii\base\InvalidConfigException;
|
||||||
use yii\validators\Validator;
|
use yii\validators\Validator;
|
||||||
@@ -48,8 +49,12 @@ class TotpValidator extends Validator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function validateValue($value) {
|
protected function validateValue($value) {
|
||||||
$totp = new TOTP(null, $this->account->otp_secret);
|
try {
|
||||||
if (!$totp->verify((string)$value, $this->getTimestamp(), $this->window)) {
|
$totp = TOTP::create($this->account->otp_secret);
|
||||||
|
if (!$totp->verify((string)$value, $this->getTimestamp(), $this->window)) {
|
||||||
|
return [E::OTP_TOKEN_INCORRECT, []];
|
||||||
|
}
|
||||||
|
} catch (RangeException $e) {
|
||||||
return [E::OTP_TOKEN_INCORRECT, []];
|
return [E::OTP_TOKEN_INCORRECT, []];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
return [
|
return [
|
||||||
'version' => '1.1.16',
|
'version' => '1.1.17',
|
||||||
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
|
'vendorPath' => dirname(dirname(__DIR__)) . '/vendor',
|
||||||
'components' => [
|
'components' => [
|
||||||
'cache' => [
|
'cache' => [
|
||||||
|
|||||||
@@ -1,21 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "yiisoft/yii2-app-advanced",
|
"name": "elyby/accounts",
|
||||||
"description": "Yii 2 Advanced Project Template",
|
"description": "Authentication service for Ely.by",
|
||||||
"keywords": ["yii2", "framework", "advanced", "project template"],
|
"homepage": "https://account.ely.by",
|
||||||
"homepage": "http://www.yiiframework.com/",
|
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/yiisoft/yii2/issues?state=open",
|
|
||||||
"forum": "http://www.yiiframework.com/forum/",
|
|
||||||
"wiki": "http://www.yiiframework.com/wiki/",
|
|
||||||
"irc": "irc://irc.freenode.net/yii",
|
|
||||||
"source": "https://github.com/yiisoft/yii2"
|
|
||||||
},
|
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.1",
|
"php": "^7.1",
|
||||||
"yiisoft/yii2": "2.0.11.2",
|
"yiisoft/yii2": "2.0.12",
|
||||||
"yiisoft/yii2-swiftmailer": "*",
|
"yiisoft/yii2-swiftmailer": "*",
|
||||||
"ramsey/uuid": "^3.5.0",
|
"ramsey/uuid": "^3.5.0",
|
||||||
"league/oauth2-server": "dev-improvements#fbaa9b0bd3d8050235ba7dde90f731764122bc20",
|
"league/oauth2-server": "dev-improvements#fbaa9b0bd3d8050235ba7dde90f731764122bc20",
|
||||||
@@ -29,8 +20,10 @@
|
|||||||
"predis/predis": "^1.0",
|
"predis/predis": "^1.0",
|
||||||
"mito/yii2-sentry": "^1.0",
|
"mito/yii2-sentry": "^1.0",
|
||||||
"minime/annotations": "~3.0",
|
"minime/annotations": "~3.0",
|
||||||
"spomky-labs/otphp": "8.3.1",
|
"spomky-labs/otphp": "^9.0.2",
|
||||||
"bacon/bacon-qr-code": "^1.0"
|
"bacon/bacon-qr-code": "^1.0",
|
||||||
|
"roave/security-advisories": "dev-master",
|
||||||
|
"paragonie/constant_time_encoding": "^2.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"yiisoft/yii2-codeception": "*",
|
"yiisoft/yii2-codeception": "*",
|
||||||
@@ -38,16 +31,13 @@
|
|||||||
"yiisoft/yii2-faker": "*",
|
"yiisoft/yii2-faker": "*",
|
||||||
"flow/jsonpath": "^0.3.1",
|
"flow/jsonpath": "^0.3.1",
|
||||||
"phpunit/phpunit": "^5.7",
|
"phpunit/phpunit": "^5.7",
|
||||||
"codeception/codeception": "~2.3",
|
"codeception/codeception": "2.3.4",
|
||||||
"codeception/specify": "*",
|
"codeception/specify": "*",
|
||||||
"codeception/verify": "*",
|
"codeception/verify": "*",
|
||||||
"phploc/phploc": "^3.0.1",
|
"phploc/phploc": "^3.0.1",
|
||||||
"mockery/mockery": "1.0.0-alpha1",
|
"mockery/mockery": "1.0.0-alpha1",
|
||||||
"php-mock/php-mock-mockery": "dev-mockery-1.0.0#03956ed4b34ae25bc20a0677500f4f4b416f976c"
|
"php-mock/php-mock-mockery": "dev-mockery-1.0.0#03956ed4b34ae25bc20a0677500f4f4b416f976c"
|
||||||
},
|
},
|
||||||
"config": {
|
|
||||||
"process-timeout": 1800
|
|
||||||
},
|
|
||||||
"repositories": [
|
"repositories": [
|
||||||
{
|
{
|
||||||
"type": "composer",
|
"type": "composer",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ modules:
|
|||||||
Yii2:
|
Yii2:
|
||||||
configFile: '../config/api/functional.php'
|
configFile: '../config/api/functional.php'
|
||||||
cleanup: true
|
cleanup: true
|
||||||
|
transaction: false
|
||||||
Redis:
|
Redis:
|
||||||
host: "%REDIS_HOST%"
|
host: "%REDIS_HOST%"
|
||||||
port: 6379
|
port: 6379
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class ForgotPasswordCest {
|
|||||||
|
|
||||||
public function testForgotPasswordByAccountWithOtp(FunctionalTester $I) {
|
public function testForgotPasswordByAccountWithOtp(FunctionalTester $I) {
|
||||||
$I->wantTo('create new password recover request by passing username and otp token');
|
$I->wantTo('create new password recover request by passing username and otp token');
|
||||||
$totp = new TOTP(null, 'secret-secret-secret');
|
$totp = TOTP::create('BBBB');
|
||||||
$this->route->forgotPassword('AccountWithEnabledOtp', $totp->now());
|
$this->route->forgotPassword('AccountWithEnabledOtp', $totp->now());
|
||||||
$this->assertSuccessResponse($I, true);
|
$this->assertSuccessResponse($I, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ class LoginCest {
|
|||||||
$route = new AuthenticationRoute($I);
|
$route = new AuthenticationRoute($I);
|
||||||
|
|
||||||
$I->wantTo('login into account with enabled otp');
|
$I->wantTo('login into account with enabled otp');
|
||||||
$route->login('AccountWithEnabledOtp', 'password_0', (new TOTP(null, 'secret-secret-secret'))->now());
|
$route->login('AccountWithEnabledOtp', 'password_0', (TOTP::create('BBBB'))->now());
|
||||||
$I->canSeeResponseContainsJson([
|
$I->canSeeResponseContainsJson([
|
||||||
'success' => true,
|
'success' => true,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class TwoFactorAuthDisableCest {
|
|||||||
|
|
||||||
public function testSuccessEnable(FunctionalTester $I) {
|
public function testSuccessEnable(FunctionalTester $I) {
|
||||||
$I->amAuthenticated('AccountWithEnabledOtp');
|
$I->amAuthenticated('AccountWithEnabledOtp');
|
||||||
$totp = new TOTP(null, 'secret-secret-secret');
|
$totp = TOTP::create('BBBB');
|
||||||
$this->route->disable($totp->now(), 'password_0');
|
$this->route->disable($totp->now(), 'password_0');
|
||||||
$I->canSeeResponseCodeIs(200);
|
$I->canSeeResponseCodeIs(200);
|
||||||
$I->canSeeResponseIsJson();
|
$I->canSeeResponseIsJson();
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class TwoFactorAuthEnableCest {
|
|||||||
|
|
||||||
public function testSuccessEnable(FunctionalTester $I) {
|
public function testSuccessEnable(FunctionalTester $I) {
|
||||||
$I->amAuthenticated('AccountWithOtpSecret');
|
$I->amAuthenticated('AccountWithOtpSecret');
|
||||||
$totp = new TOTP(null, 'some otp secret value');
|
$totp = TOTP::create('AAAA');
|
||||||
$this->route->enable($totp->now(), 'password_0');
|
$this->route->enable($totp->now(), 'password_0');
|
||||||
$I->canSeeResponseCodeIs(200);
|
$I->canSeeResponseCodeIs(200);
|
||||||
$I->canSeeResponseIsJson();
|
$I->canSeeResponseIsJson();
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ modules:
|
|||||||
Yii2:
|
Yii2:
|
||||||
configFile: '../config/api/unit.php'
|
configFile: '../config/api/unit.php'
|
||||||
cleanup: true
|
cleanup: true
|
||||||
|
transaction: false
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class ForgotPasswordFormTest extends TestCase {
|
|||||||
$model->validateTotpToken('token');
|
$model->validateTotpToken('token');
|
||||||
$this->assertEquals(['error.token_incorrect'], $model->getErrors('token'));
|
$this->assertEquals(['error.token_incorrect'], $model->getErrors('token'));
|
||||||
|
|
||||||
$totp = new TOTP(null, 'secret-secret-secret');
|
$totp = TOTP::create('BBBB');
|
||||||
$model = new ForgotPasswordForm();
|
$model = new ForgotPasswordForm();
|
||||||
$model->login = 'AccountWithEnabledOtp';
|
$model->login = 'AccountWithEnabledOtp';
|
||||||
$model->token = $totp->now();
|
$model->token = $totp->now();
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class LoginFormTest extends TestCase {
|
|||||||
$account = new AccountIdentity(['password' => '12345678']);
|
$account = new AccountIdentity(['password' => '12345678']);
|
||||||
$account->password = '12345678';
|
$account->password = '12345678';
|
||||||
$account->is_otp_enabled = true;
|
$account->is_otp_enabled = true;
|
||||||
$account->otp_secret = 'mock secret';
|
$account->otp_secret = 'AAAA';
|
||||||
|
|
||||||
$this->specify('error.token_incorrect if totp invalid', function() use ($account) {
|
$this->specify('error.token_incorrect if totp invalid', function() use ($account) {
|
||||||
$model = $this->createModel([
|
$model = $this->createModel([
|
||||||
@@ -88,7 +88,7 @@ class LoginFormTest extends TestCase {
|
|||||||
$this->assertEquals(['error.token_incorrect'], $model->getErrors('token'));
|
$this->assertEquals(['error.token_incorrect'], $model->getErrors('token'));
|
||||||
});
|
});
|
||||||
|
|
||||||
$totp = new TOTP(null, 'mock secret');
|
$totp = TOTP::create($account->otp_secret);
|
||||||
$this->specify('no errors if password valid', function() use ($account, $totp) {
|
$this->specify('no errors if password valid', function() use ($account, $totp) {
|
||||||
$model = $this->createModel([
|
$model = $this->createModel([
|
||||||
'password' => '12345678',
|
'password' => '12345678',
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ use common\models\UsernameHistory;
|
|||||||
use GuzzleHttp\ClientInterface;
|
use GuzzleHttp\ClientInterface;
|
||||||
use tests\codeception\api\unit\TestCase;
|
use tests\codeception\api\unit\TestCase;
|
||||||
use tests\codeception\common\fixtures\AccountFixture;
|
use tests\codeception\common\fixtures\AccountFixture;
|
||||||
|
use tests\codeception\common\fixtures\EmailActivationFixture;
|
||||||
|
use tests\codeception\common\fixtures\UsernameHistoryFixture;
|
||||||
use Yii;
|
use Yii;
|
||||||
use yii\web\Request;
|
use yii\web\Request;
|
||||||
use const common\LATEST_RULES_VERSION;
|
use const common\LATEST_RULES_VERSION;
|
||||||
@@ -30,6 +32,8 @@ class RegistrationFormTest extends TestCase {
|
|||||||
public function _fixtures() {
|
public function _fixtures() {
|
||||||
return [
|
return [
|
||||||
'accounts' => AccountFixture::class,
|
'accounts' => AccountFixture::class,
|
||||||
|
'emailActivations' => EmailActivationFixture::class,
|
||||||
|
'usernameHistory' => UsernameHistoryFixture::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class TwoFactorAuthFormTest extends TestCase {
|
|||||||
|
|
||||||
$model->expects($this->once())
|
$model->expects($this->once())
|
||||||
->method('drawQrCode')
|
->method('drawQrCode')
|
||||||
->willReturn('this is qr code, trust me');
|
->willReturn('<_/>');
|
||||||
|
|
||||||
$result = $model->getCredentials();
|
$result = $model->getCredentials();
|
||||||
$this->assertTrue(is_array($result));
|
$this->assertTrue(is_array($result));
|
||||||
@@ -44,7 +44,7 @@ class TwoFactorAuthFormTest extends TestCase {
|
|||||||
$this->assertArrayHasKey('secret', $result);
|
$this->assertArrayHasKey('secret', $result);
|
||||||
$this->assertNotNull($account->otp_secret);
|
$this->assertNotNull($account->otp_secret);
|
||||||
$this->assertEquals($account->otp_secret, $result['secret']);
|
$this->assertEquals($account->otp_secret, $result['secret']);
|
||||||
$this->assertEquals(base64_encode('this is qr code, trust me'), $result['qr']);
|
$this->assertEquals('data:image/svg+xml,<_/>', $result['qr']);
|
||||||
|
|
||||||
/** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
|
/** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
|
||||||
$account = $this->getMockBuilder(Account::class)
|
$account = $this->getMockBuilder(Account::class)
|
||||||
@@ -197,10 +197,12 @@ class TwoFactorAuthFormTest extends TestCase {
|
|||||||
$model = new TwoFactorAuthForm($account);
|
$model = new TwoFactorAuthForm($account);
|
||||||
$this->callProtected($model, 'setOtpSecret');
|
$this->callProtected($model, 'setOtpSecret');
|
||||||
$this->assertEquals(24, strlen($model->getAccount()->otp_secret));
|
$this->assertEquals(24, strlen($model->getAccount()->otp_secret));
|
||||||
|
$this->assertSame(strtoupper($model->getAccount()->otp_secret), $model->getAccount()->otp_secret);
|
||||||
|
|
||||||
$model = new TwoFactorAuthForm($account);
|
$model = new TwoFactorAuthForm($account);
|
||||||
$this->callProtected($model, 'setOtpSecret', 25);
|
$this->callProtected($model, 'setOtpSecret', 25);
|
||||||
$this->assertEquals(25, strlen($model->getAccount()->otp_secret));
|
$this->assertEquals(25, strlen($model->getAccount()->otp_secret));
|
||||||
|
$this->assertSame(strtoupper($model->getAccount()->otp_secret), $model->getAccount()->otp_secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ class TotpValidatorTest extends TestCase {
|
|||||||
|
|
||||||
public function testValidateValue() {
|
public function testValidateValue() {
|
||||||
$account = new Account();
|
$account = new Account();
|
||||||
$account->otp_secret = 'some secret';
|
$account->otp_secret = 'AAAA';
|
||||||
$controlTotp = new TOTP(null, $account->otp_secret);
|
$controlTotp = TOTP::create($account->otp_secret);
|
||||||
|
|
||||||
$validator = new TotpValidator(['account' => $account]);
|
$validator = new TotpValidator(['account' => $account]);
|
||||||
|
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ return [
|
|||||||
'lang' => 'ru',
|
'lang' => 'ru',
|
||||||
'status' => \common\models\Account::STATUS_ACTIVE,
|
'status' => \common\models\Account::STATUS_ACTIVE,
|
||||||
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
|
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
|
||||||
'otp_secret' => 'some otp secret value',
|
'otp_secret' => 'AAAA',
|
||||||
'is_otp_enabled' => false,
|
'is_otp_enabled' => false,
|
||||||
'created_at' => 1485124615,
|
'created_at' => 1485124615,
|
||||||
'updated_at' => 1485124615,
|
'updated_at' => 1485124615,
|
||||||
@@ -171,7 +171,7 @@ return [
|
|||||||
'lang' => 'ru',
|
'lang' => 'ru',
|
||||||
'status' => \common\models\Account::STATUS_ACTIVE,
|
'status' => \common\models\Account::STATUS_ACTIVE,
|
||||||
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
|
'rules_agreement_version' => \common\LATEST_RULES_VERSION,
|
||||||
'otp_secret' => 'secret-secret-secret',
|
'otp_secret' => 'BBBB',
|
||||||
'is_otp_enabled' => true,
|
'is_otp_enabled' => true,
|
||||||
'created_at' => 1485124685,
|
'created_at' => 1485124685,
|
||||||
'updated_at' => 1485124685,
|
'updated_at' => 1485124685,
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ modules:
|
|||||||
Yii2:
|
Yii2:
|
||||||
configFile: '../config/common/unit.php'
|
configFile: '../config/common/unit.php'
|
||||||
cleanup: true
|
cleanup: true
|
||||||
|
transaction: false
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ modules:
|
|||||||
Yii2:
|
Yii2:
|
||||||
configFile: '../config/console/unit.php'
|
configFile: '../config/console/unit.php'
|
||||||
cleanup: true
|
cleanup: true
|
||||||
|
transaction: false
|
||||||
|
|||||||
Reference in New Issue
Block a user