mirror of
				https://github.com/elyby/accounts.git
				synced 2025-05-31 14:11:46 +05:30 
			
		
		
		
	Объединены сущности для авторизации посредством JWT токенов и токенов, выданных через oAuth2.
Все действия, связанные с аккаунтами, теперь вызываются через url `/api/v1/accounts/<id>/<action>`. Добавлена вменяемая система разграничения прав на основе RBAC. Теперь oAuth2 токены генерируются как случайная строка в 40 символов длинной, а не UUID. Исправлен баг с неправильным временем жизни токена в ответе успешного запроса аутентификации. Теперь все unit тесты можно успешно прогнать без наличия интернета.
This commit is contained in:
		@@ -2,14 +2,12 @@
 | 
			
		||||
namespace codeception\api\unit\components\User;
 | 
			
		||||
 | 
			
		||||
use api\components\User\Component;
 | 
			
		||||
use api\components\User\LoginResult;
 | 
			
		||||
use api\components\User\RenewResult;
 | 
			
		||||
use api\models\AccountIdentity;
 | 
			
		||||
use Codeception\Specify;
 | 
			
		||||
use api\components\User\Identity;
 | 
			
		||||
use api\components\User\AuthenticationResult;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\AccountSession;
 | 
			
		||||
use Emarref\Jwt\Algorithm\AlgorithmInterface;
 | 
			
		||||
use Emarref\Jwt\Claim\ClaimInterface;
 | 
			
		||||
use Emarref\Jwt\Claim\Expiration;
 | 
			
		||||
use Emarref\Jwt\Claim;
 | 
			
		||||
use Emarref\Jwt\Jwt;
 | 
			
		||||
use Emarref\Jwt\Token;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use tests\codeception\common\_support\ProtectedCaller;
 | 
			
		||||
@@ -20,7 +18,6 @@ use Yii;
 | 
			
		||||
use yii\web\Request;
 | 
			
		||||
 | 
			
		||||
class ComponentTest extends TestCase {
 | 
			
		||||
    use Specify;
 | 
			
		||||
    use ProtectedCaller;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -30,7 +27,7 @@ class ComponentTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function _before() {
 | 
			
		||||
        parent::_before();
 | 
			
		||||
        $this->component = new Component($this->getComponentArguments());
 | 
			
		||||
        $this->component = new Component($this->getComponentConfig());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function _fixtures() {
 | 
			
		||||
@@ -41,183 +38,140 @@ class ComponentTest extends TestCase {
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testLogin() {
 | 
			
		||||
    public function testCreateJwtAuthenticationToken() {
 | 
			
		||||
        $this->mockRequest();
 | 
			
		||||
        $this->specify('success get LoginResult object without session value', function() {
 | 
			
		||||
            $account = new AccountIdentity(['id' => 1]);
 | 
			
		||||
            $result = $this->component->login($account, false);
 | 
			
		||||
            expect($result)->isInstanceOf(LoginResult::class);
 | 
			
		||||
            expect($result->getSession())->null();
 | 
			
		||||
            expect($result->getIdentity())->equals($account);
 | 
			
		||||
            $jwt = $result->getJwt();
 | 
			
		||||
            expect(is_string($jwt))->true();
 | 
			
		||||
            $token = $this->component->parseToken($jwt);
 | 
			
		||||
            $claim = $token->getPayload()->findClaimByName(Expiration::NAME);
 | 
			
		||||
            // Токен выписывается на 7 дней, но мы проверим хотя бы на 2 суток
 | 
			
		||||
            expect($claim->getValue())->greaterThan(time() + 60 * 60 * 24 * 2);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->specify('success get LoginResult object with session value if rememberMe is true', function() {
 | 
			
		||||
            /** @var AccountIdentity $account */
 | 
			
		||||
            $account = AccountIdentity::findOne($this->tester->grabFixture('accounts', 'admin')['id']);
 | 
			
		||||
            $result = $this->component->login($account, true);
 | 
			
		||||
            expect($result)->isInstanceOf(LoginResult::class);
 | 
			
		||||
            expect($result->getSession())->isInstanceOf(AccountSession::class);
 | 
			
		||||
            expect($result->getIdentity())->equals($account);
 | 
			
		||||
            expect($result->getSession()->refresh())->true();
 | 
			
		||||
            $jwt = $result->getJwt();
 | 
			
		||||
            expect(is_string($jwt))->true();
 | 
			
		||||
            $token = $this->component->parseToken($jwt);
 | 
			
		||||
            $claim = $token->getPayload()->findClaimByName(Expiration::NAME);
 | 
			
		||||
            // Токен выписывается на 1 час, т.к. в дальнейшем он будет рефрешиться
 | 
			
		||||
            expect($claim->getValue())->lessOrEquals(time() + 3600);
 | 
			
		||||
        });
 | 
			
		||||
        $account = new Account(['id' => 1]);
 | 
			
		||||
        $result = $this->component->createJwtAuthenticationToken($account, false);
 | 
			
		||||
        $this->assertInstanceOf(AuthenticationResult::class, $result);
 | 
			
		||||
        $this->assertNull($result->getSession());
 | 
			
		||||
        $this->assertEquals($account, $result->getAccount());
 | 
			
		||||
        $payloads = (new Jwt())->deserialize($result->getJwt())->getPayload();
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals(time(), $payloads->findClaimByName(Claim\IssuedAt::NAME)->getValue(), '', 3);
 | 
			
		||||
        /** @noinspection SummerTimeUnsafeTimeManipulationInspection */
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals(time() + 60 * 60 * 24 * 7, $payloads->findClaimByName('exp')->getValue(), '', 3);
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals('ely|1', $payloads->findClaimByName('sub')->getValue());
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals('accounts_web_user', $payloads->findClaimByName('ely-scopes')->getValue());
 | 
			
		||||
        $this->assertNull($payloads->findClaimByName('jti'));
 | 
			
		||||
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        $account = $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
        $result = $this->component->createJwtAuthenticationToken($account, true);
 | 
			
		||||
        $this->assertInstanceOf(AuthenticationResult::class, $result);
 | 
			
		||||
        $this->assertInstanceOf(AccountSession::class, $result->getSession());
 | 
			
		||||
        $this->assertEquals($account, $result->getAccount());
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertTrue($result->getSession()->refresh());
 | 
			
		||||
        $payloads = (new Jwt())->deserialize($result->getJwt())->getPayload();
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals(time(), $payloads->findClaimByName(Claim\IssuedAt::NAME)->getValue(), '', 3);
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals(time() + 3600, $payloads->findClaimByName('exp')->getValue(), '', 3);
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals('ely|1', $payloads->findClaimByName('sub')->getValue());
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals('accounts_web_user', $payloads->findClaimByName('ely-scopes')->getValue());
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals($result->getSession()->id, $payloads->findClaimByName('jti')->getValue());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testRenew() {
 | 
			
		||||
        $this->specify('success get RenewResult object', function() {
 | 
			
		||||
            $userIP = '192.168.0.1';
 | 
			
		||||
            $this->mockRequest($userIP);
 | 
			
		||||
            /** @var AccountSession $session */
 | 
			
		||||
            $session = AccountSession::findOne($this->tester->grabFixture('sessions', 'admin')['id']);
 | 
			
		||||
            $callTime = time();
 | 
			
		||||
            $result = $this->component->renew($session);
 | 
			
		||||
            expect($result)->isInstanceOf(RenewResult::class);
 | 
			
		||||
            expect(is_string($result->getJwt()))->true();
 | 
			
		||||
            expect($result->getIdentity()->getId())->equals($session->account_id);
 | 
			
		||||
            $session->refresh();
 | 
			
		||||
            expect($session->last_refreshed_at)->greaterOrEquals($callTime);
 | 
			
		||||
            expect($session->getReadableIp())->equals($userIP);
 | 
			
		||||
        });
 | 
			
		||||
    public function testRenewJwtAuthenticationToken() {
 | 
			
		||||
        $userIP = '192.168.0.1';
 | 
			
		||||
        $this->mockRequest($userIP);
 | 
			
		||||
        /** @var AccountSession $session */
 | 
			
		||||
        $session = $this->tester->grabFixture('sessions', 'admin');
 | 
			
		||||
        $result = $this->component->renewJwtAuthenticationToken($session);
 | 
			
		||||
        $this->assertInstanceOf(AuthenticationResult::class, $result);
 | 
			
		||||
        $this->assertEquals($session, $result->getSession());
 | 
			
		||||
        $this->assertEquals($session->account_id, $result->getAccount()->id);
 | 
			
		||||
        $session->refresh(); // reload data from db
 | 
			
		||||
        $this->assertEquals(time(), $session->last_refreshed_at, '', 3);
 | 
			
		||||
        $this->assertEquals($userIP, $session->getReadableIp());
 | 
			
		||||
        $payloads = (new Jwt())->deserialize($result->getJwt())->getPayload();
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals(time(), $payloads->findClaimByName(Claim\IssuedAt::NAME)->getValue(), '', 3);
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals(time() + 3600, $payloads->findClaimByName('exp')->getValue(), '', 3);
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals('ely|1', $payloads->findClaimByName('sub')->getValue());
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals('accounts_web_user', $payloads->findClaimByName('ely-scopes')->getValue());
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals($session->id, $payloads->findClaimByName('jti')->getValue(), 'session has not changed');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testParseToken() {
 | 
			
		||||
        $this->mockRequest();
 | 
			
		||||
        $this->specify('success get RenewResult object', function() {
 | 
			
		||||
            $identity = new AccountIdentity(['id' => 1]);
 | 
			
		||||
            $token = $this->callProtected($this->component, 'createToken', $identity);
 | 
			
		||||
            $jwt = $this->callProtected($this->component, 'serializeToken', $token);
 | 
			
		||||
 | 
			
		||||
            expect($this->component->parseToken($jwt))->isInstanceOf(Token::class);
 | 
			
		||||
        });
 | 
			
		||||
        $token = $this->callProtected($this->component, 'createToken', new Account(['id' => 1]));
 | 
			
		||||
        $jwt = $this->callProtected($this->component, 'serializeToken', $token);
 | 
			
		||||
        $this->assertInstanceOf(Token::class, $this->component->parseToken($jwt), 'success get RenewResult object');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testGetActiveSession() {
 | 
			
		||||
        $this->specify('get used account session', function() {
 | 
			
		||||
            /** @var AccountIdentity $identity */
 | 
			
		||||
            $identity = AccountIdentity::findOne($this->tester->grabFixture('accounts', 'admin')['id']);
 | 
			
		||||
            $result = $this->component->login($identity, true);
 | 
			
		||||
            $this->component->logout();
 | 
			
		||||
        $account = $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
        $result = $this->component->createJwtAuthenticationToken($account, true);
 | 
			
		||||
        $this->component->logout();
 | 
			
		||||
 | 
			
		||||
            /** @var Component|\PHPUnit_Framework_MockObject_MockObject $component */
 | 
			
		||||
            $component = $this->getMockBuilder(Component::class)
 | 
			
		||||
                ->setMethods(['getIsGuest'])
 | 
			
		||||
                ->setConstructorArgs([$this->getComponentArguments()])
 | 
			
		||||
                ->getMock();
 | 
			
		||||
        /** @var Component|\PHPUnit_Framework_MockObject_MockObject $component */
 | 
			
		||||
        $component = $this->getMockBuilder(Component::class)
 | 
			
		||||
            ->setMethods(['getIsGuest'])
 | 
			
		||||
            ->setConstructorArgs([$this->getComponentConfig()])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
            $component
 | 
			
		||||
                ->expects($this->any())
 | 
			
		||||
                ->method('getIsGuest')
 | 
			
		||||
                ->willReturn(false);
 | 
			
		||||
        $component
 | 
			
		||||
            ->expects($this->any())
 | 
			
		||||
            ->method('getIsGuest')
 | 
			
		||||
            ->willReturn(false);
 | 
			
		||||
 | 
			
		||||
            $this->mockAuthorizationHeader($result->getJwt());
 | 
			
		||||
        $this->mockAuthorizationHeader($result->getJwt());
 | 
			
		||||
 | 
			
		||||
            $session = $component->getActiveSession();
 | 
			
		||||
            expect($session)->isInstanceOf(AccountSession::class);
 | 
			
		||||
            expect($session->id)->equals($result->getSession()->id);
 | 
			
		||||
        });
 | 
			
		||||
        $session = $component->getActiveSession();
 | 
			
		||||
        $this->assertInstanceOf(AccountSession::class, $session);
 | 
			
		||||
        /** @noinspection NullPointerExceptionInspection */
 | 
			
		||||
        $this->assertEquals($session->id, $result->getSession()->id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testTerminateSessions() {
 | 
			
		||||
        /** @var AccountSession $session */
 | 
			
		||||
        $session = AccountSession::findOne($this->tester->grabFixture('sessions', 'admin2')['id']);
 | 
			
		||||
 | 
			
		||||
        /** @var Component|\PHPUnit_Framework_MockObject_MockObject $component */
 | 
			
		||||
        $component = $this->getMockBuilder(Component::class)
 | 
			
		||||
            ->setMethods(['getActiveSession'])
 | 
			
		||||
            ->setConstructorArgs([$this->getComponentArguments()])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
        /** @var Component|\Mockery\MockInterface $component */
 | 
			
		||||
        $component = mock(Component::class . '[getActiveSession]', [$this->getComponentConfig()])->shouldDeferMissing();
 | 
			
		||||
        $component->shouldReceive('getActiveSession')->times(1)->andReturn($session);
 | 
			
		||||
 | 
			
		||||
        $component
 | 
			
		||||
            ->expects($this->exactly(1))
 | 
			
		||||
            ->method('getActiveSession')
 | 
			
		||||
            ->willReturn($session);
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        $account = $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
        $component->createJwtAuthenticationToken($account, true);
 | 
			
		||||
 | 
			
		||||
        /** @var AccountIdentity $identity */
 | 
			
		||||
        $identity = AccountIdentity::findOne($this->tester->grabFixture('accounts', 'admin')['id']);
 | 
			
		||||
        $component->login($identity, true);
 | 
			
		||||
        $component->terminateSessions($account, Component::KEEP_MINECRAFT_SESSIONS | Component::KEEP_SITE_SESSIONS);
 | 
			
		||||
        $this->assertNotEmpty($account->getMinecraftAccessKeys()->all());
 | 
			
		||||
        $this->assertNotEmpty($account->getSessions()->all());
 | 
			
		||||
 | 
			
		||||
        $component->terminateSessions(0);
 | 
			
		||||
        $this->assertNotEmpty($identity->getMinecraftAccessKeys()->all());
 | 
			
		||||
        $this->assertNotEmpty($identity->getSessions()->all());
 | 
			
		||||
        $component->terminateSessions($account, Component::KEEP_SITE_SESSIONS);
 | 
			
		||||
        $this->assertEmpty($account->getMinecraftAccessKeys()->all());
 | 
			
		||||
        $this->assertNotEmpty($account->getSessions()->all());
 | 
			
		||||
 | 
			
		||||
        $component->terminateSessions(Component::TERMINATE_MINECRAFT_SESSIONS);
 | 
			
		||||
        $this->assertEmpty($identity->getMinecraftAccessKeys()->all());
 | 
			
		||||
        $this->assertNotEmpty($identity->getSessions()->all());
 | 
			
		||||
 | 
			
		||||
        $component->terminateSessions(Component::TERMINATE_SITE_SESSIONS | Component::DO_NOT_TERMINATE_CURRENT_SESSION);
 | 
			
		||||
        $sessions = $identity->getSessions()->all();
 | 
			
		||||
        $component->terminateSessions($account, Component::KEEP_CURRENT_SESSION);
 | 
			
		||||
        $sessions = $account->getSessions()->all();
 | 
			
		||||
        $this->assertEquals(1, count($sessions));
 | 
			
		||||
        $this->assertTrue($sessions[0]->id === $session->id);
 | 
			
		||||
 | 
			
		||||
        $component->terminateSessions(Component::TERMINATE_ALL);
 | 
			
		||||
        $this->assertEmpty($identity->getSessions()->all());
 | 
			
		||||
        $this->assertEmpty($identity->getMinecraftAccessKeys()->all());
 | 
			
		||||
        $component->terminateSessions($account);
 | 
			
		||||
        $this->assertEmpty($account->getSessions()->all());
 | 
			
		||||
        $this->assertEmpty($account->getMinecraftAccessKeys()->all());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testSerializeToken() {
 | 
			
		||||
        $this->specify('get string, contained jwt token', function() {
 | 
			
		||||
            $token = new Token();
 | 
			
		||||
            expect($this->callProtected($this->component, 'serializeToken', $token))
 | 
			
		||||
                ->regExp('/^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+\/=]*$/');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testCreateToken() {
 | 
			
		||||
        $this->specify('create token', function() {
 | 
			
		||||
            expect($this->callProtected($this->component, 'createToken', new AccountIdentity(['id' => 1])))
 | 
			
		||||
                ->isInstanceOf(Token::class);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testGetAlgorithm() {
 | 
			
		||||
        $this->specify('get expected hash algorithm object', function() {
 | 
			
		||||
            expect($this->component->getAlgorithm())->isInstanceOf(AlgorithmInterface::class);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testGetClaims() {
 | 
			
		||||
        $this->specify('get expected array of claims', function() {
 | 
			
		||||
            $claims = $this->callProtected($this->component, 'getClaims', new AccountIdentity(['id' => 1]));
 | 
			
		||||
            expect(is_array($claims))->true();
 | 
			
		||||
            expect('all array items should have valid type', array_filter($claims, function($claim) {
 | 
			
		||||
                return !$claim instanceof ClaimInterface;
 | 
			
		||||
            }))->isEmpty();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param string $userIP
 | 
			
		||||
     * @return \PHPUnit_Framework_MockObject_MockObject
 | 
			
		||||
     */
 | 
			
		||||
    private function mockRequest($userIP = '127.0.0.1') {
 | 
			
		||||
        $request = $this->getMockBuilder(Request::class)
 | 
			
		||||
            ->setMethods(['getHostInfo', 'getUserIP'])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        $request
 | 
			
		||||
            ->expects($this->any())
 | 
			
		||||
            ->method('getHostInfo')
 | 
			
		||||
            ->will($this->returnValue('http://localhost'));
 | 
			
		||||
 | 
			
		||||
        $request
 | 
			
		||||
            ->expects($this->any())
 | 
			
		||||
            ->method('getUserIP')
 | 
			
		||||
            ->will($this->returnValue($userIP));
 | 
			
		||||
        /** @var Request|\Mockery\MockInterface $request */
 | 
			
		||||
        $request = mock(Request::class . '[getHostInfo,getUserIP]')->shouldDeferMissing();
 | 
			
		||||
        $request->shouldReceive('getHostInfo')->andReturn('http://localhost');
 | 
			
		||||
        $request->shouldReceive('getUserIP')->andReturn($userIP);
 | 
			
		||||
 | 
			
		||||
        Yii::$app->set('request', $request);
 | 
			
		||||
 | 
			
		||||
        return $request;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -231,9 +185,9 @@ class ComponentTest extends TestCase {
 | 
			
		||||
        Yii::$app->request->headers->set('Authorization', $bearerToken);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function getComponentArguments() {
 | 
			
		||||
    private function getComponentConfig() {
 | 
			
		||||
        return [
 | 
			
		||||
            'identityClass' => AccountIdentity::class,
 | 
			
		||||
            'identityClass' => Identity::class,
 | 
			
		||||
            'enableSession' => false,
 | 
			
		||||
            'loginUrl' => null,
 | 
			
		||||
            'secret' => 'secret',
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,63 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\unit\components\User;
 | 
			
		||||
 | 
			
		||||
use api\components\User\AuthenticationResult;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\AccountSession;
 | 
			
		||||
use Emarref\Jwt\Algorithm\Hs256;
 | 
			
		||||
use Emarref\Jwt\Claim\Expiration;
 | 
			
		||||
use Emarref\Jwt\Encryption\Factory as EncryptionFactory;
 | 
			
		||||
use Emarref\Jwt\Jwt;
 | 
			
		||||
use Emarref\Jwt\Token;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
 | 
			
		||||
class JwtAuthenticationResultTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function testGetAccount() {
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->id = 123;
 | 
			
		||||
        $model = new AuthenticationResult($account, '', null);
 | 
			
		||||
        $this->assertEquals($account, $model->getAccount());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testGetJwt() {
 | 
			
		||||
        $model = new AuthenticationResult(new Account(), 'mocked jwt', null);
 | 
			
		||||
        $this->assertEquals('mocked jwt', $model->getJwt());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testGetSession() {
 | 
			
		||||
        $model = new AuthenticationResult(new Account(), '', null);
 | 
			
		||||
        $this->assertNull($model->getSession());
 | 
			
		||||
 | 
			
		||||
        $session = new AccountSession();
 | 
			
		||||
        $session->id = 321;
 | 
			
		||||
        $model = new AuthenticationResult(new Account(), '', $session);
 | 
			
		||||
        $this->assertEquals($session, $model->getSession());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testGetAsResponse() {
 | 
			
		||||
        $jwtToken = $this->createJwtToken(time() + 3600);
 | 
			
		||||
        $model = new AuthenticationResult(new Account(), $jwtToken, null);
 | 
			
		||||
        $result = $model->getAsResponse();
 | 
			
		||||
        $this->assertEquals($jwtToken, $result['access_token']);
 | 
			
		||||
        $this->assertSame(3600, $result['expires_in']);
 | 
			
		||||
 | 
			
		||||
        /** @noinspection SummerTimeUnsafeTimeManipulationInspection */
 | 
			
		||||
        $jwtToken = $this->createJwtToken(time() + 86400);
 | 
			
		||||
        $session = new AccountSession();
 | 
			
		||||
        $session->refresh_token = 'refresh token';
 | 
			
		||||
        $model = new AuthenticationResult(new Account(), $jwtToken, $session);
 | 
			
		||||
        $result = $model->getAsResponse();
 | 
			
		||||
        $this->assertEquals($jwtToken, $result['access_token']);
 | 
			
		||||
        $this->assertEquals('refresh token', $result['refresh_token']);
 | 
			
		||||
        $this->assertSame(86400, $result['expires_in']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function createJwtToken(int $expires): string {
 | 
			
		||||
        $token = new Token();
 | 
			
		||||
        $token->addClaim(new Expiration($expires));
 | 
			
		||||
 | 
			
		||||
        return (new Jwt())->serialize($token, EncryptionFactory::create(new Hs256('123')));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,66 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\unit\filters;
 | 
			
		||||
 | 
			
		||||
use api\filters\ActiveUserRule;
 | 
			
		||||
use api\models\AccountIdentity;
 | 
			
		||||
use Codeception\Specify;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use tests\codeception\common\_support\ProtectedCaller;
 | 
			
		||||
use yii\base\Action;
 | 
			
		||||
use const common\LATEST_RULES_VERSION;
 | 
			
		||||
 | 
			
		||||
class ActiveUserRuleTest extends TestCase {
 | 
			
		||||
    use Specify;
 | 
			
		||||
    use ProtectedCaller;
 | 
			
		||||
 | 
			
		||||
    public function testMatchCustom() {
 | 
			
		||||
        $account = new AccountIdentity();
 | 
			
		||||
 | 
			
		||||
        $this->specify('get false if user not finished registration', function() use (&$account) {
 | 
			
		||||
            $account->status = Account::STATUS_REGISTERED;
 | 
			
		||||
            $filter = $this->getFilterMock($account);
 | 
			
		||||
            expect($this->callProtected($filter, 'matchCustom', new Action(null, null)))->false();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->specify('get false if user has banned status', function() use (&$account) {
 | 
			
		||||
            $account->status = Account::STATUS_BANNED;
 | 
			
		||||
            $filter = $this->getFilterMock($account);
 | 
			
		||||
            expect($this->callProtected($filter, 'matchCustom', new Action(null, null)))->false();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->specify('get false if user have old EULA agreement', function() use (&$account) {
 | 
			
		||||
            $account->status = Account::STATUS_ACTIVE;
 | 
			
		||||
            $account->rules_agreement_version = null;
 | 
			
		||||
            $filter = $this->getFilterMock($account);
 | 
			
		||||
            expect($this->callProtected($filter, 'matchCustom', new Action(null, null)))->false();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->specify('get true if user fully active', function() use (&$account) {
 | 
			
		||||
            $account->status = Account::STATUS_ACTIVE;
 | 
			
		||||
            $account->rules_agreement_version = LATEST_RULES_VERSION;
 | 
			
		||||
            $filter = $this->getFilterMock($account);
 | 
			
		||||
            expect($this->callProtected($filter, 'matchCustom', new Action(null, null)))->true();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param AccountIdentity $returnIdentity
 | 
			
		||||
     * @return ActiveUserRule|\PHPUnit_Framework_MockObject_MockObject
 | 
			
		||||
     */
 | 
			
		||||
    private function getFilterMock(AccountIdentity $returnIdentity) {
 | 
			
		||||
        /** @var ActiveUserRule|\PHPUnit_Framework_MockObject_MockObject $filter */
 | 
			
		||||
        $filter = $this
 | 
			
		||||
            ->getMockBuilder(ActiveUserRule::class)
 | 
			
		||||
            ->setMethods(['getIdentity'])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        $filter
 | 
			
		||||
            ->expects($this->any())
 | 
			
		||||
            ->method('getIdentity')
 | 
			
		||||
            ->will($this->returnValue($returnIdentity));
 | 
			
		||||
 | 
			
		||||
        return $filter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,35 +1,34 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace codeception\api\unit\models;
 | 
			
		||||
 | 
			
		||||
use api\models\AccountIdentity;
 | 
			
		||||
use api\components\User\IdentityInterface;
 | 
			
		||||
use api\components\User\Jwt;
 | 
			
		||||
use api\components\User\JwtIdentity;
 | 
			
		||||
use Codeception\Specify;
 | 
			
		||||
use Emarref\Jwt\Claim;
 | 
			
		||||
use Emarref\Jwt\Encryption\Factory as EncryptionFactory;
 | 
			
		||||
use Emarref\Jwt\Jwt;
 | 
			
		||||
use Emarref\Jwt\Token;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use tests\codeception\common\_support\ProtectedCaller;
 | 
			
		||||
use tests\codeception\common\fixtures\AccountFixture;
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\web\IdentityInterface;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @property AccountIdentity $accounts
 | 
			
		||||
 */
 | 
			
		||||
class AccountIdentityTest extends TestCase {
 | 
			
		||||
class JwtIdentityTest extends TestCase {
 | 
			
		||||
    use Specify;
 | 
			
		||||
    use ProtectedCaller;
 | 
			
		||||
 | 
			
		||||
    public function _fixtures() {
 | 
			
		||||
    public function _fixtures(): array {
 | 
			
		||||
        return [
 | 
			
		||||
            'accounts' => AccountFixture::class,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testFindIdentityByAccessToken() {
 | 
			
		||||
        $identity = AccountIdentity::findIdentityByAccessToken($this->generateToken());
 | 
			
		||||
        $token = $this->generateToken();
 | 
			
		||||
        $identity = JwtIdentity::findIdentityByAccessToken($token);
 | 
			
		||||
        $this->assertInstanceOf(IdentityInterface::class, $identity);
 | 
			
		||||
        $this->assertEquals($this->tester->grabFixture('accounts', 'admin')['id'], $identity->getId());
 | 
			
		||||
        $this->assertEquals($token, $identity->getId());
 | 
			
		||||
        $this->assertEquals($this->tester->grabFixture('accounts', 'admin')['id'], $identity->getAccount()->id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -42,10 +41,10 @@ class AccountIdentityTest extends TestCase {
 | 
			
		||||
        $token->addClaim(new Claim\Issuer('http://localhost'));
 | 
			
		||||
        $token->addClaim(new Claim\IssuedAt(1464593193));
 | 
			
		||||
        $token->addClaim(new Claim\Expiration(1464596793));
 | 
			
		||||
        $token->addClaim(new Claim\JwtId($this->tester->grabFixture('accounts', 'admin')['id']));
 | 
			
		||||
        $token->addClaim(new Claim\Subject('ely|' . $this->tester->grabFixture('accounts', 'admin')['id']));
 | 
			
		||||
        $expiredToken = (new Jwt())->serialize($token, EncryptionFactory::create(Yii::$app->user->getAlgorithm()));
 | 
			
		||||
 | 
			
		||||
        AccountIdentity::findIdentityByAccessToken($expiredToken);
 | 
			
		||||
        JwtIdentity::findIdentityByAccessToken($expiredToken);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -53,15 +52,14 @@ class AccountIdentityTest extends TestCase {
 | 
			
		||||
     * @expectedExceptionMessage Incorrect token
 | 
			
		||||
     */
 | 
			
		||||
    public function testFindIdentityByAccessTokenWithEmptyToken() {
 | 
			
		||||
        AccountIdentity::findIdentityByAccessToken('');
 | 
			
		||||
        JwtIdentity::findIdentityByAccessToken('');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function generateToken() {
 | 
			
		||||
        /** @var \api\components\User\Component $component */
 | 
			
		||||
        $component = Yii::$app->user;
 | 
			
		||||
        /** @var AccountIdentity $account */
 | 
			
		||||
        $account = AccountIdentity::findOne($this->tester->grabFixture('accounts', 'admin')['id']);
 | 
			
		||||
 | 
			
		||||
        /** @var \common\models\Account $account */
 | 
			
		||||
        $account = $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
        $token = $this->callProtected($component, 'createToken', $account);
 | 
			
		||||
 | 
			
		||||
        return $this->callProtected($component, 'serializeToken', $token);
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\models\authentication;
 | 
			
		||||
 | 
			
		||||
use api\components\User\LoginResult;
 | 
			
		||||
use api\components\User\AuthenticationResult;
 | 
			
		||||
use api\models\authentication\ConfirmEmailForm;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\AccountSession;
 | 
			
		||||
@@ -21,7 +21,7 @@ class ConfirmEmailFormTest extends TestCase {
 | 
			
		||||
        $fixture = $this->tester->grabFixture('emailActivations', 'freshRegistrationConfirmation');
 | 
			
		||||
        $model = $this->createModel($fixture['key']);
 | 
			
		||||
        $result = $model->confirm();
 | 
			
		||||
        $this->assertInstanceOf(LoginResult::class, $result);
 | 
			
		||||
        $this->assertInstanceOf(AuthenticationResult::class, $result);
 | 
			
		||||
        $this->assertInstanceOf(AccountSession::class, $result->getSession(), 'session was generated');
 | 
			
		||||
        $activationExists = EmailActivation::find()->andWhere(['key' => $fixture['key']])->exists();
 | 
			
		||||
        $this->assertFalse($activationExists, 'email activation key is not exist');
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\models\authentication;
 | 
			
		||||
 | 
			
		||||
use api\components\User\LoginResult;
 | 
			
		||||
use api\models\AccountIdentity;
 | 
			
		||||
use api\components\User\AuthenticationResult;
 | 
			
		||||
use api\models\authentication\LoginForm;
 | 
			
		||||
use Codeception\Specify;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
@@ -45,7 +44,7 @@ class LoginFormTest extends TestCase {
 | 
			
		||||
        $this->specify('no errors if login exists', function () {
 | 
			
		||||
            $model = $this->createModel([
 | 
			
		||||
                'login' => 'mr-test',
 | 
			
		||||
                'account' => new AccountIdentity(),
 | 
			
		||||
                'account' => new Account(),
 | 
			
		||||
            ]);
 | 
			
		||||
            $model->validateLogin('login');
 | 
			
		||||
            $this->assertEmpty($model->getErrors('login'));
 | 
			
		||||
@@ -56,7 +55,7 @@ class LoginFormTest extends TestCase {
 | 
			
		||||
        $this->specify('error.password_incorrect if password invalid', function () {
 | 
			
		||||
            $model = $this->createModel([
 | 
			
		||||
                'password' => '87654321',
 | 
			
		||||
                'account' => new AccountIdentity(['password' => '12345678']),
 | 
			
		||||
                'account' => new Account(['password' => '12345678']),
 | 
			
		||||
            ]);
 | 
			
		||||
            $model->validatePassword('password');
 | 
			
		||||
            $this->assertEquals(['error.password_incorrect'], $model->getErrors('password'));
 | 
			
		||||
@@ -65,7 +64,7 @@ class LoginFormTest extends TestCase {
 | 
			
		||||
        $this->specify('no errors if password valid', function () {
 | 
			
		||||
            $model = $this->createModel([
 | 
			
		||||
                'password' => '12345678',
 | 
			
		||||
                'account' => new AccountIdentity(['password' => '12345678']),
 | 
			
		||||
                'account' => new Account(['password' => '12345678']),
 | 
			
		||||
            ]);
 | 
			
		||||
            $model->validatePassword('password');
 | 
			
		||||
            $this->assertEmpty($model->getErrors('password'));
 | 
			
		||||
@@ -73,7 +72,7 @@ class LoginFormTest extends TestCase {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testValidateTotp() {
 | 
			
		||||
        $account = new AccountIdentity(['password' => '12345678']);
 | 
			
		||||
        $account = new Account(['password' => '12345678']);
 | 
			
		||||
        $account->password = '12345678';
 | 
			
		||||
        $account->is_otp_enabled = true;
 | 
			
		||||
        $account->otp_secret = 'AAAA';
 | 
			
		||||
@@ -103,7 +102,7 @@ class LoginFormTest extends TestCase {
 | 
			
		||||
    public function testValidateActivity() {
 | 
			
		||||
        $this->specify('error.account_not_activated if account in not activated state', function () {
 | 
			
		||||
            $model = $this->createModel([
 | 
			
		||||
                'account' => new AccountIdentity(['status' => Account::STATUS_REGISTERED]),
 | 
			
		||||
                'account' => new Account(['status' => Account::STATUS_REGISTERED]),
 | 
			
		||||
            ]);
 | 
			
		||||
            $model->validateActivity('login');
 | 
			
		||||
            $this->assertEquals(['error.account_not_activated'], $model->getErrors('login'));
 | 
			
		||||
@@ -111,7 +110,7 @@ class LoginFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
        $this->specify('error.account_banned if account has banned status', function () {
 | 
			
		||||
            $model = $this->createModel([
 | 
			
		||||
                'account' => new AccountIdentity(['status' => Account::STATUS_BANNED]),
 | 
			
		||||
                'account' => new Account(['status' => Account::STATUS_BANNED]),
 | 
			
		||||
            ]);
 | 
			
		||||
            $model->validateActivity('login');
 | 
			
		||||
            $this->assertEquals(['error.account_banned'], $model->getErrors('login'));
 | 
			
		||||
@@ -119,7 +118,7 @@ class LoginFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
        $this->specify('no errors if account active', function () {
 | 
			
		||||
            $model = $this->createModel([
 | 
			
		||||
                'account' => new AccountIdentity(['status' => Account::STATUS_ACTIVE]),
 | 
			
		||||
                'account' => new Account(['status' => Account::STATUS_ACTIVE]),
 | 
			
		||||
            ]);
 | 
			
		||||
            $model->validateActivity('login');
 | 
			
		||||
            $this->assertEmpty($model->getErrors('login'));
 | 
			
		||||
@@ -130,13 +129,13 @@ class LoginFormTest extends TestCase {
 | 
			
		||||
        $model = $this->createModel([
 | 
			
		||||
            'login' => 'erickskrauch',
 | 
			
		||||
            'password' => '12345678',
 | 
			
		||||
            'account' => new AccountIdentity([
 | 
			
		||||
            'account' => new Account([
 | 
			
		||||
                'username' => 'erickskrauch',
 | 
			
		||||
                'password' => '12345678',
 | 
			
		||||
                'status' => Account::STATUS_ACTIVE,
 | 
			
		||||
            ]),
 | 
			
		||||
        ]);
 | 
			
		||||
        $this->assertInstanceOf(LoginResult::class, $model->login(), 'model should login user');
 | 
			
		||||
        $this->assertInstanceOf(AuthenticationResult::class, $model->login(), 'model should login user');
 | 
			
		||||
        $this->assertEmpty($model->getErrors(), 'error message should not be set');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -145,7 +144,7 @@ class LoginFormTest extends TestCase {
 | 
			
		||||
            'login' => $this->tester->grabFixture('accounts', 'user-with-old-password-type')['username'],
 | 
			
		||||
            'password' => '12345678',
 | 
			
		||||
        ]);
 | 
			
		||||
        $this->assertInstanceOf(LoginResult::class, $model->login());
 | 
			
		||||
        $this->assertInstanceOf(AuthenticationResult::class, $model->login());
 | 
			
		||||
        $this->assertEmpty($model->getErrors());
 | 
			
		||||
        $this->assertEquals(
 | 
			
		||||
            Account::PASS_HASH_STRATEGY_YII2,
 | 
			
		||||
@@ -166,7 +165,7 @@ class LoginFormTest extends TestCase {
 | 
			
		||||
                $this->_account = $value;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public function getAccount() {
 | 
			
		||||
            public function getAccount(): ?Account {
 | 
			
		||||
                return $this->_account;
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
namespace tests\codeception\api\models\authentication;
 | 
			
		||||
 | 
			
		||||
use api\components\User\Component;
 | 
			
		||||
use api\models\AccountIdentity;
 | 
			
		||||
use api\components\User\Identity;
 | 
			
		||||
use api\models\authentication\LogoutForm;
 | 
			
		||||
use Codeception\Specify;
 | 
			
		||||
use common\models\AccountSession;
 | 
			
		||||
@@ -59,7 +59,7 @@ class LogoutFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    private function getComponentArgs() {
 | 
			
		||||
        return [
 | 
			
		||||
            'identityClass' => AccountIdentity::class,
 | 
			
		||||
            'identityClass' => Identity::class,
 | 
			
		||||
            'enableSession' => false,
 | 
			
		||||
            'loginUrl' => null,
 | 
			
		||||
            'secret' => 'secret',
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\models\authentication;
 | 
			
		||||
 | 
			
		||||
use api\components\User\LoginResult;
 | 
			
		||||
use api\components\User\AuthenticationResult;
 | 
			
		||||
use api\models\authentication\RecoverPasswordForm;
 | 
			
		||||
use Codeception\Specify;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
@@ -26,7 +26,7 @@ class RecoverPasswordFormTest extends TestCase {
 | 
			
		||||
            'newRePassword' => '12345678',
 | 
			
		||||
        ]);
 | 
			
		||||
        $result = $model->recoverPassword();
 | 
			
		||||
        $this->assertInstanceOf(LoginResult::class, $result);
 | 
			
		||||
        $this->assertInstanceOf(AuthenticationResult::class, $result);
 | 
			
		||||
        $this->assertNull($result->getSession(), 'session was not generated');
 | 
			
		||||
        $this->assertFalse(EmailActivation::find()->andWhere(['key' => $fixture['key']])->exists());
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace codeception\api\unit\models\authentication;
 | 
			
		||||
 | 
			
		||||
use api\components\User\RenewResult;
 | 
			
		||||
use api\components\User\AuthenticationResult;
 | 
			
		||||
use api\models\authentication\RefreshTokenForm;
 | 
			
		||||
use Codeception\Specify;
 | 
			
		||||
use common\models\AccountSession;
 | 
			
		||||
@@ -26,7 +26,7 @@ class RefreshTokenFormTest extends TestCase {
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            $model->validateRefreshToken();
 | 
			
		||||
            expect($model->getErrors('refresh_token'))->equals(['error.refresh_token_not_exist']);
 | 
			
		||||
            $this->assertEquals(['error.refresh_token_not_exist'], $model->getErrors('refresh_token'));
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->specify('no errors if token exists', function() {
 | 
			
		||||
@@ -37,14 +37,14 @@ class RefreshTokenFormTest extends TestCase {
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            $model->validateRefreshToken();
 | 
			
		||||
            expect($model->getErrors('refresh_token'))->isEmpty();
 | 
			
		||||
            $this->assertEmpty($model->getErrors('refresh_token'));
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testRenew() {
 | 
			
		||||
        $model = new RefreshTokenForm();
 | 
			
		||||
        $model->refresh_token = $this->tester->grabFixture('sessions', 'admin')['refresh_token'];
 | 
			
		||||
        $this->assertInstanceOf(RenewResult::class, $model->renew());
 | 
			
		||||
        $this->assertInstanceOf(AuthenticationResult::class, $model->renew());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,12 +8,13 @@ use common\models\Account;
 | 
			
		||||
use common\models\EmailActivation;
 | 
			
		||||
use common\models\UsernameHistory;
 | 
			
		||||
use GuzzleHttp\ClientInterface;
 | 
			
		||||
use ReflectionClass;
 | 
			
		||||
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 tests\codeception\common\helpers\Mock;
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\validators\EmailValidator;
 | 
			
		||||
use yii\web\Request;
 | 
			
		||||
use const common\LATEST_RULES_VERSION;
 | 
			
		||||
 | 
			
		||||
@@ -59,6 +60,7 @@ class RegistrationFormTest extends TestCase {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testSignup() {
 | 
			
		||||
        Mock::func(EmailValidator::class, 'checkdnsrr')->andReturnTrue();
 | 
			
		||||
        $model = new RegistrationForm([
 | 
			
		||||
            'username' => 'some_username',
 | 
			
		||||
            'email' => 'some_email@example.com',
 | 
			
		||||
@@ -75,6 +77,7 @@ class RegistrationFormTest extends TestCase {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testSignupWithDefaultLanguage() {
 | 
			
		||||
        Mock::func(EmailValidator::class, 'checkdnsrr')->andReturnTrue();
 | 
			
		||||
        $model = new RegistrationForm([
 | 
			
		||||
            'username' => 'some_username',
 | 
			
		||||
            'email' => 'some_email@example.com',
 | 
			
		||||
 
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace codeception\api\unit\models\profile;
 | 
			
		||||
 | 
			
		||||
use api\models\profile\AcceptRulesForm;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use tests\codeception\common\fixtures\AccountFixture;
 | 
			
		||||
use const common\LATEST_RULES_VERSION;
 | 
			
		||||
 | 
			
		||||
class AcceptRulesFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function _fixtures() {
 | 
			
		||||
        return [
 | 
			
		||||
            'accounts' => AccountFixture::class,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testAgreeWithLatestRules() {
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        $account = Account::findOne($this->tester->grabFixture('accounts', 'account-with-old-rules-version'));
 | 
			
		||||
        $model = new AcceptRulesForm($account);
 | 
			
		||||
        $this->assertTrue($model->agreeWithLatestRules());
 | 
			
		||||
        $this->assertEquals(LATEST_RULES_VERSION, $account->rules_agreement_version);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace codeception\api\unit\models\profile;
 | 
			
		||||
 | 
			
		||||
use api\models\profile\ChangeLanguageForm;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use tests\codeception\common\fixtures\AccountFixture;
 | 
			
		||||
 | 
			
		||||
class ChangeLanguageFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function _fixtures() {
 | 
			
		||||
        return [
 | 
			
		||||
            'accounts' => AccountFixture::class
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testApplyLanguage() {
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        $account = $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
        $model = new ChangeLanguageForm($account);
 | 
			
		||||
        $model->lang = 'ru';
 | 
			
		||||
        $this->assertTrue($model->applyLanguage());
 | 
			
		||||
        $this->assertEquals('ru', $account->lang);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,135 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\models\profile;
 | 
			
		||||
 | 
			
		||||
use api\components\User\Component;
 | 
			
		||||
use api\models\AccountIdentity;
 | 
			
		||||
use api\models\profile\ChangePasswordForm;
 | 
			
		||||
use Codeception\Specify;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\AccountSession;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use tests\codeception\common\fixtures\AccountFixture;
 | 
			
		||||
use tests\codeception\common\fixtures\AccountSessionFixture;
 | 
			
		||||
use Yii;
 | 
			
		||||
 | 
			
		||||
class ChangePasswordFormTest extends TestCase {
 | 
			
		||||
    use Specify;
 | 
			
		||||
 | 
			
		||||
    public function _fixtures() {
 | 
			
		||||
        return [
 | 
			
		||||
            'accounts' => AccountFixture::class,
 | 
			
		||||
            'accountSessions' => AccountSessionFixture::class,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testValidatePasswordAndRePasswordMatch() {
 | 
			
		||||
        $this->specify('error.rePassword_does_not_match expected if passwords not match', function() {
 | 
			
		||||
            $account = new Account();
 | 
			
		||||
            $account->setPassword('12345678');
 | 
			
		||||
            $model = new ChangePasswordForm($account, [
 | 
			
		||||
                'password' => '12345678',
 | 
			
		||||
                'newPassword' => 'my-new-password',
 | 
			
		||||
                'newRePassword' => 'another-password',
 | 
			
		||||
            ]);
 | 
			
		||||
            $model->validatePasswordAndRePasswordMatch('newRePassword');
 | 
			
		||||
            expect($model->getErrors('newRePassword'))->equals(['error.rePassword_does_not_match']);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->specify('no errors expected if passwords are valid', function() {
 | 
			
		||||
            $account = new Account();
 | 
			
		||||
            $account->setPassword('12345678');
 | 
			
		||||
            $model = new ChangePasswordForm($account, [
 | 
			
		||||
                'password' => '12345678',
 | 
			
		||||
                'newPassword' => 'my-new-password',
 | 
			
		||||
                'newRePassword' => 'my-new-password',
 | 
			
		||||
            ]);
 | 
			
		||||
            $model->validatePasswordAndRePasswordMatch('newRePassword');
 | 
			
		||||
            expect($model->getErrors('newRePassword'))->isEmpty();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->specify('error.rePassword_does_not_match expected even if there are errors on other attributes', function() {
 | 
			
		||||
            // this is very important, because password change flow may be combined of two steps
 | 
			
		||||
            // therefore we need to validate password sameness before we will validate current account password
 | 
			
		||||
            $account = new Account();
 | 
			
		||||
            $account->setPassword('12345678');
 | 
			
		||||
            $model = new ChangePasswordForm($account, [
 | 
			
		||||
                'newPassword' => 'my-new-password',
 | 
			
		||||
                'newRePassword' => 'another-password',
 | 
			
		||||
            ]);
 | 
			
		||||
            $model->validate();
 | 
			
		||||
            expect($model->getErrors('newRePassword'))->equals(['error.rePassword_does_not_match']);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testChangePassword() {
 | 
			
		||||
        $this->specify('successfully change password with modern hash strategy', function() {
 | 
			
		||||
            /** @var Account $account */
 | 
			
		||||
            $account = Account::findOne($this->tester->grabFixture('accounts', 'admin')['id']);
 | 
			
		||||
            $model = new ChangePasswordForm($account, [
 | 
			
		||||
                'password' => 'password_0',
 | 
			
		||||
                'newPassword' => 'my-new-password',
 | 
			
		||||
                'newRePassword' => 'my-new-password',
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
            $callTime = time();
 | 
			
		||||
            expect('form should return true', $model->changePassword())->true();
 | 
			
		||||
            expect('new password should be successfully stored into account', $account->validatePassword('my-new-password'))->true();
 | 
			
		||||
            expect('password change time updated', $account->password_changed_at)->greaterOrEquals($callTime);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->specify('successfully change password with legacy hash strategy', function() {
 | 
			
		||||
            /** @var Account $account */
 | 
			
		||||
            $account = Account::findOne($this->tester->grabFixture('accounts', 'user-with-old-password-type')['id']);
 | 
			
		||||
            $model = new ChangePasswordForm($account, [
 | 
			
		||||
                'password' => '12345678',
 | 
			
		||||
                'newPassword' => 'my-new-password',
 | 
			
		||||
                'newRePassword' => 'my-new-password',
 | 
			
		||||
            ]);
 | 
			
		||||
 | 
			
		||||
            $callTime = time();
 | 
			
		||||
            expect($model->changePassword())->true();
 | 
			
		||||
            expect($account->validatePassword('my-new-password'))->true();
 | 
			
		||||
            expect($account->password_changed_at)->greaterOrEquals($callTime);
 | 
			
		||||
            expect($account->password_hash_strategy)->equals(Account::PASS_HASH_STRATEGY_YII2);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testChangePasswordWithLogout() {
 | 
			
		||||
        /** @var Component|\PHPUnit_Framework_MockObject_MockObject $component */
 | 
			
		||||
        $component = $this->getMockBuilder(Component::class)
 | 
			
		||||
            ->setMethods(['getActiveSession', 'terminateSessions'])
 | 
			
		||||
            ->setConstructorArgs([[
 | 
			
		||||
                'identityClass' => AccountIdentity::class,
 | 
			
		||||
                'enableSession' => false,
 | 
			
		||||
                'loginUrl' => null,
 | 
			
		||||
                'secret' => 'secret',
 | 
			
		||||
            ]])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        /** @var AccountSession $session */
 | 
			
		||||
        $session = AccountSession::findOne($this->tester->grabFixture('accountSessions', 'admin2')['id']);
 | 
			
		||||
 | 
			
		||||
        $component
 | 
			
		||||
            ->expects($this->any())
 | 
			
		||||
            ->method('getActiveSession')
 | 
			
		||||
            ->will($this->returnValue($session));
 | 
			
		||||
 | 
			
		||||
        $component
 | 
			
		||||
            ->expects($this->once())
 | 
			
		||||
            ->method('terminateSessions');
 | 
			
		||||
 | 
			
		||||
        Yii::$app->set('user', $component);
 | 
			
		||||
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        $account = $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
        $model = new ChangePasswordForm($account, [
 | 
			
		||||
            'password' => 'password_0',
 | 
			
		||||
            'newPassword' => 'my-new-password',
 | 
			
		||||
            'newRePassword' => 'my-new-password',
 | 
			
		||||
            'logoutAll' => true,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $this->assertTrue($model->changePassword());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,208 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\unit\models\profile;
 | 
			
		||||
 | 
			
		||||
use api\components\User\Component;
 | 
			
		||||
use api\models\AccountIdentity;
 | 
			
		||||
use api\models\profile\TwoFactorAuthForm;
 | 
			
		||||
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;
 | 
			
		||||
use Yii;
 | 
			
		||||
 | 
			
		||||
class TwoFactorAuthFormTest extends TestCase {
 | 
			
		||||
    use ProtectedCaller;
 | 
			
		||||
 | 
			
		||||
    public function testGetCredentials() {
 | 
			
		||||
        /** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
 | 
			
		||||
        $account = $this->getMockBuilder(Account::class)
 | 
			
		||||
            ->setMethods(['save'])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        $account->expects($this->once())
 | 
			
		||||
            ->method('save')
 | 
			
		||||
            ->willReturn(true);
 | 
			
		||||
 | 
			
		||||
        $account->email = 'mock@email.com';
 | 
			
		||||
        $account->otp_secret = null;
 | 
			
		||||
 | 
			
		||||
        /** @var TwoFactorAuthForm|\PHPUnit_Framework_MockObject_MockObject $model */
 | 
			
		||||
        $model = $this->getMockBuilder(TwoFactorAuthForm::class)
 | 
			
		||||
            ->setConstructorArgs([$account])
 | 
			
		||||
            ->setMethods(['drawQrCode'])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        $model->expects($this->once())
 | 
			
		||||
            ->method('drawQrCode')
 | 
			
		||||
            ->willReturn('<_/>');
 | 
			
		||||
 | 
			
		||||
        $result = $model->getCredentials();
 | 
			
		||||
        $this->assertTrue(is_array($result));
 | 
			
		||||
        $this->assertArrayHasKey('qr', $result);
 | 
			
		||||
        $this->assertArrayHasKey('uri', $result);
 | 
			
		||||
        $this->assertArrayHasKey('secret', $result);
 | 
			
		||||
        $this->assertNotNull($account->otp_secret);
 | 
			
		||||
        $this->assertEquals($account->otp_secret, $result['secret']);
 | 
			
		||||
        $this->assertEquals('data:image/svg+xml,<_/>', $result['qr']);
 | 
			
		||||
 | 
			
		||||
        /** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
 | 
			
		||||
        $account = $this->getMockBuilder(Account::class)
 | 
			
		||||
            ->setMethods(['save'])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        $account->expects($this->never())
 | 
			
		||||
            ->method('save');
 | 
			
		||||
 | 
			
		||||
        $account->email = 'mock@email.com';
 | 
			
		||||
        $account->otp_secret = 'some valid totp secret value';
 | 
			
		||||
 | 
			
		||||
        /** @var TwoFactorAuthForm|\PHPUnit_Framework_MockObject_MockObject $model */
 | 
			
		||||
        $model = $this->getMockBuilder(TwoFactorAuthForm::class)
 | 
			
		||||
            ->setConstructorArgs([$account])
 | 
			
		||||
            ->setMethods(['drawQrCode'])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        $model->expects($this->once())
 | 
			
		||||
            ->method('drawQrCode')
 | 
			
		||||
            ->willReturn('this is qr code, trust me');
 | 
			
		||||
 | 
			
		||||
        $result = $model->getCredentials();
 | 
			
		||||
        $this->assertEquals('some valid totp secret value', $result['secret']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testActivate() {
 | 
			
		||||
        /** @var Component|\PHPUnit_Framework_MockObject_MockObject $component */
 | 
			
		||||
        $component = $this->getMockBuilder(Component::class)
 | 
			
		||||
            ->setMethods(['terminateSessions'])
 | 
			
		||||
            ->setConstructorArgs([[
 | 
			
		||||
                'identityClass' => AccountIdentity::class,
 | 
			
		||||
                'enableSession' => false,
 | 
			
		||||
                'loginUrl' => null,
 | 
			
		||||
                'secret' => 'secret',
 | 
			
		||||
            ]])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        $component
 | 
			
		||||
            ->expects($this->once())
 | 
			
		||||
            ->method('terminateSessions');
 | 
			
		||||
 | 
			
		||||
        Yii::$app->set('user', $component);
 | 
			
		||||
 | 
			
		||||
        /** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
 | 
			
		||||
        $account = $this->getMockBuilder(Account::class)
 | 
			
		||||
            ->setMethods(['save'])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        $account->expects($this->once())
 | 
			
		||||
            ->method('save')
 | 
			
		||||
            ->willReturn(true);
 | 
			
		||||
 | 
			
		||||
        $account->is_otp_enabled = false;
 | 
			
		||||
        $account->otp_secret = 'mock secret';
 | 
			
		||||
 | 
			
		||||
        /** @var TwoFactorAuthForm|\PHPUnit_Framework_MockObject_MockObject $model */
 | 
			
		||||
        $model = $this->getMockBuilder(TwoFactorAuthForm::class)
 | 
			
		||||
            ->setMethods(['validate'])
 | 
			
		||||
            ->setConstructorArgs([$account, ['scenario' => TwoFactorAuthForm::SCENARIO_ACTIVATE]])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        $model->expects($this->once())
 | 
			
		||||
            ->method('validate')
 | 
			
		||||
            ->willReturn(true);
 | 
			
		||||
 | 
			
		||||
        $this->assertTrue($model->activate());
 | 
			
		||||
        $this->assertTrue($account->is_otp_enabled);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testDisable() {
 | 
			
		||||
        /** @var Account|\PHPUnit_Framework_MockObject_MockObject $account */
 | 
			
		||||
        $account = $this->getMockBuilder(Account::class)
 | 
			
		||||
            ->setMethods(['save'])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        $account->expects($this->once())
 | 
			
		||||
            ->method('save')
 | 
			
		||||
            ->willReturn(true);
 | 
			
		||||
 | 
			
		||||
        $account->is_otp_enabled = true;
 | 
			
		||||
        $account->otp_secret = 'mock secret';
 | 
			
		||||
 | 
			
		||||
        /** @var TwoFactorAuthForm|\PHPUnit_Framework_MockObject_MockObject $model */
 | 
			
		||||
        $model = $this->getMockBuilder(TwoFactorAuthForm::class)
 | 
			
		||||
            ->setMethods(['validate'])
 | 
			
		||||
            ->setConstructorArgs([$account, ['scenario' => TwoFactorAuthForm::SCENARIO_DISABLE]])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        $model->expects($this->once())
 | 
			
		||||
            ->method('validate')
 | 
			
		||||
            ->willReturn(true);
 | 
			
		||||
 | 
			
		||||
        $this->assertTrue($model->disable());
 | 
			
		||||
        $this->assertNull($account->otp_secret);
 | 
			
		||||
        $this->assertFalse($account->is_otp_enabled);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testValidateOtpDisabled() {
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->is_otp_enabled = true;
 | 
			
		||||
        $model = new TwoFactorAuthForm($account);
 | 
			
		||||
        $model->validateOtpDisabled('account');
 | 
			
		||||
        $this->assertEquals([E::OTP_ALREADY_ENABLED], $model->getErrors('account'));
 | 
			
		||||
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->is_otp_enabled = false;
 | 
			
		||||
        $model = new TwoFactorAuthForm($account);
 | 
			
		||||
        $model->validateOtpDisabled('account');
 | 
			
		||||
        $this->assertEmpty($model->getErrors('account'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testValidateOtpEnabled() {
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->is_otp_enabled = false;
 | 
			
		||||
        $model = new TwoFactorAuthForm($account);
 | 
			
		||||
        $model->validateOtpEnabled('account');
 | 
			
		||||
        $this->assertEquals([E::OTP_NOT_ENABLED], $model->getErrors('account'));
 | 
			
		||||
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->is_otp_enabled = true;
 | 
			
		||||
        $model = new TwoFactorAuthForm($account);
 | 
			
		||||
        $model->validateOtpEnabled('account');
 | 
			
		||||
        $this->assertEmpty($model->getErrors('account'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testGetTotp() {
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->otp_secret = 'mock secret';
 | 
			
		||||
        $account->email = 'check@this.email';
 | 
			
		||||
 | 
			
		||||
        $model = new TwoFactorAuthForm($account);
 | 
			
		||||
        $totp = $model->getTotp();
 | 
			
		||||
        $this->assertInstanceOf(TOTP::class, $totp);
 | 
			
		||||
        $this->assertEquals('check@this.email', $totp->getLabel());
 | 
			
		||||
        $this->assertEquals('mock secret', $totp->getSecret());
 | 
			
		||||
        $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));
 | 
			
		||||
        $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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,22 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\unit\modules\accounts\models;
 | 
			
		||||
 | 
			
		||||
use api\modules\accounts\models\AcceptRulesForm;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use const common\LATEST_RULES_VERSION;
 | 
			
		||||
 | 
			
		||||
class AcceptRulesFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function testAgreeWithLatestRules() {
 | 
			
		||||
        /** @var Account|\Mockery\MockInterface $account */
 | 
			
		||||
        $account = mock(Account::class . '[save]');
 | 
			
		||||
        $account->shouldReceive('save')->andReturn(true);
 | 
			
		||||
        $account->rules_agreement_version = LATEST_RULES_VERSION - 1;
 | 
			
		||||
 | 
			
		||||
        $model = new AcceptRulesForm($account);
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
        $this->assertEquals(LATEST_RULES_VERSION, $account->rules_agreement_version);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +1,14 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace codeception\api\unit\models\profile\ChangeEmail;
 | 
			
		||||
namespace tests\codeception\api\unit\modules\accounts\models;
 | 
			
		||||
 | 
			
		||||
use api\models\profile\ChangeEmail\ConfirmNewEmailForm;
 | 
			
		||||
use api\modules\accounts\models\ChangeEmailForm;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\EmailActivation;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use tests\codeception\common\fixtures\AccountFixture;
 | 
			
		||||
use tests\codeception\common\fixtures\EmailActivationFixture;
 | 
			
		||||
 | 
			
		||||
class ConfirmNewEmailFormTest extends TestCase {
 | 
			
		||||
class ChangeEmailFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function _fixtures() {
 | 
			
		||||
        return [
 | 
			
		||||
@@ -21,14 +21,15 @@ class ConfirmNewEmailFormTest extends TestCase {
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        $account = Account::findOne($this->getAccountId());
 | 
			
		||||
        $newEmailConfirmationFixture = $this->tester->grabFixture('emailActivations', 'newEmailConfirmation');
 | 
			
		||||
        $model = new ConfirmNewEmailForm($account, [
 | 
			
		||||
        $model = new ChangeEmailForm($account, [
 | 
			
		||||
            'key' => $newEmailConfirmationFixture['key'],
 | 
			
		||||
        ]);
 | 
			
		||||
        $this->assertTrue($model->changeEmail());
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
        $this->assertNull(EmailActivation::findOne([
 | 
			
		||||
            'account_id' => $account->id,
 | 
			
		||||
            'type' => EmailActivation::TYPE_NEW_EMAIL_CONFIRMATION,
 | 
			
		||||
        ]));
 | 
			
		||||
        /** @noinspection UnserializeExploitsInspection */
 | 
			
		||||
        $data = unserialize($newEmailConfirmationFixture['_data']);
 | 
			
		||||
        $this->assertEquals($data['newEmail'], $account->email);
 | 
			
		||||
        $this->tester->canSeeAmqpMessageIsCreated('events');
 | 
			
		||||
@@ -37,7 +38,7 @@ class ConfirmNewEmailFormTest extends TestCase {
 | 
			
		||||
    public function testCreateTask() {
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        $account = Account::findOne($this->getAccountId());
 | 
			
		||||
        $model = new ConfirmNewEmailForm($account);
 | 
			
		||||
        $model = new ChangeEmailForm($account);
 | 
			
		||||
        $model->createTask(1, 'test1@ely.by', 'test@ely.by');
 | 
			
		||||
        $message = $this->tester->grabLastSentAmqpMessage('events');
 | 
			
		||||
        $body = json_decode($message->getBody(), true);
 | 
			
		||||
@@ -0,0 +1,21 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\unit\modules\accounts\models;
 | 
			
		||||
 | 
			
		||||
use api\modules\accounts\models\ChangeLanguageForm;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
 | 
			
		||||
class ChangeLanguageFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function testApplyLanguage() {
 | 
			
		||||
        /** @var Account|\Mockery\MockInterface $account */
 | 
			
		||||
        $account = mock(Account::class . '[save]');
 | 
			
		||||
        $account->shouldReceive('save')->andReturn(true);
 | 
			
		||||
 | 
			
		||||
        $model = new ChangeLanguageForm($account);
 | 
			
		||||
        $model->lang = 'ru';
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
        $this->assertEquals('ru', $account->lang);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,139 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\unit\modules\accounts\models;
 | 
			
		||||
 | 
			
		||||
use api\components\User\Component;
 | 
			
		||||
use api\components\User\Identity;
 | 
			
		||||
use api\modules\accounts\models\ChangePasswordForm;
 | 
			
		||||
use common\components\UserPass;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\db\Transaction;
 | 
			
		||||
 | 
			
		||||
class ChangePasswordFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function testValidatePasswordAndRePasswordMatch() {
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->setPassword('12345678');
 | 
			
		||||
        $model = new ChangePasswordForm($account, [
 | 
			
		||||
            'password' => '12345678',
 | 
			
		||||
            'newPassword' => 'my-new-password',
 | 
			
		||||
            'newRePassword' => 'another-password',
 | 
			
		||||
        ]);
 | 
			
		||||
        $model->validatePasswordAndRePasswordMatch('newRePassword');
 | 
			
		||||
        $this->assertEquals(
 | 
			
		||||
            [E::NEW_RE_PASSWORD_DOES_NOT_MATCH],
 | 
			
		||||
            $model->getErrors('newRePassword'),
 | 
			
		||||
            'error.rePassword_does_not_match expected if passwords not match'
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->setPassword('12345678');
 | 
			
		||||
        $model = new ChangePasswordForm($account, [
 | 
			
		||||
            'password' => '12345678',
 | 
			
		||||
            'newPassword' => 'my-new-password',
 | 
			
		||||
            'newRePassword' => 'my-new-password',
 | 
			
		||||
        ]);
 | 
			
		||||
        $model->validatePasswordAndRePasswordMatch('newRePassword');
 | 
			
		||||
        $this->assertEmpty($model->getErrors('newRePassword'), 'no errors expected if passwords are valid');
 | 
			
		||||
 | 
			
		||||
        // this is very important, because password change flow may be combined of two steps
 | 
			
		||||
        // therefore we need to validate password sameness before we will validate current account password
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->setPassword('12345678');
 | 
			
		||||
        $model = new ChangePasswordForm($account, [
 | 
			
		||||
            'newPassword' => 'my-new-password',
 | 
			
		||||
            'newRePassword' => 'another-password',
 | 
			
		||||
        ]);
 | 
			
		||||
        $model->validate();
 | 
			
		||||
        $this->assertEquals(
 | 
			
		||||
            [E::NEW_RE_PASSWORD_DOES_NOT_MATCH],
 | 
			
		||||
            $model->getErrors('newRePassword'),
 | 
			
		||||
            'error.rePassword_does_not_match expected even if there are errors on other attributes'
 | 
			
		||||
        );
 | 
			
		||||
        $this->assertEmpty($model->getErrors('password'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testPerformAction() {
 | 
			
		||||
        $component = mock(Component::class . '[terminateSessions]', [[
 | 
			
		||||
            'identityClass' => Identity::class,
 | 
			
		||||
            'enableSession' => false,
 | 
			
		||||
            'loginUrl' => null,
 | 
			
		||||
            'secret' => 'secret',
 | 
			
		||||
        ]]);
 | 
			
		||||
        $component->shouldNotReceive('terminateSessions');
 | 
			
		||||
 | 
			
		||||
        Yii::$app->set('user', $component);
 | 
			
		||||
 | 
			
		||||
        $transaction = mock(Transaction::class . '[commit]');
 | 
			
		||||
        $transaction->shouldReceive('commit');
 | 
			
		||||
        $connection = mock(Yii::$app->db);
 | 
			
		||||
        $connection->shouldReceive('beginTransaction')->andReturn($transaction);
 | 
			
		||||
 | 
			
		||||
        Yii::$app->set('db', $connection);
 | 
			
		||||
 | 
			
		||||
        /** @var Account|\Mockery\MockInterface $account */
 | 
			
		||||
        $account = mock(Account::class . '[save]');
 | 
			
		||||
        $account->shouldReceive('save')->andReturn(true);
 | 
			
		||||
        $account->setPassword('password_0');
 | 
			
		||||
 | 
			
		||||
        $model = new ChangePasswordForm($account, [
 | 
			
		||||
            'password' => 'password_0',
 | 
			
		||||
            'newPassword' => 'my-new-password',
 | 
			
		||||
            'newRePassword' => 'my-new-password',
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $callTime = time();
 | 
			
		||||
        $this->assertTrue($model->performAction(), 'successfully change password with modern hash strategy');
 | 
			
		||||
        $this->assertTrue($account->validatePassword('my-new-password'), 'new password should be successfully stored into account');
 | 
			
		||||
        $this->assertGreaterThanOrEqual($callTime, $account->password_changed_at, 'password change time updated');
 | 
			
		||||
 | 
			
		||||
        /** @var Account|\Mockery\MockInterface $account */
 | 
			
		||||
        $account = mock(Account::class . '[save]');
 | 
			
		||||
        $account->shouldReceive('save')->andReturn(true);
 | 
			
		||||
        $account->email = 'mock@ely.by';
 | 
			
		||||
        $account->password_hash_strategy = Account::PASS_HASH_STRATEGY_OLD_ELY;
 | 
			
		||||
        $account->password_hash = UserPass::make($account->email, '12345678');
 | 
			
		||||
 | 
			
		||||
        $model = new ChangePasswordForm($account, [
 | 
			
		||||
            'password' => '12345678',
 | 
			
		||||
            'newPassword' => 'my-new-password',
 | 
			
		||||
            'newRePassword' => 'my-new-password',
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $callTime = time();
 | 
			
		||||
        $this->assertTrue($model->performAction(), 'successfully change password with legacy hash strategy');
 | 
			
		||||
        $this->assertTrue($account->validatePassword('my-new-password'));
 | 
			
		||||
        $this->assertGreaterThanOrEqual($callTime, $account->password_changed_at);
 | 
			
		||||
        $this->assertEquals(Account::PASS_HASH_STRATEGY_YII2, $account->password_hash_strategy);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testPerformActionWithLogout() {
 | 
			
		||||
        /** @var Account|\Mockery\MockInterface $account */
 | 
			
		||||
        $account = mock(Account::class . '[save]');
 | 
			
		||||
        $account->shouldReceive('save')->andReturn(true);
 | 
			
		||||
        $account->setPassword('password_0');
 | 
			
		||||
 | 
			
		||||
        /** @var Component|\Mockery\MockInterface $component */
 | 
			
		||||
        $component = mock(Component::class . '[terminateSessions]', [[
 | 
			
		||||
            'identityClass' => Identity::class,
 | 
			
		||||
            'enableSession' => false,
 | 
			
		||||
            'loginUrl' => null,
 | 
			
		||||
            'secret' => 'secret',
 | 
			
		||||
        ]]);
 | 
			
		||||
        $component->shouldReceive('terminateSessions')->once()->withArgs([$account, Component::KEEP_CURRENT_SESSION]);
 | 
			
		||||
 | 
			
		||||
        Yii::$app->set('user', $component);
 | 
			
		||||
 | 
			
		||||
        $model = new ChangePasswordForm($account, [
 | 
			
		||||
            'password' => 'password_0',
 | 
			
		||||
            'newPassword' => 'my-new-password',
 | 
			
		||||
            'newRePassword' => 'my-new-password',
 | 
			
		||||
            'logoutAll' => true,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,18 +1,14 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\models\profile;
 | 
			
		||||
namespace tests\codeception\api\unit\modules\accounts\models;
 | 
			
		||||
 | 
			
		||||
use api\models\AccountIdentity;
 | 
			
		||||
use api\models\profile\ChangeUsernameForm;
 | 
			
		||||
use Codeception\Specify;
 | 
			
		||||
use api\modules\accounts\models\ChangeUsernameForm;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\UsernameHistory;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use tests\codeception\common\fixtures\AccountFixture;
 | 
			
		||||
use tests\codeception\common\fixtures\UsernameHistoryFixture;
 | 
			
		||||
use Yii;
 | 
			
		||||
 | 
			
		||||
class ChangeUsernameFormTest extends TestCase {
 | 
			
		||||
    use Specify;
 | 
			
		||||
 | 
			
		||||
    public function _fixtures() {
 | 
			
		||||
        return [
 | 
			
		||||
@@ -21,23 +17,18 @@ class ChangeUsernameFormTest extends TestCase {
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setUp() {
 | 
			
		||||
        parent::setUp();
 | 
			
		||||
        Yii::$app->user->setIdentity($this->getAccount());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testChange() {
 | 
			
		||||
    public function testPerformAction() {
 | 
			
		||||
        $model = new ChangeUsernameForm($this->getAccount(), [
 | 
			
		||||
            'password' => 'password_0',
 | 
			
		||||
            'username' => 'my_new_nickname',
 | 
			
		||||
        ]);
 | 
			
		||||
        $this->assertTrue($model->change());
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
        $this->assertEquals('my_new_nickname', Account::findOne($this->getAccountId())->username);
 | 
			
		||||
        $this->assertInstanceOf(UsernameHistory::class, UsernameHistory::findOne(['username' => 'my_new_nickname']));
 | 
			
		||||
        $this->tester->canSeeAmqpMessageIsCreated('events');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testChangeWithoutChange() {
 | 
			
		||||
    public function testPerformActionWithTheSameUsername() {
 | 
			
		||||
        $account = $this->getAccount();
 | 
			
		||||
        $username = $account->username;
 | 
			
		||||
        $model = new ChangeUsernameForm($account, [
 | 
			
		||||
@@ -45,7 +36,7 @@ class ChangeUsernameFormTest extends TestCase {
 | 
			
		||||
            'username' => $username,
 | 
			
		||||
        ]);
 | 
			
		||||
        $callTime = time();
 | 
			
		||||
        $this->assertTrue($model->change());
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
        $this->assertNull(UsernameHistory::findOne([
 | 
			
		||||
            'AND',
 | 
			
		||||
            'username' => $username,
 | 
			
		||||
@@ -54,13 +45,13 @@ class ChangeUsernameFormTest extends TestCase {
 | 
			
		||||
        $this->tester->cantSeeAmqpMessageIsCreated('events');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testChangeCase() {
 | 
			
		||||
    public function testPerformActionWithChangeCase() {
 | 
			
		||||
        $newUsername = mb_strtoupper($this->tester->grabFixture('accounts', 'admin')['username']);
 | 
			
		||||
        $model = new ChangeUsernameForm($this->getAccount(), [
 | 
			
		||||
            'password' => 'password_0',
 | 
			
		||||
            'username' => $newUsername,
 | 
			
		||||
        ]);
 | 
			
		||||
        $this->assertTrue($model->change());
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
        $this->assertEquals($newUsername, Account::findOne($this->getAccountId())->username);
 | 
			
		||||
        $this->assertInstanceOf(
 | 
			
		||||
            UsernameHistory::class,
 | 
			
		||||
@@ -80,12 +71,12 @@ class ChangeUsernameFormTest extends TestCase {
 | 
			
		||||
        $this->assertEquals('test', $body['oldUsername']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function getAccount(): AccountIdentity {
 | 
			
		||||
        return AccountIdentity::findOne($this->getAccountId());
 | 
			
		||||
    private function getAccount(): Account {
 | 
			
		||||
        return $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function getAccountId() {
 | 
			
		||||
        return $this->tester->grabFixture('accounts', 'admin')->id;
 | 
			
		||||
        return $this->getAccount()->id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,42 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\unit\modules\accounts\models;
 | 
			
		||||
 | 
			
		||||
use api\modules\accounts\models\DisableTwoFactorAuthForm;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
 | 
			
		||||
class DisableTwoFactorAuthFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function testPerformAction() {
 | 
			
		||||
        /** @var Account|\Mockery\MockInterface $account */
 | 
			
		||||
        $account = mock(Account::class)->makePartial();
 | 
			
		||||
        $account->shouldReceive('save')->once()->andReturn(true);
 | 
			
		||||
 | 
			
		||||
        $account->is_otp_enabled = true;
 | 
			
		||||
        $account->otp_secret = 'mock secret';
 | 
			
		||||
 | 
			
		||||
        /** @var DisableTwoFactorAuthForm|\Mockery\MockInterface $model */
 | 
			
		||||
        $model = mock(DisableTwoFactorAuthForm::class . '[validate]', [$account]);
 | 
			
		||||
        $model->shouldReceive('validate')->once()->andReturn(true);
 | 
			
		||||
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
        $this->assertNull($account->otp_secret);
 | 
			
		||||
        $this->assertFalse($account->is_otp_enabled);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testValidateOtpEnabled() {
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->is_otp_enabled = false;
 | 
			
		||||
        $model = new DisableTwoFactorAuthForm($account);
 | 
			
		||||
        $model->validateOtpEnabled('account');
 | 
			
		||||
        $this->assertEquals([E::OTP_NOT_ENABLED], $model->getErrors('account'));
 | 
			
		||||
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->is_otp_enabled = true;
 | 
			
		||||
        $model = new DisableTwoFactorAuthForm($account);
 | 
			
		||||
        $model->validateOtpEnabled('account');
 | 
			
		||||
        $this->assertEmpty($model->getErrors('account'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,54 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\unit\modules\accounts\models;
 | 
			
		||||
 | 
			
		||||
use api\components\User\Component;
 | 
			
		||||
use api\components\User\Identity;
 | 
			
		||||
use api\modules\accounts\models\EnableTwoFactorAuthForm;
 | 
			
		||||
use common\helpers\Error as E;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use Yii;
 | 
			
		||||
 | 
			
		||||
class EnableTwoFactorAuthFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function testPerformAction() {
 | 
			
		||||
        /** @var Account|\Mockery\MockInterface $account */
 | 
			
		||||
        $account = mock(Account::class . '[save]');
 | 
			
		||||
        $account->shouldReceive('save')->andReturn(true);
 | 
			
		||||
        $account->is_otp_enabled = false;
 | 
			
		||||
        $account->otp_secret = 'mock secret';
 | 
			
		||||
 | 
			
		||||
        /** @var Component|\Mockery\MockInterface $component */
 | 
			
		||||
        $component = mock(Component::class . '[terminateSessions]', [[
 | 
			
		||||
            'identityClass' => Identity::class,
 | 
			
		||||
            'enableSession' => false,
 | 
			
		||||
            'loginUrl' => null,
 | 
			
		||||
            'secret' => 'secret',
 | 
			
		||||
        ]]);
 | 
			
		||||
        $component->shouldReceive('terminateSessions')->withArgs([$account, Component::KEEP_CURRENT_SESSION]);
 | 
			
		||||
 | 
			
		||||
        Yii::$app->set('user', $component);
 | 
			
		||||
 | 
			
		||||
        /** @var EnableTwoFactorAuthForm|\Mockery\MockInterface $model */
 | 
			
		||||
        $model = mock(EnableTwoFactorAuthForm::class . '[validate]', [$account]);
 | 
			
		||||
        $model->shouldReceive('validate')->andReturn(true);
 | 
			
		||||
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
        $this->assertTrue($account->is_otp_enabled);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testValidateOtpDisabled() {
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->is_otp_enabled = true;
 | 
			
		||||
        $model = new EnableTwoFactorAuthForm($account);
 | 
			
		||||
        $model->validateOtpDisabled('account');
 | 
			
		||||
        $this->assertEquals([E::OTP_ALREADY_ENABLED], $model->getErrors('account'));
 | 
			
		||||
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->is_otp_enabled = false;
 | 
			
		||||
        $model = new EnableTwoFactorAuthForm($account);
 | 
			
		||||
        $model->validateOtpDisabled('account');
 | 
			
		||||
        $this->assertEmpty($model->getErrors('account'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace codeception\api\unit\models\profile\ChangeEmail;
 | 
			
		||||
namespace tests\codeception\api\unit\modules\accounts\models;
 | 
			
		||||
 | 
			
		||||
use api\models\profile\ChangeEmail\InitStateForm;
 | 
			
		||||
use api\modules\accounts\models\SendEmailVerificationForm;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\confirmations\CurrentEmailConfirmation;
 | 
			
		||||
use common\models\EmailActivation;
 | 
			
		||||
@@ -9,7 +9,7 @@ use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use tests\codeception\common\fixtures\AccountFixture;
 | 
			
		||||
use tests\codeception\common\fixtures\EmailActivationFixture;
 | 
			
		||||
 | 
			
		||||
class InitStateFormTest extends TestCase {
 | 
			
		||||
class SendEmailVerificationFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function _fixtures() {
 | 
			
		||||
        return [
 | 
			
		||||
@@ -21,7 +21,7 @@ class InitStateFormTest extends TestCase {
 | 
			
		||||
    public function testCreateCode() {
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        $account = $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
        $model = new InitStateForm($account);
 | 
			
		||||
        $model = new SendEmailVerificationForm($account);
 | 
			
		||||
        $activationModel = $model->createCode();
 | 
			
		||||
        $this->assertInstanceOf(CurrentEmailConfirmation::class, $activationModel);
 | 
			
		||||
        $this->assertEquals($account->id, $activationModel->account_id);
 | 
			
		||||
@@ -31,10 +31,10 @@ class InitStateFormTest extends TestCase {
 | 
			
		||||
    public function testSendCurrentEmailConfirmation() {
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        $account = $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
        $model = new InitStateForm($account, [
 | 
			
		||||
        $model = new SendEmailVerificationForm($account, [
 | 
			
		||||
            'password' => 'password_0',
 | 
			
		||||
        ]);
 | 
			
		||||
        $this->assertTrue($model->sendCurrentEmailConfirmation());
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
        $this->assertTrue(EmailActivation::find()->andWhere([
 | 
			
		||||
            'account_id' => $account->id,
 | 
			
		||||
            'type' => EmailActivation::TYPE_CURRENT_EMAIL_CONFIRMATION,
 | 
			
		||||
@@ -1,15 +1,17 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace codeception\api\unit\models\profile\ChangeEmail;
 | 
			
		||||
namespace tests\codeception\api\unit\modules\accounts\models;
 | 
			
		||||
 | 
			
		||||
use api\models\profile\ChangeEmail\NewEmailForm;
 | 
			
		||||
use api\modules\accounts\models\SendNewEmailVerificationForm;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use common\models\confirmations\NewEmailConfirmation;
 | 
			
		||||
use common\models\EmailActivation;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
use tests\codeception\common\fixtures\AccountFixture;
 | 
			
		||||
use tests\codeception\common\fixtures\EmailActivationFixture;
 | 
			
		||||
use tests\codeception\common\helpers\Mock;
 | 
			
		||||
use yii\validators\EmailValidator;
 | 
			
		||||
 | 
			
		||||
class NewEmailFormTest extends TestCase {
 | 
			
		||||
class SendNewEmailVerificationFormTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function _fixtures() {
 | 
			
		||||
        return [
 | 
			
		||||
@@ -21,7 +23,7 @@ class NewEmailFormTest extends TestCase {
 | 
			
		||||
    public function testCreateCode() {
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        $account = $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
        $model = new NewEmailForm($account);
 | 
			
		||||
        $model = new SendNewEmailVerificationForm($account);
 | 
			
		||||
        $model->email = 'my-new-email@ely.by';
 | 
			
		||||
        $activationModel = $model->createCode();
 | 
			
		||||
        $this->assertInstanceOf(NewEmailConfirmation::class, $activationModel);
 | 
			
		||||
@@ -33,13 +35,14 @@ class NewEmailFormTest extends TestCase {
 | 
			
		||||
    public function testSendNewEmailConfirmation() {
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        $account = $this->tester->grabFixture('accounts', 'account-with-change-email-init-state');
 | 
			
		||||
        /** @var NewEmailForm $model */
 | 
			
		||||
        /** @var SendNewEmailVerificationForm $model */
 | 
			
		||||
        $key = $this->tester->grabFixture('emailActivations', 'currentChangeEmailConfirmation')['key'];
 | 
			
		||||
        $model = new NewEmailForm($account, [
 | 
			
		||||
        $model = new SendNewEmailVerificationForm($account, [
 | 
			
		||||
            'key' => $key,
 | 
			
		||||
            'email' => 'my-new-email@ely.by',
 | 
			
		||||
        ]);
 | 
			
		||||
        $this->assertTrue($model->sendNewEmailConfirmation());
 | 
			
		||||
        Mock::func(EmailValidator::class, 'checkdnsrr')->andReturn(true);
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
        $this->assertNull(EmailActivation::findOne($key));
 | 
			
		||||
        $this->assertNotNull(EmailActivation::findOne([
 | 
			
		||||
            'account_id' => $account->id,
 | 
			
		||||
@@ -0,0 +1,47 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\unit\modules\accounts\models;
 | 
			
		||||
 | 
			
		||||
use api\modules\accounts\models\TwoFactorAuthInfo;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
 | 
			
		||||
class TwoFactorAuthInfoTest extends TestCase {
 | 
			
		||||
 | 
			
		||||
    public function testGetCredentials() {
 | 
			
		||||
        /** @var Account|\Mockery\MockInterface $account */
 | 
			
		||||
        $account = mock(Account::class . '[save]');
 | 
			
		||||
        $account->shouldReceive('save')->andReturn(true);
 | 
			
		||||
 | 
			
		||||
        $account->email = 'mock@email.com';
 | 
			
		||||
        $account->otp_secret = null;
 | 
			
		||||
 | 
			
		||||
        $model = new TwoFactorAuthInfo($account);
 | 
			
		||||
 | 
			
		||||
        $result = $model->getCredentials();
 | 
			
		||||
        $this->assertTrue(is_array($result));
 | 
			
		||||
        $this->assertArrayHasKey('qr', $result);
 | 
			
		||||
        $this->assertArrayHasKey('uri', $result);
 | 
			
		||||
        $this->assertArrayHasKey('secret', $result);
 | 
			
		||||
        $this->assertSame($account->otp_secret, $result['secret']);
 | 
			
		||||
        $this->assertSame(strtoupper($account->otp_secret), $account->otp_secret);
 | 
			
		||||
        $this->assertStringStartsWith('data:image/svg+xml,<?xml', $result['qr']);
 | 
			
		||||
 | 
			
		||||
        $previous = libxml_use_internal_errors(true);
 | 
			
		||||
        simplexml_load_string(base64_decode($result['qr']));
 | 
			
		||||
        libxml_use_internal_errors($previous);
 | 
			
		||||
        $this->assertEmpty(libxml_get_errors());
 | 
			
		||||
 | 
			
		||||
        /** @var Account|\Mockery\MockInterface $account */
 | 
			
		||||
        $account = mock(Account::class . '[save]');
 | 
			
		||||
        $account->shouldReceive('save')->andReturn(true);
 | 
			
		||||
 | 
			
		||||
        $account->email = 'mock@email.com';
 | 
			
		||||
        $account->otp_secret = 'AAAA';
 | 
			
		||||
 | 
			
		||||
        $model = new TwoFactorAuthInfo($account);
 | 
			
		||||
 | 
			
		||||
        $result = $model->getCredentials();
 | 
			
		||||
        $this->assertEquals('AAAA', $result['secret']);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace codeception\api\unit\modules\authserver\models;
 | 
			
		||||
 | 
			
		||||
use api\models\AccountIdentity;
 | 
			
		||||
use api\models\authentication\LoginForm;
 | 
			
		||||
use api\modules\authserver\models\AuthenticateData;
 | 
			
		||||
use api\modules\authserver\models\AuthenticationForm;
 | 
			
		||||
@@ -117,7 +116,7 @@ class AuthenticationFormTest extends TestCase {
 | 
			
		||||
            ->setMethods(['getAccount'])
 | 
			
		||||
            ->getMock();
 | 
			
		||||
 | 
			
		||||
        $account = new AccountIdentity();
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->username = 'dummy';
 | 
			
		||||
        $account->email = 'dummy@ely.by';
 | 
			
		||||
        $account->status = $status;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
namespace tests\codeception\api\unit\modules\internal\models;
 | 
			
		||||
 | 
			
		||||
use api\modules\internal\helpers\Error as E;
 | 
			
		||||
use api\modules\internal\models\BanForm;
 | 
			
		||||
use api\modules\accounts\models\BanAccountForm;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
 | 
			
		||||
@@ -11,13 +11,13 @@ class BanFormTest extends TestCase {
 | 
			
		||||
    public function testValidateAccountActivity() {
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->status = Account::STATUS_ACTIVE;
 | 
			
		||||
        $form = new BanForm($account);
 | 
			
		||||
        $form = new BanAccountForm($account);
 | 
			
		||||
        $form->validateAccountActivity();
 | 
			
		||||
        $this->assertEmpty($form->getErrors('account'));
 | 
			
		||||
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->status = Account::STATUS_BANNED;
 | 
			
		||||
        $form = new BanForm($account);
 | 
			
		||||
        $form = new BanAccountForm($account);
 | 
			
		||||
        $form->validateAccountActivity();
 | 
			
		||||
        $this->assertEquals([E::ACCOUNT_ALREADY_BANNED], $form->getErrors('account'));
 | 
			
		||||
    }
 | 
			
		||||
@@ -32,8 +32,8 @@ class BanFormTest extends TestCase {
 | 
			
		||||
            ->method('save')
 | 
			
		||||
            ->willReturn(true);
 | 
			
		||||
 | 
			
		||||
        $model = new BanForm($account);
 | 
			
		||||
        $this->assertTrue($model->ban());
 | 
			
		||||
        $model = new BanAccountForm($account);
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
        $this->assertEquals(Account::STATUS_BANNED, $account->status);
 | 
			
		||||
        $this->tester->canSeeAmqpMessageIsCreated('events');
 | 
			
		||||
    }
 | 
			
		||||
@@ -42,14 +42,14 @@ class BanFormTest extends TestCase {
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->id = 3;
 | 
			
		||||
 | 
			
		||||
        $model = new BanForm($account);
 | 
			
		||||
        $model = new BanAccountForm($account);
 | 
			
		||||
        $model->createTask();
 | 
			
		||||
        $message = json_decode($this->tester->grabLastSentAmqpMessage('events')->body, true);
 | 
			
		||||
        $this->assertSame(3, $message['accountId']);
 | 
			
		||||
        $this->assertSame(-1, $message['duration']);
 | 
			
		||||
        $this->assertSame('', $message['message']);
 | 
			
		||||
 | 
			
		||||
        $model = new BanForm($account);
 | 
			
		||||
        $model = new BanAccountForm($account);
 | 
			
		||||
        $model->duration = 123;
 | 
			
		||||
        $model->message = 'test';
 | 
			
		||||
        $model->createTask();
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
namespace tests\codeception\api\unit\modules\internal\models;
 | 
			
		||||
 | 
			
		||||
use api\modules\internal\helpers\Error as E;
 | 
			
		||||
use api\modules\internal\models\PardonForm;
 | 
			
		||||
use api\modules\accounts\models\PardonAccountForm;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
use tests\codeception\api\unit\TestCase;
 | 
			
		||||
 | 
			
		||||
@@ -11,13 +11,13 @@ class PardonFormTest extends TestCase {
 | 
			
		||||
    public function testValidateAccountBanned() {
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->status = Account::STATUS_BANNED;
 | 
			
		||||
        $form = new PardonForm($account);
 | 
			
		||||
        $form = new PardonAccountForm($account);
 | 
			
		||||
        $form->validateAccountBanned();
 | 
			
		||||
        $this->assertEmpty($form->getErrors('account'));
 | 
			
		||||
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->status = Account::STATUS_ACTIVE;
 | 
			
		||||
        $form = new PardonForm($account);
 | 
			
		||||
        $form = new PardonAccountForm($account);
 | 
			
		||||
        $form->validateAccountBanned();
 | 
			
		||||
        $this->assertEquals([E::ACCOUNT_NOT_BANNED], $form->getErrors('account'));
 | 
			
		||||
    }
 | 
			
		||||
@@ -33,8 +33,8 @@ class PardonFormTest extends TestCase {
 | 
			
		||||
            ->willReturn(true);
 | 
			
		||||
 | 
			
		||||
        $account->status = Account::STATUS_BANNED;
 | 
			
		||||
        $model = new PardonForm($account);
 | 
			
		||||
        $this->assertTrue($model->pardon());
 | 
			
		||||
        $model = new PardonAccountForm($account);
 | 
			
		||||
        $this->assertTrue($model->performAction());
 | 
			
		||||
        $this->assertEquals(Account::STATUS_ACTIVE, $account->status);
 | 
			
		||||
        $this->tester->canSeeAmqpMessageIsCreated('events');
 | 
			
		||||
    }
 | 
			
		||||
@@ -43,7 +43,7 @@ class PardonFormTest extends TestCase {
 | 
			
		||||
        $account = new Account();
 | 
			
		||||
        $account->id = 3;
 | 
			
		||||
 | 
			
		||||
        $model = new PardonForm($account);
 | 
			
		||||
        $model = new PardonAccountForm($account);
 | 
			
		||||
        $model->createTask();
 | 
			
		||||
        $message = json_decode($this->tester->grabLastSentAmqpMessage('events')->body, true);
 | 
			
		||||
        $this->assertSame(3, $message['accountId']);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace tests\codeception\api\traits;
 | 
			
		||||
 | 
			
		||||
use api\models\AccountIdentity;
 | 
			
		||||
use api\traits\AccountFinder;
 | 
			
		||||
use Codeception\Specify;
 | 
			
		||||
use common\models\Account;
 | 
			
		||||
@@ -18,50 +17,27 @@ class AccountFinderTest extends TestCase {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testGetAccount() {
 | 
			
		||||
        $this->specify('founded account for passed login data', function() {
 | 
			
		||||
            $model = new AccountFinderTestTestClass();
 | 
			
		||||
            /** @var Account $account */
 | 
			
		||||
            $account = $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
            $model->login = $account->email;
 | 
			
		||||
            $account = $model->getAccount();
 | 
			
		||||
            expect($account)->isInstanceOf(Account::class);
 | 
			
		||||
            expect($account->id)->equals($account->id);
 | 
			
		||||
        });
 | 
			
		||||
        $model = new AccountFinderTestTestClass();
 | 
			
		||||
        /** @var Account $account */
 | 
			
		||||
        $accountFixture = $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
        $model->login = $accountFixture->email;
 | 
			
		||||
        $account = $model->getAccount();
 | 
			
		||||
        $this->assertInstanceOf(Account::class, $account);
 | 
			
		||||
        $this->assertSame($accountFixture->id, $account->id, 'founded account for passed login data');
 | 
			
		||||
 | 
			
		||||
        $this->specify('founded account for passed login data with changed account model class name', function() {
 | 
			
		||||
            /** @var AccountFinderTestTestClass $model */
 | 
			
		||||
            $model = new class extends AccountFinderTestTestClass {
 | 
			
		||||
                protected function getAccountClassName() {
 | 
			
		||||
                    return AccountIdentity::class;
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            /** @var Account $account */
 | 
			
		||||
            $account = $this->tester->grabFixture('accounts', 'admin');
 | 
			
		||||
            $model->login = $account->email;
 | 
			
		||||
            $account = $model->getAccount();
 | 
			
		||||
            expect($account)->isInstanceOf(AccountIdentity::class);
 | 
			
		||||
            expect($account->id)->equals($account->id);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        $this->specify('null, if account not founded', function() {
 | 
			
		||||
            $model = new AccountFinderTestTestClass();
 | 
			
		||||
            $model->login = 'unexpected';
 | 
			
		||||
            expect($account = $model->getAccount())->null();
 | 
			
		||||
        });
 | 
			
		||||
        $model = new AccountFinderTestTestClass();
 | 
			
		||||
        $model->login = 'unexpected';
 | 
			
		||||
        $this->assertNull($account = $model->getAccount(), 'null, if account can\'t be found');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function testGetLoginAttribute() {
 | 
			
		||||
        $this->specify('if login look like email value, then \'email\'', function() {
 | 
			
		||||
            $model = new AccountFinderTestTestClass();
 | 
			
		||||
            $model->login = 'erickskrauch@ely.by';
 | 
			
		||||
            expect($model->getLoginAttribute())->equals('email');
 | 
			
		||||
        });
 | 
			
		||||
        $model = new AccountFinderTestTestClass();
 | 
			
		||||
        $model->login = 'erickskrauch@ely.by';
 | 
			
		||||
        $this->assertEquals('email', $model->getLoginAttribute(), 'if login look like email value, then \'email\'');
 | 
			
		||||
 | 
			
		||||
        $this->specify('username in any other case', function() {
 | 
			
		||||
            $model = new AccountFinderTestTestClass();
 | 
			
		||||
            $model->login = 'erickskrauch';
 | 
			
		||||
            expect($model->getLoginAttribute())->equals('username');
 | 
			
		||||
        });
 | 
			
		||||
        $model = new AccountFinderTestTestClass();
 | 
			
		||||
        $model->login = 'erickskrauch';
 | 
			
		||||
        $this->assertEquals('username', $model->getLoginAttribute(), 'username in any other case');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -71,7 +47,7 @@ class AccountFinderTestTestClass {
 | 
			
		||||
 | 
			
		||||
    public $login;
 | 
			
		||||
 | 
			
		||||
    public function getLogin() {
 | 
			
		||||
    public function getLogin(): string {
 | 
			
		||||
        return $this->login;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user