* [ADD] Unit testing. Work in progress

* [MOD] Improved Public Links key generation
* [MOD] Code refactoring
This commit is contained in:
nuxsmin
2018-07-22 19:31:00 +02:00
parent 1bcfb6db49
commit 0f2e4e7119
13 changed files with 1078 additions and 75 deletions

View File

@@ -195,7 +195,7 @@ class AccountController extends ControllerBase implements CrudControllerInterfac
$vault = unserialize($publicLinkData->getData());
/** @var AccountExtData $accountData */
$accountData = Util::unserialize(AccountExtData::class, $vault->getData(PublicLinkService::getKeyForHash($this->config->getConfigData()->getPasswordSalt(), $publicLinkData)));
$accountData = Util::unserialize(AccountExtData::class, $vault->getData($publicLinkService->getPublicLinkKey($publicLinkData->getHash())->getKey()));
$this->view->assign('title',
[

View File

@@ -29,7 +29,6 @@ use SP\Core\Exceptions\ValidationException;
use SP\DataModel\PublicLinkData;
use SP\Mgmt\PublicLinks\PublicLink;
use SP\Services\PublicLink\PublicLinkService;
use SP\Util\Util;
/**
* Class PublicLinkForm
@@ -68,7 +67,6 @@ class PublicLinkForm extends FormBase implements FormInterface
* Analizar los datos de la petición HTTP
*
* @return void
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
*/
protected function analyzeRequestData()
{
@@ -77,7 +75,6 @@ class PublicLinkForm extends FormBase implements FormInterface
$this->publicLinkData->setTypeId(PublicLinkService::TYPE_ACCOUNT);
$this->publicLinkData->setItemId($this->request->analyzeInt('accountId'));
$this->publicLinkData->setNotify($this->request->analyzeBool('notify', false));
$this->publicLinkData->setHash(Util::generateRandomBytes());
}
/**

View File

@@ -209,7 +209,7 @@ class PluginRepository extends Repository implements RepositoryItemInterface
$queryData = new QueryData();
$queryData->setQuery('DELETE FROM Plugin WHERE id IN (' . $this->getParamsFromArray($ids) . ')');
$queryData->setParams($ids);
$queryData->setOnErrorMessage(__u('Error al eliminar el plugin'));
$queryData->setOnErrorMessage(__u('Error al eliminar los plugins'));
return $this->db->doQuery($queryData)->getAffectedNumRows();
}

View File

@@ -170,6 +170,7 @@ class AuthTokenService extends Service
* @param string $token
*
* @return AuthTokenData
* @throws ServiceException
* @throws \Defuse\Crypto\Exception\CryptoException
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
* @throws \SP\Core\Exceptions\ConstraintException

View File

@@ -28,6 +28,7 @@ use SP\Core\Exceptions\SPException;
use SP\DataModel\ItemData;
use SP\DataModel\ItemSearchData;
use SP\DataModel\PluginData;
use SP\Repositories\NoSuchItemException;
use SP\Repositories\Plugin\PluginRepository;
use SP\Services\Service;
use SP\Services\ServiceException;
@@ -81,10 +82,17 @@ class PluginService extends Service
* @return PluginData
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws NoSuchItemException
*/
public function getById($id)
{
return $this->pluginRepository->getById($id)->getData();
$result = $this->pluginRepository->getById($id);
if ($result->getNumRows() === 0) {
throw new NoSuchItemException(__u('Plugin no encontrado'), NoSuchItemException::INFO);
}
return $result->getData();
}
/**
@@ -125,7 +133,9 @@ class PluginService extends Service
*/
public function deleteByIdBatch(array $ids)
{
$this->pluginRepository->deleteByIdBatch($ids);
if ($this->pluginRepository->deleteByIdBatch($ids) !== count($ids)) {
throw new ServiceException(__u('Error al eliminar los plugins'));
}
}
/**
@@ -140,7 +150,7 @@ class PluginService extends Service
public function delete($id)
{
if ($this->pluginRepository->delete($id) === 0) {
throw new ServiceException(__u('Plugin no encontrado'), ServiceException::INFO);
throw new NoSuchItemException(__u('Plugin no encontrado'), NoSuchItemException::INFO);
}
}
@@ -164,12 +174,19 @@ class PluginService extends Service
* @param string $name
*
* @return PluginData
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function getByName($name)
{
return $this->pluginRepository->getByName($name)->getData();
$result = $this->pluginRepository->getByName($name);
if ($result->getNumRows() === 0) {
throw new NoSuchItemException(__u('Plugin no encontrado'), NoSuchItemException::INFO);
}
return $result->getData();
}
/**
@@ -178,13 +195,16 @@ class PluginService extends Service
* @param $id
* @param $enabled
*
* @return bool
* @return void
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function toggleEnabled($id, $enabled)
{
return $this->pluginRepository->toggleEnabled($id, $enabled);
if ($this->pluginRepository->toggleEnabled($id, $enabled) === 0) {
throw new NoSuchItemException(__u('Plugin no encontrado'), NoSuchItemException::INFO);
}
}
/**
@@ -193,13 +213,16 @@ class PluginService extends Service
* @param $name
* @param $enabled
*
* @return bool
* @return void
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function toggleEnabledByName($name, $enabled)
{
return $this->pluginRepository->toggleEnabledByName($name, $enabled);
if ($this->pluginRepository->toggleEnabledByName($name, $enabled) === 0) {
throw new NoSuchItemException(__u('Plugin no encontrado'), NoSuchItemException::INFO);
}
}
/**
@@ -208,13 +231,15 @@ class PluginService extends Service
* @param $id
* @param $available
*
* @return bool
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function toggleAvailable($id, $available)
{
return $this->pluginRepository->toggleAvailable($id, $available);
if ($this->pluginRepository->toggleAvailable($id, $available) === 0) {
throw new NoSuchItemException(__u('Plugin no encontrado'), NoSuchItemException::INFO);
}
}
/**
@@ -223,13 +248,15 @@ class PluginService extends Service
* @param $name
* @param $available
*
* @return bool
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function toggleAvailableByName($name, $available)
{
return $this->pluginRepository->toggleAvailableByName($name, $available);
if ($this->pluginRepository->toggleAvailableByName($name, $available) === 0) {
throw new NoSuchItemException(__u('Plugin no encontrado'), NoSuchItemException::INFO);
}
}
/**
@@ -238,12 +265,17 @@ class PluginService extends Service
* @param int $id Id del plugin
*
* @return bool
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function resetById($id)
{
return $this->pluginRepository->resetById($id);
if (($count = $this->pluginRepository->resetById($id)) === 0) {
throw new NoSuchItemException(__u('Plugin no encontrado'), NoSuchItemException::INFO);
}
return $count;
}
/**

View File

@@ -0,0 +1,87 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Services\PublicLink;
use SP\Util\Util;
/**
* Class PublicLinkKey
*
* @package SP\Services\PublicLink
*/
class PublicLinkKey
{
/**
* @var string
*/
private $hash;
/**
* @var string
*/
private $salt;
/**
* PublicLinkKey constructor.
*
* @param string $salt
* @param string $hash
*
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
*/
public function __construct(string $salt, string $hash = null)
{
$this->salt = $salt;
if ($hash === null) {
$this->hash = Util::generateRandomBytes();
} else {
$this->hash = $hash;
}
}
/**
* @return string
*/
public function getKey(): string
{
return sha1($this->salt . $this->hash);
}
/**
* @return string
*/
public function getHash(): string
{
return $this->hash;
}
/**
* @return string
*/
public function getSalt(): string
{
return $this->salt;
}
}

View File

@@ -27,11 +27,11 @@ namespace SP\Services\PublicLink;
use SP\Bootstrap;
use SP\Config\Config;
use SP\Core\Crypt\Crypt;
use SP\Core\Crypt\Session as CryptSession;
use SP\Core\Crypt\Vault;
use SP\Core\Exceptions\SPException;
use SP\DataModel\ItemSearchData;
use SP\DataModel\PublicLinkData;
use SP\DataModel\PublicLinkListData;
use SP\Http\Request;
use SP\Repositories\NoSuchItemException;
use SP\Repositories\PublicLink\PublicLinkRepository;
@@ -40,7 +40,6 @@ use SP\Services\Service;
use SP\Services\ServiceException;
use SP\Services\ServiceItemTrait;
use SP\Storage\Database\QueryResult;
use SP\Util\Util;
/**
* Class PublicLinkService
@@ -86,6 +85,17 @@ class PublicLinkService extends Service
return hash('sha256', uniqid('sysPassPublicLink', true));
}
/**
* @param string $salt
* @param PublicLinkData $publicLinkData
*
* @return string
*/
public static function getKeyForHash($salt, PublicLinkData $publicLinkData)
{
return sha1($salt . $publicLinkData->getHash());
}
/**
* @param ItemSearchData $itemSearchData
*
@@ -106,7 +116,13 @@ class PublicLinkService extends Service
*/
public function getById($id)
{
return $this->publicLinkRepository->getById($id)->getData();
$result = $this->publicLinkRepository->getById($id);
if ($result->getNumRows() === 0) {
throw new NoSuchItemException(__u('Enlace no encontrado'));
}
return $result->getData();
}
/**
@@ -123,18 +139,17 @@ class PublicLinkService extends Service
*/
public function refresh($id)
{
$salt = $this->config->getConfigData()->getPasswordSalt();
$key = self::getNewKey($salt);
$result = $this->publicLinkRepository->getById($id);
if ($result->getNumRows() === 0) {
throw new NoSuchItemException(__u('El enlace no existe'));
throw new NoSuchItemException(__u('Enlace no encontrado'));
}
$key = $this->getPublicLinkKey();
/** @var PublicLinkData $publicLinkData */
$publicLinkData = $result->getData();
$publicLinkData->setHash(self::getHashForKey($key, $salt));
$publicLinkData->setHash($key->getHash());
$publicLinkData->setData($this->getSecuredLinkData($publicLinkData->getItemId(), $key));
$publicLinkData->setDateExpire(self::calcDateExpire($this->config));
$publicLinkData->setCountViews($this->config->getConfigData()->getPublinksMaxViews());
@@ -143,52 +158,39 @@ class PublicLinkService extends Service
}
/**
* @param string $salt
* @param string|null $hash
*
* @return string
* @return PublicLinkKey
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
*/
public static function getNewKey($salt)
public function getPublicLinkKey(string $hash = null)
{
return $salt . Util::generateRandomBytes();
}
/**
* Returns the hash from a composed key
*
* @param string $key
* @param string $salt
*
* @return mixed
*/
public static function getHashForKey($key, $salt)
{
return str_replace($salt, '', $key);
return new PublicLinkKey($this->config->getConfigData()->getPasswordSalt(), $hash);
}
/**
* Obtener los datos de una cuenta y encriptarlos para el enlace
*
* @param int $itemId
* @param string $linkKey
* @param int $itemId
* @param PublicLinkKey $key
*
* @return Vault
* @throws NoSuchItemException
* @throws ServiceException
* @throws \Defuse\Crypto\Exception\CryptoException
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
* @throws SPException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
protected function getSecuredLinkData($itemId, $linkKey)
private function getSecuredLinkData($itemId, PublicLinkKey $key)
{
// Obtener los datos de la cuenta
$accountData = $this->dic->get(AccountService::class)->getDataForLink($itemId);
// Desencriptar la clave de la cuenta
$accountData->setPass(Crypt::decrypt($accountData->getPass(), $accountData->getKey(), CryptSession::getSessionKey($this->context)));
$accountData->setPass(Crypt::decrypt($accountData->getPass(), $accountData->getKey(), $this->getMasterKeyFromContext()));
$accountData->setKey(null);
$vault = new Vault();
return serialize($vault->saveData(serialize($accountData), $linkKey));
return (new Vault())->saveData(serialize($accountData), $key->getKey())->getSerialized();
}
/**
@@ -207,14 +209,14 @@ class PublicLinkService extends Service
* @param $id
*
* @return $this
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\SPException
*/
public function delete($id)
{
if ($this->publicLinkRepository->delete($id) === 0) {
throw new ServiceException(__u('Enlace no encontrado'), ServiceException::INFO);
throw new NoSuchItemException(__u('Enlace no encontrado'), NoSuchItemException::INFO);
}
return $this;
@@ -252,7 +254,10 @@ class PublicLinkService extends Service
*/
public function create(PublicLinkData $itemData)
{
$itemData->setData($this->getSecuredLinkData($itemData->getItemId(), self::getKeyForHash($this->config->getConfigData()->getPasswordSalt(), $itemData)));
$key = $this->getPublicLinkKey();
$itemData->setHash($key->getHash());
$itemData->setData($this->getSecuredLinkData($itemData->getItemId(), $key));
$itemData->setDateExpire(self::calcDateExpire($this->config));
$itemData->setMaxCountViews($this->config->getConfigData()->getPublinksMaxViews());
$itemData->setUserId($this->context->getUserData()->getId());
@@ -260,21 +265,10 @@ class PublicLinkService extends Service
return $this->publicLinkRepository->create($itemData)->getLastId();
}
/**
* @param string $salt
* @param PublicLinkData $publicLinkData
*
* @return string
*/
public static function getKeyForHash($salt, PublicLinkData $publicLinkData)
{
return $salt . $publicLinkData->getHash();
}
/**
* Get all items from the service's repository
*
* @return array
* @return PublicLinkListData[]
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
@@ -288,7 +282,7 @@ class PublicLinkService extends Service
*
* @param PublicLinkData $publicLinkData
*
* @return bool
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
@@ -313,7 +307,9 @@ class PublicLinkService extends Service
// Email::sendEmail($LogMessage);
// }
return $this->publicLinkRepository->addLinkView($publicLinkData);
if ($this->publicLinkRepository->addLinkView($publicLinkData) === 0) {
throw new NoSuchItemException(__u('Enlace no encontrado'));
}
}
/**
@@ -347,7 +343,7 @@ class PublicLinkService extends Service
$result = $this->publicLinkRepository->getByHash($hash);
if ($result->getNumRows() === 0) {
throw new NoSuchItemException(__u('El enlace no existe'));
throw new NoSuchItemException(__u('Enlace no encontrado'));
}
return $result->getData();
@@ -368,7 +364,7 @@ class PublicLinkService extends Service
$result = $this->publicLinkRepository->getHashForItem($itemId);
if ($result->getNumRows() === 0) {
throw new NoSuchItemException(__u('El enlace no existe'));
throw new NoSuchItemException(__u('Enlace no encontrado'));
}
return $result->getData();

View File

@@ -49,8 +49,6 @@ class UpgradePublicLink extends Service
/**
* upgrade_300_18010101
*
* @throws \SP\Core\Exceptions\SPException
*/
public function upgrade_300_18010101()
{

View File

@@ -137,7 +137,7 @@ class PluginRepositoryTest extends DatabaseTestCase
$this->assertEquals(1, $data->getAvailable());
$this->assertEquals(0, $data->getEnabled());
$this->assertEquals(0, self::$repository->getById('Authenticator 2')->getNumRows());
$this->assertEquals(0, self::$repository->getByName('Authenticator 2')->getNumRows());
}
/**
@@ -258,6 +258,16 @@ class PluginRepositoryTest extends DatabaseTestCase
$this->expectException(ConstraintException::class);
self::$repository->create($data);
}
/**
* @depends testGetById
* @throws ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testCreateBlank()
{
$this->expectException(ConstraintException::class);
self::$repository->create(new PluginData());
}

View File

@@ -253,7 +253,7 @@ class PublicLinkRepositoryTest extends DatabaseTestCase
$hash = pack('H*', '313065363937306666653833623531393234356635333433333732626366663433376461623565356134386238326131653238636131356235346635');
$useInfo = [
'who' => '127.0.0.1',
'who' => SELF_IP_ADDRESS,
'time' => time(),
'hash' => $hash,
'agent' => 'Mozilla/Firefox',

View File

@@ -0,0 +1,384 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Tests\Services\Plugin;
use SP\Core\Exceptions\ConstraintException;
use SP\DataModel\ItemData;
use SP\DataModel\ItemSearchData;
use SP\DataModel\PluginData;
use SP\Repositories\NoSuchItemException;
use SP\Services\Plugin\PluginService;
use SP\Services\ServiceException;
use SP\Storage\Database\DatabaseConnectionData;
use SP\Test\DatabaseTestCase;
use function SP\Test\setupContext;
/**
* Class PluginServiceTest
*
* @package SP\Tests\Services\Plugin
*/
class PluginServiceTest extends DatabaseTestCase
{
/**
* @var PluginService
*/
private static $service;
/**
* @throws \DI\NotFoundException
* @throws \SP\Core\Context\ContextException
* @throws \DI\DependencyException
*/
public static function setUpBeforeClass()
{
$dic = setupContext();
self::$dataset = 'syspass_plugin.xml';
// Datos de conexión a la BBDD
self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
// Inicializar el repositorio
self::$service = $dic->get(PluginService::class);
}
/**
* @throws ConstraintException
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testUpdate()
{
$data = new PluginData();
$data->setId(1);
$data->setName('Authenticator 2');
$data->setAvailable(1);
$data->setEnabled(1);
$data->setData('data');
$this->assertEquals(1, self::$service->update($data));
$result = self::$service->getById(1);
$this->assertEquals($data, $result);
$data->setId(null);
$data->setName('Authenticator');
$this->assertEquals(0, self::$service->update($data));
$data->setId(2);
$data->setName('DokuWiki');
$this->expectException(ConstraintException::class);
self::$service->update($data);
}
/**
* @throws ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\SPException
*/
public function testDeleteByIdBatch()
{
self::$service->deleteByIdBatch([1, 2]);
$this->assertEquals(1, $this->conn->getRowCount('Plugin'));
$this->expectException(ServiceException::class);
self::$service->deleteByIdBatch([4]);
}
/**
* @throws ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Repositories\NoSuchItemException
*/
public function testToggleAvailable()
{
self::$service->toggleAvailable(1, 0);
$data = self::$service->getById(1);
$this->assertEquals(0, $data->getAvailable());
$this->expectException(NoSuchItemException::class);
self::$service->toggleAvailable(4, 1);
}
/**
* @throws ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws NoSuchItemException
*/
public function testResetById()
{
$this->assertEquals(1, self::$service->resetById(2));
$data = self::$service->getById(2);
$this->assertNull($data->getData());
$this->expectException(NoSuchItemException::class);
self::$service->resetById(4);
}
/**
* @throws ConstraintException
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testGetByName()
{
$data = self::$service->getByName('Authenticator');
$this->assertInstanceOf(PluginData::class, $data);
$this->assertEquals(1, $data->getId());
$this->assertEquals('Authenticator', $data->getName());
$this->assertNull($data->getData());
$this->assertEquals(1, $data->getAvailable());
$this->assertEquals(0, $data->getEnabled());
$this->expectException(NoSuchItemException::class);
self::$service->getByName('Authenticator 2');
}
/**
* @throws ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\SPException
*/
public function testDelete()
{
self::$service->delete(1);
$this->assertEquals(2, $this->conn->getRowCount('Plugin'));
$this->expectException(NoSuchItemException::class);
self::$service->getById(1);
}
/**
* @throws ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testSearch()
{
$itemSearchData = new ItemSearchData();
$itemSearchData->setLimitCount(10);
$itemSearchData->setSeachString('Auth');
$result = self::$service->search($itemSearchData);
$this->assertEquals(1, $result->getNumRows());
/** @var PluginData[] $data */
$data = $result->getDataAsArray();
$this->assertCount(1, $data);
$this->assertEquals(1, $data[0]->getId());
$this->assertEquals('Authenticator', $data[0]->getName());
$this->assertEquals(0, $data[0]->getEnabled());
$this->assertEquals(1, $data[0]->getAvailable());
$itemSearchData->setSeachString('test');
$result = self::$service->search($itemSearchData);
$this->assertEquals(0, $result->getNumRows());
$itemSearchData->setSeachString('');
$result = self::$service->search($itemSearchData);
$this->assertEquals(3, $result->getNumRows());
}
/**
* @throws ConstraintException
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testGetById()
{
$data = self::$service->getById(1);
$this->assertInstanceOf(PluginData::class, $data);
$this->assertEquals(1, $data->getId());
$this->assertEquals('Authenticator', $data->getName());
$this->assertNull($data->getData());
$this->assertEquals(1, $data->getAvailable());
$this->assertEquals(0, $data->getEnabled());
$this->expectException(NoSuchItemException::class);
self::$service->getById(4);
}
/**
* @throws ConstraintException
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testCreate()
{
$data = new PluginData();
$data->setId(4);
$data->setName('Authenticator 2');
$data->setAvailable(1);
$data->setEnabled(1);
$data->setData('data');
$this->assertEquals(4, self::$service->create($data));
$this->assertEquals($data, self::$service->getById(4));
$this->expectException(ConstraintException::class);
self::$service->create($data);
}
/**
* @throws ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testCreateBlank()
{
$this->expectException(ConstraintException::class);
self::$service->create(new PluginData());
}
/**
* @throws ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testGetEnabled()
{
$data = self::$service->getEnabled();
$this->assertCount(2, $data);
$this->assertInstanceOf(ItemData::class, $data[0]);
$this->assertEquals(2, $data[0]->getId());
$this->assertEquals('XML Exporter', $data[0]->getName());
$this->assertInstanceOf(ItemData::class, $data[1]);
$this->assertEquals(3, $data[1]->getId());
$this->assertEquals('DokuWiki', $data[1]->getName());
}
/**
* @throws ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testGetAll()
{
$data = self::$service->getAll();
$this->assertCount(3, $data);
$this->assertEquals(1, $data[0]->getId());
$this->assertEquals('Authenticator', $data[0]->getName());
$this->assertNull($data[0]->getData());
$this->assertEquals(1, $data[0]->getAvailable());
$this->assertEquals(0, $data[0]->getEnabled());
$this->assertEquals(3, $data[1]->getId());
$this->assertEquals(2, $data[2]->getId());
}
/**
* @throws ConstraintException
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testToggleEnabledByName()
{
self::$service->toggleEnabledByName('Authenticator', 1);
$data = self::$service->getByName('Authenticator');
$this->assertEquals(1, $data->getEnabled());
$this->expectException(NoSuchItemException::class);
self::$service->toggleEnabledByName('Test', 0);
}
/**
* @throws ConstraintException
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testToggleAvailableByName()
{
self::$service->toggleAvailableByName('Authenticator', 0);
$data = self::$service->getByName('Authenticator');
$this->assertEquals(0, $data->getAvailable());
$this->expectException(NoSuchItemException::class);
self::$service->toggleAvailableByName('Authenticator 2', 1);
}
/**
* @throws ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testGetByIdBatch()
{
$data = self::$service->getByIdBatch([1, 2, 3]);
$this->assertCount(3, $data);
$this->assertEquals(1, $data[0]->getId());
$this->assertEquals(2, $data[1]->getId());
$this->assertEquals(3, $data[2]->getId());
$this->assertCount(0, self::$service->getByIdBatch([4]));
}
/**
* @throws ConstraintException
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testToggleEnabled()
{
self::$service->toggleEnabled(1, 1);
$data = self::$service->getById(1);
$this->assertEquals(1, $data->getEnabled());
$this->expectException(NoSuchItemException::class);
self::$service->toggleEnabled(4, 0);
}
}

View File

@@ -0,0 +1,459 @@
<?php
/**
* sysPass
*
* @author nuxsmin
* @link https://syspass.org
* @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org
*
* This file is part of sysPass.
*
* sysPass is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sysPass is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sysPass. If not, see <http://www.gnu.org/licenses/>.
*/
namespace SP\Tests\Services\PublicLink;
use SP\Config\ConfigData;
use SP\Core\Crypt\Vault;
use SP\Core\Exceptions\ConstraintException;
use SP\DataModel\AccountExtData;
use SP\DataModel\ItemSearchData;
use SP\DataModel\PublicLinkData;
use SP\DataModel\PublicLinkListData;
use SP\Repositories\DuplicatedItemException;
use SP\Repositories\NoSuchItemException;
use SP\Services\PublicLink\PublicLinkService;
use SP\Services\ServiceException;
use SP\Storage\Database\DatabaseConnectionData;
use SP\Test\DatabaseTestCase;
use SP\Util\Util;
use function SP\Test\setupContext;
/**
* Class PublicLinkServiceTest
*
* @package SP\Tests\Services\PublicLink
*/
class PublicLinkServiceTest extends DatabaseTestCase
{
/**
* @var string
*/
private static $salt;
/**
* @var PublicLinkService
*/
private static $service;
/**
* @throws \DI\NotFoundException
* @throws \SP\Core\Context\ContextException
* @throws \DI\DependencyException
*/
public static function setUpBeforeClass()
{
$dic = setupContext();
self::$dataset = 'syspass_publicLink.xml';
// Datos de conexión a la BBDD
self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class);
// Inicializar el repositorio
self::$service = $dic->get(PublicLinkService::class);
self::$salt = $dic->get(ConfigData::class)->getPasswordSalt();
}
/**
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testGetAllBasic()
{
$data = self::$service->getAllBasic();
$this->assertInstanceOf(PublicLinkListData::class, $data[0]);
$this->assertEquals(2, $data[0]->getId());
$this->assertInstanceOf(PublicLinkListData::class, $data[1]);
$this->assertEquals(3, $data[1]->getId());
$this->assertEquals(2, $data[1]->getItemId());
$this->assertEquals('ac744b6948823cb0514546c567981ce4fe7240df396826d99f24fd9a1344', $data[1]->getHash());
$this->assertNotEmpty($data[1]->getData());
$this->assertEquals(1, $data[1]->getUserId());
$this->assertEquals(1, $data[1]->getTypeId());
$this->assertEquals(0, $data[1]->isNotify());
$this->assertEquals(1529276100, $data[1]->getDateAdd());
$this->assertEquals(1532280828, $data[1]->getDateExpire());
$this->assertEquals(0, $data[1]->getDateUpdate());
$this->assertEquals(0, $data[1]->getCountViews());
$this->assertEquals(3, $data[1]->getMaxCountViews());
$this->assertEquals(0, $data[1]->getTotalCountViews());
$this->assertNull($data[1]->getUseInfo());
$this->assertEquals('Apple', $data[1]->getAccountName());
$this->assertEquals('admin', $data[1]->getUserLogin());
}
/**
* @throws \SP\Core\Exceptions\SPException
*/
public function testGetByHash()
{
$hash = 'ced3400ea170619ad7d2589488b6b60747ea99f12e220f5a910ede6d834f';
$data = self::$service->getByHash($hash);
$this->assertInstanceOf(PublicLinkData::class, $data);
$this->assertEquals(2, $data->getId());
$this->assertEquals(1, $data->getItemId());
$this->assertEquals($hash, $data->getHash());
$this->assertNotEmpty($data->getData());
$this->assertEquals(1, $data->getUserId());
$this->assertEquals(1, $data->getTypeId());
$this->assertEquals(0, $data->isNotify());
$this->assertEquals(1529228863, $data->getDateAdd());
$this->assertEquals(1532280825, $data->getDateExpire());
$this->assertEquals(0, $data->getDateUpdate());
$this->assertEquals(0, $data->getCountViews());
$this->assertEquals(3, $data->getMaxCountViews());
$this->assertEquals(0, $data->getTotalCountViews());
$this->assertNull($data->getUseInfo());
$this->expectException(NoSuchItemException::class);
self::$service->getByHash('');
}
/**
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testSearch()
{
$itemSearchData = new ItemSearchData();
$itemSearchData->setLimitCount(10);
$itemSearchData->setSeachString('Google');
$result = self::$service->search($itemSearchData);
/** @var PublicLinkListData[] $data */
$data = $result->getDataAsArray();
$this->assertEquals(1, $result->getNumRows());
$this->assertCount(1, $data);
$this->assertInstanceOf(PublicLinkListData::class, $data[0]);
$this->assertEquals(2, $data[0]->getId());
$this->assertEquals(1, $data[0]->getItemId());
$this->assertEquals('ced3400ea170619ad7d2589488b6b60747ea99f12e220f5a910ede6d834f', $data[0]->getHash());
$this->assertNotEmpty($data[0]->getData());
$this->assertEquals(1, $data[0]->getUserId());
$this->assertEquals(1, $data[0]->getTypeId());
$this->assertEquals(0, $data[0]->isNotify());
$this->assertEquals(1529228863, $data[0]->getDateAdd());
$this->assertEquals(1532280825, $data[0]->getDateExpire());
$this->assertEquals(0, $data[0]->getDateUpdate());
$this->assertEquals(0, $data[0]->getCountViews());
$this->assertEquals(3, $data[0]->getMaxCountViews());
$this->assertEquals(0, $data[0]->getTotalCountViews());
$this->assertNull($data[0]->getUseInfo());
$this->assertEquals('Google', $data[0]->getAccountName());
$this->assertEquals('admin', $data[0]->getUserLogin());
$itemSearchData->setSeachString('Apple');
$result = self::$service->search($itemSearchData);
/** @var PublicLinkListData[] $data */
$data = $result->getDataAsArray();
$this->assertEquals(1, $result->getNumRows());
$this->assertCount(1, $data);
$this->assertInstanceOf(PublicLinkListData::class, $data[0]);
$this->assertEquals(3, $data[0]->getId());
$this->assertEquals(2, $data[0]->getItemId());
$itemSearchData->setSeachString('');
$result = self::$service->search($itemSearchData);
$this->assertEquals(2, $result->getNumRows());
}
/**
* @throws NoSuchItemException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testGetHashForItem()
{
$data = self::$service->getHashForItem(2);
$this->assertEquals(3, $data->getId());
$this->assertEquals('ac744b6948823cb0514546c567981ce4fe7240df396826d99f24fd9a1344', $data->getHash());
$this->expectException(NoSuchItemException::class);
self::$service->getHashForItem(3);
}
/**
* @throws \Defuse\Crypto\Exception\CryptoException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\SPException
*/
public function testCreate()
{
self::$service->delete(2);
$data = new PublicLinkData();
$data->setItemId(1);
$data->setHash(Util::generateRandomBytes());
$data->setUserId(1);
$data->setTypeId(1);
$data->setNotify(1);
$data->setDateExpire(time() + 600);
$data->setDateAdd(time());
$data->setMaxCountViews(3);
$this->assertEquals(4, self::$service->create($data));
/** @var PublicLinkListData $resultData */
$resultData = self::$service->getById(4);
$this->assertEquals(4, $resultData->getId());
$this->assertEquals($data->getItemId(), $resultData->getItemId());
$this->assertEquals($data->getHash(), $resultData->getHash());
$this->assertEquals($data->getUserId(), $resultData->getUserId());
$this->assertEquals($data->getTypeId(), $resultData->getTypeId());
$this->assertEquals($data->isNotify(), $resultData->isNotify());
$this->assertEquals($data->getDateExpire(), $resultData->getDateExpire());
$this->assertEquals($data->getMaxCountViews(), $resultData->getMaxCountViews());
$this->checkVaultData($resultData);
$this->expectException(DuplicatedItemException::class);
self::$service->create($data);
}
/**
* @param PublicLinkListData $data
*
* @throws \Defuse\Crypto\Exception\CryptoException
*/
private function checkVaultData(PublicLinkListData $data)
{
$this->assertNotEmpty($data->getData());
/** @var Vault $vault */
$vault = Util::unserialize(Vault::class, $data->getData());
$this->assertInstanceOf(Vault::class, $vault);
/** @var AccountExtData $accountData */
$accountData = Util::unserialize(AccountExtData::class, $vault->getData(self::$service->getPublicLinkKey($data->getHash())->getKey()));
$this->assertInstanceOf(AccountExtData::class, $accountData);
$this->assertEquals($data->getItemId(), $accountData->getId());
}
/**
* @throws \Defuse\Crypto\Exception\CryptoException
* @throws \SP\Core\Exceptions\ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\SPException
*/
public function testCreateSameItemId()
{
$data = new PublicLinkData();
$data->setItemId(2);
$data->setHash(Util::generateRandomBytes());
$data->setData('data');
$data->setUserId(1);
$data->setTypeId(1);
$data->setNotify(1);
$data->setDateExpire(time() + 600);
$data->setDateAdd(time());
$data->setMaxCountViews(3);
$this->expectException(DuplicatedItemException::class);
self::$service->create($data);
}
/**
* @throws ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\SPException
*/
public function testDelete()
{
self::$service->delete(2);
self::$service->delete(3);
$this->assertEquals(0, $this->conn->getRowCount('PublicLink'));
$this->expectException(NoSuchItemException::class);
$this->assertEquals(0, self::$service->delete(10));
}
/**
* @throws ConstraintException
* @throws \Defuse\Crypto\Exception\CryptoException
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\SPException
*/
public function testRefresh()
{
$this->assertEquals(1, self::$service->refresh(2));
/** @var PublicLinkListData $data */
$data = self::$service->getById(2);
$this->checkVaultData($data);
$this->expectException(NoSuchItemException::class);
self::$service->refresh(4);
}
/**
* @throws ConstraintException
* @throws ServiceException
* @throws \SP\Core\Exceptions\QueryException
*/
public function testDeleteByIdBatch()
{
$this->assertEquals(2, self::$service->deleteByIdBatch([2, 3]));
$this->assertEquals(0, $this->conn->getRowCount('PublicLink'));
$this->expectException(ServiceException::class);
self::$service->deleteByIdBatch([10]);
}
/**
* @throws ConstraintException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\SPException
*/
public function testAddLinkView()
{
$hash = 'ac744b6948823cb0514546c567981ce4fe7240df396826d99f24fd9a1344';
$useInfo[] = [
'who' => SELF_IP_ADDRESS,
'time' => time(),
'hash' => $hash,
'agent' => 'Mozilla/Firefox',
'https' => true
];
$data = new PublicLinkData();
$data->setHash($hash);
$data->setUseInfo($useInfo);
self::$service->addLinkView($data);
/** @var PublicLinkData $resultData */
$resultData = self::$service->getByHash($hash);
$this->assertEquals(1, $resultData->getCountViews());
$this->assertEquals(1, $resultData->getTotalCountViews());
$this->assertCount(2, unserialize($resultData->getUseInfo()));
$this->expectException(NoSuchItemException::class);
$data->setHash('123');
self::$service->addLinkView($data);
}
/**
* @throws ConstraintException
* @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
* @throws \SP\Core\Exceptions\QueryException
* @throws \SP\Core\Exceptions\SPException
*/
public function testUpdate()
{
$data = new PublicLinkData();
$data->setId(3);
$data->setItemId(2);
$data->setHash(Util::generateRandomBytes());
$data->setData('data');
$data->setUserId(2);
$data->setTypeId(1);
$data->setNotify(0);
$data->setDateExpire(time() + 3600);
$data->setDateAdd(time());
$data->setMaxCountViews(6);
$this->assertEquals(1, self::$service->update($data));
/** @var PublicLinkListData $resultData */
$resultData = self::$service->getById(3);
$this->assertEquals(3, $resultData->getId());
$this->assertEquals($data->getItemId(), $resultData->getItemId());
$this->assertEquals($data->getHash(), $resultData->getHash());
$this->assertEquals($data->getData(), $resultData->getData());
$this->assertEquals($data->getUserId(), $resultData->getUserId());
$this->assertEquals($data->getTypeId(), $resultData->getTypeId());
$this->assertEquals($data->isNotify(), $resultData->isNotify());
$this->assertEquals($data->getDateExpire(), $resultData->getDateExpire());
$this->assertEquals($data->getDateAdd(), $resultData->getDateAdd());
$this->assertEquals($data->getMaxCountViews(), $resultData->getMaxCountViews());
$this->expectException(ConstraintException::class);
$data->setItemId(1);
self::$service->update($data);
}
/**
* @throws \SP\Core\Exceptions\SPException
* @throws \Defuse\Crypto\Exception\CryptoException
*/
public function testGetById()
{
$data = self::$service->getById(2);
$this->assertInstanceOf(PublicLinkListData::class, $data);
$this->assertEquals(2, $data->getId());
$this->assertEquals(1, $data->getItemId());
$this->assertEquals('ced3400ea170619ad7d2589488b6b60747ea99f12e220f5a910ede6d834f', $data->getHash());
$this->assertEquals(1, $data->getUserId());
$this->assertEquals(1, $data->getTypeId());
$this->assertEquals(0, $data->isNotify());
$this->assertEquals(1529228863, $data->getDateAdd());
$this->assertEquals(1532280825, $data->getDateExpire());
$this->assertEquals(0, $data->getDateUpdate());
$this->assertEquals(0, $data->getCountViews());
$this->assertEquals(3, $data->getMaxCountViews());
$this->assertEquals(0, $data->getTotalCountViews());
$this->assertNull($data->getUseInfo());
$this->assertEquals('Google', $data->getAccountName());
$this->assertEquals('admin', $data->getUserLogin());
$this->checkVaultData($data);
$this->expectException(NoSuchItemException::class);
self::$service->getById(10);
}
}

File diff suppressed because one or more lines are too long