From 86268b97ecc9f12698b7e7109500612297fd755f Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Mon, 31 Jul 2017 23:30:55 +0300 Subject: [PATCH 01/17] 1.1.17-dev [skip ci] --- common/config/config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/config/config.php b/common/config/config.php index 74c5481..e95a179 100644 --- a/common/config/config.php +++ b/common/config/config.php @@ -1,6 +1,6 @@ '1.1.16', + 'version' => '1.1.17-dev', 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', 'components' => [ 'cache' => [ From f235116a70304b018925a6efde095038197c2a65 Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Tue, 1 Aug 2017 20:27:35 +0300 Subject: [PATCH 02/17] Fix build command to exit with code 1 on build fail --- Dockerfile | 2 +- Dockerfile-dev | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index bc906e3..3c33849 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,7 +46,7 @@ RUN mkdir -p api/runtime api/web/assets console/runtime \ # Билдим фронт && cd frontend \ && ln -s /var/www/frontend/node_modules $PWD/node_modules \ - && npm run build:quite --quiet \ + && npm run build:quiet \ && rm node_modules \ # Копируем билд наружу, чтобы его не затёрло volume в dev режиме && cp -r ./dist /var/www/dist \ diff --git a/Dockerfile-dev b/Dockerfile-dev index 2f82da8..a73a928 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -43,7 +43,7 @@ RUN mkdir -p api/runtime api/web/assets console/runtime \ # Билдим фронт && cd frontend \ && ln -s /var/www/frontend/node_modules $PWD/node_modules \ - && npm run build:quite --quiet \ + && npm run build:quite \ && rm node_modules \ # Копируем билд наружу, чтобы его не затёрло volume в dev режиме && cp -r ./dist /var/www/dist \ From 1cf935f3b64ddb66015f44714f6b6c630a766548 Mon Sep 17 00:00:00 2001 From: SleepWalker Date: Tue, 1 Aug 2017 20:43:16 +0300 Subject: [PATCH 03/17] Fix typos --- Dockerfile-dev | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile-dev b/Dockerfile-dev index a73a928..2f5313e 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -43,7 +43,7 @@ RUN mkdir -p api/runtime api/web/assets console/runtime \ # Билдим фронт && cd frontend \ && ln -s /var/www/frontend/node_modules $PWD/node_modules \ - && npm run build:quite \ + && npm run build:quiet \ && rm node_modules \ # Копируем билд наружу, чтобы его не затёрло volume в dev режиме && cp -r ./dist /var/www/dist \ From 7ef672fffc7965b8806f90b4022a5e81b54b34ef Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Wed, 2 Aug 2017 02:43:21 +0300 Subject: [PATCH 04/17] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D1=91=D0=BD=20accounts-php=20=D0=B4=D0=BE=20=D0=B2=D0=B5=D1=80?= =?UTF-8?q?=D1=81=D0=B8=D0=B8=201.4.0=20(PHP=207.1.7,=20NodeJS=208.2.1,=20?= =?UTF-8?q?NPM=205.3.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 2 +- Dockerfile-dev | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3c33849..6aefae6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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/ diff --git a/Dockerfile-dev b/Dockerfile-dev index 2f5313e..3000374 100644 --- a/Dockerfile-dev +++ b/Dockerfile-dev @@ -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/ From c8db2f4b3f041c554ca5887a13ffca202ceccc61 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Wed, 2 Aug 2017 21:55:46 +0300 Subject: [PATCH 05/17] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D1=81=D0=BE=D0=B2=D0=BC=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D1=8C=20=D1=81=20codecepti?= =?UTF-8?q?on=202.3.4=20=D0=92=D0=B5=D1=80=D1=81=D0=B8=D1=8F=20codeception?= =?UTF-8?q?=20=D0=B7=D0=B0=D1=84=D0=B8=D0=BA=D1=81=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 2 +- tests/codeception/api/functional.suite.yml | 1 + tests/codeception/api/unit.suite.yml | 1 + .../api/unit/models/authentication/RegistrationFormTest.php | 4 ++++ tests/codeception/common/unit.suite.yml | 1 + tests/codeception/console/unit.suite.yml | 1 + 6 files changed, 9 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 9624f06..862b0db 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,7 @@ "yiisoft/yii2-faker": "*", "flow/jsonpath": "^0.3.1", "phpunit/phpunit": "^5.7", - "codeception/codeception": "~2.3", + "codeception/codeception": "2.3.4", "codeception/specify": "*", "codeception/verify": "*", "phploc/phploc": "^3.0.1", diff --git a/tests/codeception/api/functional.suite.yml b/tests/codeception/api/functional.suite.yml index 3dd11ab..2c726d3 100644 --- a/tests/codeception/api/functional.suite.yml +++ b/tests/codeception/api/functional.suite.yml @@ -13,6 +13,7 @@ modules: Yii2: configFile: '../config/api/functional.php' cleanup: true + transaction: false Redis: host: "%REDIS_HOST%" port: 6379 diff --git a/tests/codeception/api/unit.suite.yml b/tests/codeception/api/unit.suite.yml index ddf9713..ccb1862 100644 --- a/tests/codeception/api/unit.suite.yml +++ b/tests/codeception/api/unit.suite.yml @@ -9,3 +9,4 @@ modules: Yii2: configFile: '../config/api/unit.php' cleanup: true + transaction: false diff --git a/tests/codeception/api/unit/models/authentication/RegistrationFormTest.php b/tests/codeception/api/unit/models/authentication/RegistrationFormTest.php index d3e7c57..2db914f 100644 --- a/tests/codeception/api/unit/models/authentication/RegistrationFormTest.php +++ b/tests/codeception/api/unit/models/authentication/RegistrationFormTest.php @@ -10,6 +10,8 @@ use common\models\UsernameHistory; use GuzzleHttp\ClientInterface; use tests\codeception\api\unit\TestCase; use tests\codeception\common\fixtures\AccountFixture; +use tests\codeception\common\fixtures\EmailActivationFixture; +use tests\codeception\common\fixtures\UsernameHistoryFixture; use Yii; use yii\web\Request; use const common\LATEST_RULES_VERSION; @@ -30,6 +32,8 @@ class RegistrationFormTest extends TestCase { public function _fixtures() { return [ 'accounts' => AccountFixture::class, + 'emailActivations' => EmailActivationFixture::class, + 'usernameHistory' => UsernameHistoryFixture::class, ]; } diff --git a/tests/codeception/common/unit.suite.yml b/tests/codeception/common/unit.suite.yml index 74f9d6a..11d4bb4 100644 --- a/tests/codeception/common/unit.suite.yml +++ b/tests/codeception/common/unit.suite.yml @@ -8,3 +8,4 @@ modules: Yii2: configFile: '../config/common/unit.php' cleanup: true + transaction: false diff --git a/tests/codeception/console/unit.suite.yml b/tests/codeception/console/unit.suite.yml index 110e551..baa5a80 100644 --- a/tests/codeception/console/unit.suite.yml +++ b/tests/codeception/console/unit.suite.yml @@ -8,3 +8,4 @@ modules: Yii2: configFile: '../config/console/unit.php' cleanup: true + transaction: false From ec9da1709bdffc757f0f4b20958dbaf3c70ca357 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Thu, 3 Aug 2017 03:02:51 +0300 Subject: [PATCH 06/17] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=B2=20=D0=BF=D0=BE=D0=BB=D0=B5=20qr=20=D0=B7=D0=B0=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=81=D0=B0=20/api/two-factor-auth=20=D0=B2=D0=BE?= =?UTF-8?q?=D0=B7=D0=B2=D1=80=D0=B0=D1=89=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20?= =?UTF-8?q?=D1=81=D1=82=D1=80=D0=BE=D0=BA=D0=B0=20=D1=81=20svg=20=D0=B1?= =?UTF-8?q?=D0=B5=D0=B7=20base64,=20=D0=BD=D0=B0=D1=87=D0=B8=D0=BD=D0=B0?= =?UTF-8?q?=D1=8E=D1=89=D0=B0=D1=8F=D1=81=D1=8F=20=D1=81=20data:image/svg+?= =?UTF-8?q?xml,?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/models/profile/TwoFactorAuthForm.php | 2 +- .../api/unit/models/profile/TwoFactorAuthFormTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/models/profile/TwoFactorAuthForm.php b/api/models/profile/TwoFactorAuthForm.php index 275ec97..1f2b47f 100644 --- a/api/models/profile/TwoFactorAuthForm.php +++ b/api/models/profile/TwoFactorAuthForm.php @@ -63,7 +63,7 @@ class TwoFactorAuthForm extends ApiForm { $provisioningUri = $this->getTotp()->getProvisioningUri(); return [ - 'qr' => base64_encode($this->drawQrCode($provisioningUri)), + 'qr' => 'data:image/svg+xml,' . htmlspecialchars(trim($this->drawQrCode($provisioningUri))), 'uri' => $provisioningUri, 'secret' => $this->account->otp_secret, ]; diff --git a/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php b/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php index 780652c..36435f1 100644 --- a/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php +++ b/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php @@ -35,7 +35,7 @@ class TwoFactorAuthFormTest extends TestCase { $model->expects($this->once()) ->method('drawQrCode') - ->willReturn('this is qr code, trust me'); + ->willReturn('<_/>'); $result = $model->getCredentials(); $this->assertTrue(is_array($result)); @@ -44,7 +44,7 @@ class TwoFactorAuthFormTest extends TestCase { $this->assertArrayHasKey('secret', $result); $this->assertNotNull($account->otp_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 */ $account = $this->getMockBuilder(Account::class) From f75c241c5f4eac7d21f5d064ed0b5a605861a90c Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Thu, 3 Aug 2017 14:50:48 +0300 Subject: [PATCH 07/17] =?UTF-8?q?=D0=9D=D0=B5=20=D1=8D=D0=BA=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=80=D1=83=D0=B5=D0=BC=20=D1=81=D0=B8=D0=BC=D0=B2?= =?UTF-8?q?=D0=BE=D0=BB=D1=8B=20html=20=D1=81=D0=B8=D0=BC=D0=B2=D0=BE?= =?UTF-8?q?=D0=BB=D1=8B=20=D0=B2=20qr=20=D0=BA=D0=BE=D0=B4=D0=B5,=20=D1=82?= =?UTF-8?q?.=D0=BA.=20=D0=BE=D0=BD=D0=B8=20=D0=B2=D1=81=D1=91=20=D1=82?= =?UTF-8?q?=D0=B0=D0=BA=D0=B8=20=D0=BD=D0=B5=20=D0=B4=D0=BE=D0=BB=D0=B6?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=B1=D1=8B=D1=82=D1=8C=20=D1=8D=D0=BA=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/models/profile/TwoFactorAuthForm.php | 2 +- .../api/unit/models/profile/TwoFactorAuthFormTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/models/profile/TwoFactorAuthForm.php b/api/models/profile/TwoFactorAuthForm.php index 1f2b47f..f78b00c 100644 --- a/api/models/profile/TwoFactorAuthForm.php +++ b/api/models/profile/TwoFactorAuthForm.php @@ -63,7 +63,7 @@ class TwoFactorAuthForm extends ApiForm { $provisioningUri = $this->getTotp()->getProvisioningUri(); return [ - 'qr' => 'data:image/svg+xml,' . htmlspecialchars(trim($this->drawQrCode($provisioningUri))), + 'qr' => 'data:image/svg+xml,' . trim($this->drawQrCode($provisioningUri)), 'uri' => $provisioningUri, 'secret' => $this->account->otp_secret, ]; diff --git a/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php b/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php index 36435f1..6e8837d 100644 --- a/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php +++ b/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php @@ -44,7 +44,7 @@ class TwoFactorAuthFormTest extends TestCase { $this->assertArrayHasKey('secret', $result); $this->assertNotNull($account->otp_secret); $this->assertEquals($account->otp_secret, $result['secret']); - $this->assertEquals('data:image/svg+xml,<_/>', $result['qr']); + $this->assertEquals('data:image/svg+xml,<_/>', $result['qr']); /** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */ $account = $this->getMockBuilder(Account::class) From 46936db0a70fe7169b300cd665a3d8f449ef72fc Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Mon, 7 Aug 2017 14:05:42 +0300 Subject: [PATCH 08/17] =?UTF-8?q?Fix=20#344=20=D0=91=D0=B0=D0=B3=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D0=BF=D0=BE=D0=BF=D1=8B=D1=82=D0=BA=D0=B5=20?= =?UTF-8?q?=D0=B7=D0=B0=D1=80=D0=B5=D1=84=D1=80=D0=B5=D1=88=D0=B8=D1=82?= =?UTF-8?q?=D1=8C=20accessToken,=20=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D1=8B?= =?UTF-8?q?=D0=B9=20=D0=BE=D0=BA=D0=BE=D0=BD=D1=87=D0=B0=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D0=BE=20=D1=81=D0=B3=D0=BD=D0=B8=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/components/OAuth2/Storage/AccessTokenStorage.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/api/components/OAuth2/Storage/AccessTokenStorage.php b/api/components/OAuth2/Storage/AccessTokenStorage.php index fdeb14c..c31742b 100644 --- a/api/components/OAuth2/Storage/AccessTokenStorage.php +++ b/api/components/OAuth2/Storage/AccessTokenStorage.php @@ -16,6 +16,9 @@ class AccessTokenStorage extends AbstractStorage implements AccessTokenInterface public function get($token) { $result = Json::decode((new Key($this->dataTable, $token))->getValue()); + if ($result === null) { + return null; + } $token = new AccessTokenEntity($this->server); $token->setId($result['id']); From 9a852e8052cfd8b8a2529a9409b5325bf2254903 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 8 Aug 2017 00:56:24 +0300 Subject: [PATCH 09/17] =?UTF-8?q?=D0=A0=D0=B5=D0=BD=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B8=D0=BC=20SVG=20QR=20=D0=BA=D0=BE=D0=B4=20=D0=B1=D0=B5?= =?UTF-8?q?=D0=B7=20=D1=84=D0=B8=D0=BA=D1=81=D0=B0=D1=86=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=B5=D0=B3=D0=BE=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80=D0=B0?= =?UTF-8?q?,=20=D1=82.=D0=BA.=20=D0=BF=D0=BE=D1=81=D1=87=D0=B8=D1=82=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D0=BE=D0=B5=20=D1=80=D0=B0=D0=B7=D1=80=D0=B5=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B2=20=D0=BC=D0=BE=D0=BC=D0=B5=D0=BD=D1=82=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=B3=D0=BE=D1=82=D0=BE=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D1=80=D0=B5=D0=BD=D0=B4=D0=B5=D1=80=D0=B5=D1=80=D0=B0=20=D0=BD?= =?UTF-8?q?=D0=B5=20=D0=B8=D0=B7=D0=B2=D0=B5=D1=81=D1=82=D0=B5=D0=BD=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=80=20=D0=BC=D0=B0=D1=82=D1=80?= =?UTF-8?q?=D0=B8=D1=86=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/models/profile/TwoFactorAuthForm.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/api/models/profile/TwoFactorAuthForm.php b/api/models/profile/TwoFactorAuthForm.php index f78b00c..e734bb6 100644 --- a/api/models/profile/TwoFactorAuthForm.php +++ b/api/models/profile/TwoFactorAuthForm.php @@ -38,7 +38,7 @@ class TwoFactorAuthForm extends ApiForm { parent::__construct($config); } - public function rules() { + public function rules(): array { $bothScenarios = [self::SCENARIO_ACTIVATE, self::SCENARIO_DISABLE]; return [ ['timestamp', 'integer', 'on' => [self::SCENARIO_ACTIVATE]], @@ -132,10 +132,8 @@ class TwoFactorAuthForm extends ApiForm { public function drawQrCode(string $content): string { $renderer = new Svg(); - $renderer->setHeight(256); - $renderer->setWidth(256); - $renderer->setForegroundColor(new Rgb(32, 126, 92)); $renderer->setMargin(0); + $renderer->setForegroundColor(new Rgb(32, 126, 92)); $renderer->addDecorator(new ElyDecorator()); $writer = new Writer($renderer); From 5480e3c8ef310ae560dbf5a64e65a09b6cc42f55 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 8 Aug 2017 02:08:34 +0300 Subject: [PATCH 10/17] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D1=80=D0=B5=D0=BD=D0=B4=D0=B5=D1=80=D0=B8?= =?UTF-8?q?=D0=BD=D0=B3=20QR=20=D0=BA=D0=BE=D0=B4=D0=B0=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D0=B5=D0=B9=20=D1=81=20=D0=BA=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B8=D0=BC=D0=B8=20username=20=D0=B8=D0=BB=D0=B8?= =?UTF-8?q?=20email?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/models/profile/TwoFactorAuthForm.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/api/models/profile/TwoFactorAuthForm.php b/api/models/profile/TwoFactorAuthForm.php index e734bb6..df3dcc6 100644 --- a/api/models/profile/TwoFactorAuthForm.php +++ b/api/models/profile/TwoFactorAuthForm.php @@ -131,6 +131,8 @@ class TwoFactorAuthForm extends ApiForm { } public function drawQrCode(string $content): string { + $content = $this->forceMinimalQrContentLength($content); + $renderer = new Svg(); $renderer->setMargin(0); $renderer->setForegroundColor(new Rgb(32, 126, 92)); @@ -158,4 +160,20 @@ class TwoFactorAuthForm extends ApiForm { } } + /** + * В используемой либе для рендеринга 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, '#'); + } + } From 9cd622fd0dab7f05dd68684764b391e3e70706fd Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 8 Aug 2017 12:40:39 +0300 Subject: [PATCH 11/17] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20Node.js=20=D0=B4=D0=BB=D1=8F=20CI=20?= =?UTF-8?q?=D0=B4=D0=BE=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D0=B8=208.2.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 04f976d..22c33d0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -40,7 +40,7 @@ test:backend: php vendor/bin/codecept run -c tests test:frontend: - image: node:5.12 + image: node:8.2.1 stage: test cache: paths: From 54148a4b9350389bb958f9d12582bb347cc659be Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 8 Aug 2017 17:51:12 +0300 Subject: [PATCH 12/17] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20roave/security-advisories=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D0=B7=D0=B0=D1=89=D0=B8=D1=82=D1=8B=20=D0=BE=D1=82=20=D1=83?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BA=D0=B8=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=B2=D0=B8=D1=81=D0=B8=D0=BC=D0=BE=D1=81=D1=82=D0=B5=D0=B9=20?= =?UTF-8?q?=D1=81=20=D0=BF=D1=80=D0=BE=D0=B1=D0=BB=D0=B5=D0=BC=D0=B0=D0=BC?= =?UTF-8?q?=D0=B8=20=D0=B1=D0=B5=D0=B7=D0=BE=D0=BF=D0=B0=D1=81=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 862b0db..3f4e2f1 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,8 @@ "mito/yii2-sentry": "^1.0", "minime/annotations": "~3.0", "spomky-labs/otphp": "8.3.1", - "bacon/bacon-qr-code": "^1.0" + "bacon/bacon-qr-code": "^1.0", + "roave/security-advisories": "dev-master" }, "require-dev": { "yiisoft/yii2-codeception": "*", From 7f5c1e481807f7c1f31b761ec28225e75f6ad98c Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 8 Aug 2017 18:06:28 +0300 Subject: [PATCH 13/17] =?UTF-8?q?Yii2=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D1=91=D0=BD=20=D0=B4=D0=BE=20=D0=B2=D0=B5=D1=80=D1=81?= =?UTF-8?q?=D0=B8=D0=B8=202.0.12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/composer.json b/composer.json index 3f4e2f1..a67e4de 100644 --- a/composer.json +++ b/composer.json @@ -1,21 +1,12 @@ { - "name": "yiisoft/yii2-app-advanced", - "description": "Yii 2 Advanced Project Template", - "keywords": ["yii2", "framework", "advanced", "project template"], - "homepage": "http://www.yiiframework.com/", + "name": "elyby/accounts", + "description": "Authentication service for Ely.by", + "homepage": "https://account.ely.by", "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", "require": { "php": "^7.1", - "yiisoft/yii2": "2.0.11.2", + "yiisoft/yii2": "2.0.12", "yiisoft/yii2-swiftmailer": "*", "ramsey/uuid": "^3.5.0", "league/oauth2-server": "dev-improvements#fbaa9b0bd3d8050235ba7dde90f731764122bc20", @@ -46,9 +37,6 @@ "mockery/mockery": "1.0.0-alpha1", "php-mock/php-mock-mockery": "dev-mockery-1.0.0#03956ed4b34ae25bc20a0677500f4f4b416f976c" }, - "config": { - "process-timeout": 1800 - }, "repositories": [ { "type": "composer", From 549db30b2be0d9dfc664af82d734cdfc57b97b9c Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 8 Aug 2017 20:18:44 +0300 Subject: [PATCH 14/17] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D1=91=D0=BD=20Spomky-Labs/otphp=20=D0=B4=D0=BE=209.0.2=20?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/models/profile/TwoFactorAuthForm.php | 8 +++++--- api/validators/TotpValidator.php | 9 +++++++-- composer.json | 5 +++-- tests/codeception/api/functional/ForgotPasswordCest.php | 2 +- tests/codeception/api/functional/LoginCest.php | 2 +- .../api/functional/TwoFactorAuthDisableCest.php | 2 +- .../api/functional/TwoFactorAuthEnableCest.php | 2 +- .../models/authentication/ForgotPasswordFormTest.php | 2 +- .../api/unit/models/authentication/LoginFormTest.php | 4 ++-- .../api/unit/models/profile/TwoFactorAuthFormTest.php | 2 ++ .../api/unit/validators/TotpValidatorTest.php | 4 ++-- tests/codeception/common/fixtures/data/accounts.php | 4 ++-- 12 files changed, 28 insertions(+), 18 deletions(-) diff --git a/api/models/profile/TwoFactorAuthForm.php b/api/models/profile/TwoFactorAuthForm.php index df3dcc6..8f6c31f 100644 --- a/api/models/profile/TwoFactorAuthForm.php +++ b/api/models/profile/TwoFactorAuthForm.php @@ -9,11 +9,11 @@ use BaconQrCode\Encoder\Encoder; use BaconQrCode\Renderer\Color\Rgb; use BaconQrCode\Renderer\Image\Svg; use BaconQrCode\Writer; -use Base32\Base32; use common\components\Qr\ElyDecorator; use common\helpers\Error as E; use common\models\Account; use OTPHP\TOTP; +use ParagonIE\ConstantTime\Encoding; use Yii; use yii\base\ErrorException; @@ -124,7 +124,8 @@ class TwoFactorAuthForm extends ApiForm { * @return 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'); return $totp; @@ -154,7 +155,8 @@ class TwoFactorAuthForm extends ApiForm { */ 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); + $randomBase32 = trim(Encoding::base32EncodeUpper(random_bytes($randomBytesLength)), '='); + $this->account->otp_secret = substr($randomBase32, 0, $length); if (!$this->account->save()) { throw new ErrorException('Cannot set account otp_secret'); } diff --git a/api/validators/TotpValidator.php b/api/validators/TotpValidator.php index e436d0c..68bbc5e 100644 --- a/api/validators/TotpValidator.php +++ b/api/validators/TotpValidator.php @@ -4,6 +4,7 @@ namespace api\validators; use common\helpers\Error as E; use common\models\Account; use OTPHP\TOTP; +use RangeException; use Yii; use yii\base\InvalidConfigException; use yii\validators\Validator; @@ -48,8 +49,12 @@ class TotpValidator extends Validator { } protected function validateValue($value) { - $totp = new TOTP(null, $this->account->otp_secret); - if (!$totp->verify((string)$value, $this->getTimestamp(), $this->window)) { + try { + $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, []]; } diff --git a/composer.json b/composer.json index a67e4de..6dc66a0 100644 --- a/composer.json +++ b/composer.json @@ -20,9 +20,10 @@ "predis/predis": "^1.0", "mito/yii2-sentry": "^1.0", "minime/annotations": "~3.0", - "spomky-labs/otphp": "8.3.1", + "spomky-labs/otphp": "^9.0.2", "bacon/bacon-qr-code": "^1.0", - "roave/security-advisories": "dev-master" + "roave/security-advisories": "dev-master", + "paragonie/constant_time_encoding": "^2.0" }, "require-dev": { "yiisoft/yii2-codeception": "*", diff --git a/tests/codeception/api/functional/ForgotPasswordCest.php b/tests/codeception/api/functional/ForgotPasswordCest.php index 0444838..36023bd 100644 --- a/tests/codeception/api/functional/ForgotPasswordCest.php +++ b/tests/codeception/api/functional/ForgotPasswordCest.php @@ -74,7 +74,7 @@ class ForgotPasswordCest { public function testForgotPasswordByAccountWithOtp(FunctionalTester $I) { $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->assertSuccessResponse($I, true); } diff --git a/tests/codeception/api/functional/LoginCest.php b/tests/codeception/api/functional/LoginCest.php index ab11f50..6f2adaf 100644 --- a/tests/codeception/api/functional/LoginCest.php +++ b/tests/codeception/api/functional/LoginCest.php @@ -206,7 +206,7 @@ class LoginCest { $route = new AuthenticationRoute($I); $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([ 'success' => true, ]); diff --git a/tests/codeception/api/functional/TwoFactorAuthDisableCest.php b/tests/codeception/api/functional/TwoFactorAuthDisableCest.php index 5e41f83..1e288d1 100644 --- a/tests/codeception/api/functional/TwoFactorAuthDisableCest.php +++ b/tests/codeception/api/functional/TwoFactorAuthDisableCest.php @@ -49,7 +49,7 @@ class TwoFactorAuthDisableCest { public function testSuccessEnable(FunctionalTester $I) { $I->amAuthenticated('AccountWithEnabledOtp'); - $totp = new TOTP(null, 'secret-secret-secret'); + $totp = TOTP::create('BBBB'); $this->route->disable($totp->now(), 'password_0'); $I->canSeeResponseCodeIs(200); $I->canSeeResponseIsJson(); diff --git a/tests/codeception/api/functional/TwoFactorAuthEnableCest.php b/tests/codeception/api/functional/TwoFactorAuthEnableCest.php index aee002e..5fea216 100644 --- a/tests/codeception/api/functional/TwoFactorAuthEnableCest.php +++ b/tests/codeception/api/functional/TwoFactorAuthEnableCest.php @@ -49,7 +49,7 @@ class TwoFactorAuthEnableCest { public function testSuccessEnable(FunctionalTester $I) { $I->amAuthenticated('AccountWithOtpSecret'); - $totp = new TOTP(null, 'some otp secret value'); + $totp = TOTP::create('AAAA'); $this->route->enable($totp->now(), 'password_0'); $I->canSeeResponseCodeIs(200); $I->canSeeResponseIsJson(); diff --git a/tests/codeception/api/unit/models/authentication/ForgotPasswordFormTest.php b/tests/codeception/api/unit/models/authentication/ForgotPasswordFormTest.php index 4ae4cc9..e6d82c9 100644 --- a/tests/codeception/api/unit/models/authentication/ForgotPasswordFormTest.php +++ b/tests/codeception/api/unit/models/authentication/ForgotPasswordFormTest.php @@ -48,7 +48,7 @@ class ForgotPasswordFormTest extends TestCase { $model->validateTotpToken('token'); $this->assertEquals(['error.token_incorrect'], $model->getErrors('token')); - $totp = new TOTP(null, 'secret-secret-secret'); + $totp = TOTP::create('BBBB'); $model = new ForgotPasswordForm(); $model->login = 'AccountWithEnabledOtp'; $model->token = $totp->now(); diff --git a/tests/codeception/api/unit/models/authentication/LoginFormTest.php b/tests/codeception/api/unit/models/authentication/LoginFormTest.php index 0cf524e..1307eca 100644 --- a/tests/codeception/api/unit/models/authentication/LoginFormTest.php +++ b/tests/codeception/api/unit/models/authentication/LoginFormTest.php @@ -76,7 +76,7 @@ class LoginFormTest extends TestCase { $account = new AccountIdentity(['password' => '12345678']); $account->password = '12345678'; $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) { $model = $this->createModel([ @@ -88,7 +88,7 @@ class LoginFormTest extends TestCase { $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) { $model = $this->createModel([ 'password' => '12345678', diff --git a/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php b/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php index 6e8837d..5157b05 100644 --- a/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php +++ b/tests/codeception/api/unit/models/profile/TwoFactorAuthFormTest.php @@ -197,10 +197,12 @@ class TwoFactorAuthFormTest extends TestCase { $model = new TwoFactorAuthForm($account); $this->callProtected($model, 'setOtpSecret'); $this->assertEquals(24, strlen($model->getAccount()->otp_secret)); + $this->assertSame(strtoupper($model->getAccount()->otp_secret), $model->getAccount()->otp_secret); $model = new TwoFactorAuthForm($account); $this->callProtected($model, 'setOtpSecret', 25); $this->assertEquals(25, strlen($model->getAccount()->otp_secret)); + $this->assertSame(strtoupper($model->getAccount()->otp_secret), $model->getAccount()->otp_secret); } } diff --git a/tests/codeception/api/unit/validators/TotpValidatorTest.php b/tests/codeception/api/unit/validators/TotpValidatorTest.php index dfc0bd3..1954009 100644 --- a/tests/codeception/api/unit/validators/TotpValidatorTest.php +++ b/tests/codeception/api/unit/validators/TotpValidatorTest.php @@ -13,8 +13,8 @@ class TotpValidatorTest extends TestCase { public function testValidateValue() { $account = new Account(); - $account->otp_secret = 'some secret'; - $controlTotp = new TOTP(null, $account->otp_secret); + $account->otp_secret = 'AAAA'; + $controlTotp = TOTP::create($account->otp_secret); $validator = new TotpValidator(['account' => $account]); diff --git a/tests/codeception/common/fixtures/data/accounts.php b/tests/codeception/common/fixtures/data/accounts.php index c8c79d3..fe15830 100644 --- a/tests/codeception/common/fixtures/data/accounts.php +++ b/tests/codeception/common/fixtures/data/accounts.php @@ -156,7 +156,7 @@ return [ 'lang' => 'ru', 'status' => \common\models\Account::STATUS_ACTIVE, 'rules_agreement_version' => \common\LATEST_RULES_VERSION, - 'otp_secret' => 'some otp secret value', + 'otp_secret' => 'AAAA', 'is_otp_enabled' => false, 'created_at' => 1485124615, 'updated_at' => 1485124615, @@ -171,7 +171,7 @@ return [ 'lang' => 'ru', 'status' => \common\models\Account::STATUS_ACTIVE, 'rules_agreement_version' => \common\LATEST_RULES_VERSION, - 'otp_secret' => 'secret-secret-secret', + 'otp_secret' => 'BBBB', 'is_otp_enabled' => true, 'created_at' => 1485124685, 'updated_at' => 1485124685, From 0a5f8feca6f58c29110b121fa934bdfea1a1b2db Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Wed, 9 Aug 2017 01:09:26 +0300 Subject: [PATCH 15/17] =?UTF-8?q?=D0=9F=D0=BE=D0=BF=D1=8B=D1=82=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B2=D0=B5=D1=80=D0=BD=D1=83=D1=82=D1=8C=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D1=83=20npm=20run=20flow?= =?UTF-8?q?=20=D0=B2=20=D1=86=D0=B8=D0=BA=D0=BB=20=D1=81=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 22c33d0..a5a0ba1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -49,7 +49,7 @@ test:frontend: - cd frontend - npm i --silent > /dev/null - npm run lint --silent - # - npm run flow --silent # disabled due to missing libelf.so.1 in docker container + - npm run flow --silent - npm run test --silent build:production: From c824db64870e6cd67e85385b91c616892bb42fc9 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Wed, 9 Aug 2017 01:10:58 +0300 Subject: [PATCH 16/17] =?UTF-8?q?[skip=20ci]=20Revert=20"=D0=9F=D0=BE?= =?UTF-8?q?=D0=BF=D1=8B=D1=82=D0=BA=D0=B0=20=D0=B2=D0=B5=D1=80=D0=BD=D1=83?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D1=83?= =?UTF-8?q?=20npm=20run=20flow=20=D0=B2=20=D1=86=D0=B8=D0=BA=D0=BB=20?= =?UTF-8?q?=D1=81=D0=B1=D0=BE=D1=80=D0=BA=D0=B8"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Увы, это всё ещё не работает. Вероятно, нужно добирать необходимую библиотеку в контейнер --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a5a0ba1..22c33d0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -49,7 +49,7 @@ test:frontend: - cd frontend - npm i --silent > /dev/null - npm run lint --silent - - npm run flow --silent + # - npm run flow --silent # disabled due to missing libelf.so.1 in docker container - npm run test --silent build:production: From 4536129dfde6dad741d2b2318deea67a9888f7e5 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Wed, 9 Aug 2017 01:13:18 +0300 Subject: [PATCH 17/17] 1.1.17 [skip ci] --- common/config/config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/config/config.php b/common/config/config.php index e95a179..3d332f6 100644 --- a/common/config/config.php +++ b/common/config/config.php @@ -1,6 +1,6 @@ '1.1.17-dev', + 'version' => '1.1.17', 'vendorPath' => dirname(dirname(__DIR__)) . '/vendor', 'components' => [ 'cache' => [