-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow protection of access tokens before device token unpaid
This protection is necessary to prevent unwanted unpairing of backend-created access tokens serving for device-inapp purchase connection. Commit covers scenario: - Login with device token - Verify inapp purchase - Logout (device is still linked to the purchase thanks to backend-only created access token during logout process) - Login with other account At this point, device should still be able to access the content, but without the protection implemented here it wouldn't. remp/crm#1494
- Loading branch information
Showing
5 changed files
with
142 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?php | ||
|
||
namespace Crm\GooglePlayBillingModule\DataProviders; | ||
|
||
use Crm\GooglePlayBillingModule\GooglePlayBillingModule; | ||
use Crm\UsersModule\DataProvider\AccessTokenDataProviderInterface; | ||
use Nette\Database\Table\IRow; | ||
|
||
class AccessTokenDataProvider implements AccessTokenDataProviderInterface | ||
{ | ||
public function canUnpairDeviceToken(IRow $accessToken, IRow $deviceToken): bool | ||
{ | ||
if ($accessToken->source === GooglePlayBillingModule::USER_SOURCE_APP) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
public function provide(array $params) | ||
{ | ||
throw new \Exception('AccessTokenDataProvider does not provide generic method results'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
<?php | ||
|
||
namespace Crm\GooglePlayBillingModule\Tests; | ||
|
||
use Crm\ApplicationModule\DataProvider\DataProviderManager; | ||
use Crm\ApplicationModule\Tests\DatabaseTestCase; | ||
use Crm\GooglePlayBillingModule\GooglePlayBillingModule; | ||
use Crm\UsersModule\Repositories\DeviceTokensRepository; | ||
use Crm\UsersModule\Repository\AccessTokensRepository; | ||
use Crm\UsersModule\Repository\UserMetaRepository; | ||
use Crm\UsersModule\Repository\UsersRepository; | ||
use Nette\Utils\Random; | ||
|
||
class AccessTokenDataProviderTest extends DatabaseTestCase | ||
{ | ||
/** @var AccessTokensRepository */ | ||
private $accessTokensRepository; | ||
|
||
/** @var DeviceTokensRepository */ | ||
private $deviceTokensRepository; | ||
|
||
/** @var UsersRepository */ | ||
private $usersRepository; | ||
|
||
protected function requiredRepositories(): array | ||
{ | ||
return [ | ||
UsersRepository::class, | ||
UserMetaRepository::class, | ||
DeviceTokensRepository::class, | ||
AccessTokensRepository::class, | ||
]; | ||
} | ||
|
||
protected function requiredSeeders(): array | ||
{ | ||
return [ | ||
]; | ||
} | ||
|
||
public function setUp(): void | ||
{ | ||
parent::setUp(); | ||
|
||
$this->accessTokensRepository = $this->getRepository(AccessTokensRepository::class); | ||
$this->deviceTokensRepository = $this->getRepository(DeviceTokensRepository::class); | ||
$this->usersRepository = $this->getRepository(UsersRepository::class); | ||
|
||
$dataProviderManager = $this->inject(DataProviderManager::class); | ||
$dataProviderManager->registerDataProvider( | ||
'users.dataprovider.access_tokens', | ||
$this->inject(\Crm\GooglePlayBillingModule\DataProviders\AccessTokenDataProvider::class) | ||
); | ||
} | ||
|
||
public function testUnprotectedUnpairing() | ||
{ | ||
$deviceToken = $this->deviceTokensRepository->generate('foo'); | ||
|
||
// pair users | ||
$user1 = $this->getUser(); | ||
$accessToken1 = $this->accessTokensRepository->add($user1); | ||
$this->accessTokensRepository->pairWithDeviceToken($accessToken1, $deviceToken); | ||
$user2 = $this->getUser(); | ||
$accessToken2 = $this->accessTokensRepository->add($user2); | ||
$this->accessTokensRepository->pairWithDeviceToken($accessToken2, $deviceToken); | ||
|
||
// unpair token | ||
$this->accessTokensRepository->unpairDeviceToken($deviceToken); | ||
|
||
// regular unpairing should get rid of all access tokens linked to the device | ||
$this->assertCount( | ||
0, | ||
$this->accessTokensRepository->findAllByDeviceToken($deviceToken) | ||
); | ||
} | ||
|
||
public function testProtectedUnpairing() | ||
{ | ||
$deviceToken = $this->deviceTokensRepository->generate('foo'); | ||
|
||
// pair users, protected second | ||
$user1 = $this->getUser(); | ||
$accessToken1 = $this->accessTokensRepository->add($user1); | ||
$this->accessTokensRepository->pairWithDeviceToken($accessToken1, $deviceToken); | ||
$user2 = $this->getUser(); | ||
$accessToken2 = $this->accessTokensRepository->add($user2, 3, GooglePlayBillingModule::USER_SOURCE_APP); | ||
$this->accessTokensRepository->pairWithDeviceToken($accessToken2, $deviceToken); | ||
|
||
// unpair token | ||
$this->accessTokensRepository->unpairDeviceToken($deviceToken); | ||
|
||
// unpairing should get rid of the one access token without Google source | ||
$this->assertCount( | ||
1, | ||
$this->accessTokensRepository->findAllByDeviceToken($deviceToken) | ||
); | ||
} | ||
|
||
private function getUser() | ||
{ | ||
return $this->usersRepository->add('user_' . Random::generate() . '@example.com', 'secret', '', ''); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters