From 9f3a3be83f38e8f4706203768954ce050d4ce02c Mon Sep 17 00:00:00 2001 From: nuxsmin Date: Sat, 17 Feb 2018 12:47:03 +0100 Subject: [PATCH] * [MOD] Improved IoC handling. Work in progress * [ADD] Added custom fields service --- .../web/Controllers/ControllerBase.php | 31 +-- .../web/Controllers/SimpleControllerBase.php | 61 +----- .../web/Controllers/Traits/ItemTrait.php | 40 +++- lib/SP/Bootstrap.php | 2 +- lib/SP/Mvc/Controller/ControllerTrait.php | 90 ++++++++ .../CustomField/CustomFieldRepository.php | 94 +-------- .../CustomField/CustomFieldService.php | 192 ++++++++++++++++++ 7 files changed, 343 insertions(+), 167 deletions(-) create mode 100644 lib/SP/Mvc/Controller/ControllerTrait.php create mode 100644 lib/SP/Services/CustomField/CustomFieldService.php diff --git a/app/modules/web/Controllers/ControllerBase.php b/app/modules/web/Controllers/ControllerBase.php index 32b59f87..37ed1fc9 100644 --- a/app/modules/web/Controllers/ControllerBase.php +++ b/app/modules/web/Controllers/ControllerBase.php @@ -26,9 +26,9 @@ namespace SP\Modules\Web\Controllers; defined('APP_ROOT') || die(); +use DI\Container; use Klein\Klein; use Psr\Container\ContainerInterface; -use SP\Bootstrap; use SP\Config\Config; use SP\Config\ConfigData; use SP\Core\Acl\Acl; @@ -38,20 +38,19 @@ use SP\Core\Session\Session; use SP\Core\UI\Theme; use SP\Core\UI\ThemeIconsBase; use SP\DataModel\ProfileData; -use SP\Http\JsonResponse; +use SP\Mvc\Controller\ControllerTrait; use SP\Mvc\View\Template; use SP\Providers\Auth\Browser\Browser; use SP\Services\Auth\AuthException; use SP\Services\User\UserLoginResponse; -use SP\Util\Checks; -use SP\Util\Json; -use SP\Util\Util; /** * Clase base para los controladores */ abstract class ControllerBase { + use ControllerTrait; + /** * Constantes de errores */ @@ -130,16 +129,16 @@ abstract class ControllerBase /** * Constructor * - * @param $actionName + * @param Container $container + * @param $actionName * @throws \Psr\Container\ContainerExceptionInterface * @throws \Psr\Container\NotFoundExceptionInterface */ - public function __construct($actionName) + public function __construct(Container $container, $actionName) { - $this->dic = Bootstrap::getContainer(); + $this->dic = $container; - $class = static::class; - $this->controllerName = substr($class, strrpos($class, '\\') + 1, -strlen('Controller')); + $this->controllerName = $this->getControllerName(); $this->actionName = $actionName; $this->config = $this->dic->get(Config::class); @@ -248,17 +247,7 @@ abstract class ControllerBase } } - if (!$this->session->isLoggedIn()) { - if (Checks::isJson()) { - $jsonResponse = new JsonResponse(); - $jsonResponse->setDescription(__u('La sesión no se ha iniciado o ha caducado')); - $jsonResponse->setStatus(10); - - Json::returnJson($jsonResponse); - } else { - Util::logout(); - } - } + $this->checkLoggedInSession($this->session); } /** diff --git a/app/modules/web/Controllers/SimpleControllerBase.php b/app/modules/web/Controllers/SimpleControllerBase.php index 73509a99..a38da2e3 100644 --- a/app/modules/web/Controllers/SimpleControllerBase.php +++ b/app/modules/web/Controllers/SimpleControllerBase.php @@ -24,18 +24,14 @@ namespace SP\Modules\Web\Controllers; +use DI\Container; use Interop\Container\ContainerInterface; use Klein\Klein; -use SP\Bootstrap; use SP\Config\Config; use SP\Core\Events\EventDispatcher; use SP\Core\Session\Session; use SP\Core\UI\Theme; -use SP\Http\JsonResponse; -use SP\Http\Request; -use SP\Util\Checks; -use SP\Util\Json; -use SP\Util\Util; +use SP\Mvc\Controller\ControllerTrait; /** * Class SimpleControllerBase @@ -44,6 +40,8 @@ use SP\Util\Util; */ abstract class SimpleControllerBase { + use ControllerTrait; + /** * @var string Nombre del controlador */ @@ -80,16 +78,16 @@ abstract class SimpleControllerBase /** * SimpleControllerBase constructor. * - * @param $actionName + * @param Container $container + * @param $actionName * @throws \Psr\Container\ContainerExceptionInterface * @throws \Psr\Container\NotFoundExceptionInterface */ - public function __construct($actionName) + public function __construct(Container $container, $actionName) { - $this->dic = Bootstrap::getContainer(); + $this->dic = $container; - $class = static::class; - $this->controllerName = substr($class, strrpos($class, '\\') + 1, -strlen('Controller')); + $this->controllerName = $this->getControllerName(); $this->actionName = $actionName; $this->config = $this->dic->get(Config::class); @@ -103,49 +101,12 @@ abstract class SimpleControllerBase } } - /** - * Comprobar si la sesión está activa - */ - protected function checkSession() - { - if (!$this->session->isLoggedIn()) { - if (Checks::isJson()) { - $JsonResponse = new JsonResponse(); - $JsonResponse->setDescription(__u('La sesión no se ha iniciado o ha caducado')); - $JsonResponse->setStatus(10); - Json::returnJson($JsonResponse); - } else { - Util::logout(); - } - } - } - /** * Comprobaciones */ protected function checks() { - $this->checkSession(); - $this->preActionChecks(); - } - - /** - * Comprobaciones antes de realizar una acción - */ - protected function preActionChecks() - { - $sk = Request::analyze('sk'); - - if (!$sk || (null !== $this->session->getSecurityKey() && $this->session->getSecurityKey() === $sk)) { - $this->invalidAction(); - } - } - - /** - * Acción no disponible - */ - protected function invalidAction() - { - Json::returnJson((new JsonResponse())->setDescription(__u('Acción Inválida'))); + $this->checkLoggedInSession($this->session); + $this->checkSecurityToken($this->session); } } \ No newline at end of file diff --git a/app/modules/web/Controllers/Traits/ItemTrait.php b/app/modules/web/Controllers/Traits/ItemTrait.php index 8c04816e..221a2ce3 100644 --- a/app/modules/web/Controllers/Traits/ItemTrait.php +++ b/app/modules/web/Controllers/Traits/ItemTrait.php @@ -25,12 +25,13 @@ namespace SP\Modules\Web\Controllers\Traits; use Defuse\Crypto\Exception\CryptoException; +use SP\Bootstrap; use SP\Config\ConfigData; use SP\Core\Exceptions\SPException; use SP\DataModel\CustomFieldData; use SP\DataModel\ItemSearchData; use SP\Http\Request; -use SP\Repositories\CustomField\CustomFieldRepository; +use SP\Services\CustomField\CustomFieldService; /** * Trait ItemTrait @@ -45,13 +46,25 @@ trait ItemTrait * @param $moduleId * @param $itemId * @return array + * @throws \Psr\Container\ContainerExceptionInterface + * @throws \Psr\Container\NotFoundExceptionInterface */ protected function getCustomFieldsForItem($moduleId, $itemId) { - $customFieldService = new CustomFieldRepository(); + $customFieldService = Bootstrap::getContainer()->get(CustomFieldService::class); $customFields = []; $customFieldBase = new \stdClass(); + $customFieldBase->required = false; + $customFieldBase->showInList = false; + $customFieldBase->help = ''; + $customFieldBase->definitionId = 0; + $customFieldBase->definitionName = ''; + $customFieldBase->typeId = 0; + $customFieldBase->typeName = ''; + $customFieldBase->moduleId = 0; + $customFieldBase->formId = ''; + $customFieldBase->value = ''; foreach ($customFieldService->getForModuleById($moduleId, $itemId) as $item) { try { @@ -64,8 +77,8 @@ trait ItemTrait $customField->typeId = (int)$item->typeId; $customField->typeName = $item->typeName; $customField->moduleId = (int)$item->moduleId; - $customField->formId = CustomFieldRepository::getFormIdForName($item->definitionName); - $customField->value = $item->data !== null ? CustomFieldRepository::unencryptData($item->data) : ''; + $customField->formId = CustomFieldService::getFormIdForName($item->definitionName); + $customField->value = $item->data !== null ? CustomFieldService::decryptData($item->data) : ''; $customFields[] = $customField; } catch (CryptoException $e) { @@ -82,6 +95,10 @@ trait ItemTrait * @param int $moduleId * @param int|int[] $itemId * @throws SPException + * @throws \Psr\Container\ContainerExceptionInterface + * @throws \Psr\Container\NotFoundExceptionInterface + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException */ protected function addCustomFieldsForItem($moduleId, $itemId) { @@ -92,7 +109,8 @@ trait ItemTrait $customFieldData->setId($itemId); $customFieldData->setModuleId($moduleId); - $customFieldService = new CustomFieldRepository(); + $customFieldService = Bootstrap::getContainer()->get(CustomFieldService::class); + try { foreach ($customFields as $id => $value) { $customFieldData->setDefinitionId($id); @@ -112,11 +130,12 @@ trait ItemTrait * @param int $moduleId * @param int|int[] $itemId * @throws SPException + * @throws \Psr\Container\ContainerExceptionInterface + * @throws \Psr\Container\NotFoundExceptionInterface */ protected function deleteCustomFieldsForItem($moduleId, $itemId) { - $customFieldService = new CustomFieldRepository(); - $customFieldService->deleteCustomFieldData($itemId, $moduleId); + Bootstrap::getContainer()->get(CustomFieldService::class)->deleteCustomFieldData($itemId, $moduleId); } /** @@ -125,17 +144,22 @@ trait ItemTrait * @param int $moduleId * @param int|int[] $itemId * @throws SPException + * @throws \Psr\Container\ContainerExceptionInterface + * @throws \Psr\Container\NotFoundExceptionInterface + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException */ protected function updateCustomFieldsForItem($moduleId, $itemId) { $customFields = Request::analyze('customfield'); if (is_array($customFields)) { - $customFieldService = new CustomFieldRepository(); $customFieldData = new CustomFieldData(); $customFieldData->setId($itemId); $customFieldData->setModuleId($moduleId); + $customFieldService = Bootstrap::getContainer()->get(CustomFieldService::class); + try { foreach ($customFields as $id => $value) { $customFieldData->setDefinitionId($id); diff --git a/lib/SP/Bootstrap.php b/lib/SP/Bootstrap.php index af5ebb2e..35e7ce72 100644 --- a/lib/SP/Bootstrap.php +++ b/lib/SP/Bootstrap.php @@ -225,7 +225,7 @@ class Bootstrap debugLog('Routing call: ' . $controllerClass . '::' . $method . '::' . print_r($params, true)); - return call_user_func_array([new $controllerClass($method), $method], $params); + return call_user_func_array([new $controllerClass(self::$container, $method), $method], $params); } catch (\Exception $e) { debugLog($e->getMessage(), true); diff --git a/lib/SP/Mvc/Controller/ControllerTrait.php b/lib/SP/Mvc/Controller/ControllerTrait.php new file mode 100644 index 00000000..ece50917 --- /dev/null +++ b/lib/SP/Mvc/Controller/ControllerTrait.php @@ -0,0 +1,90 @@ +. + */ + +namespace SP\Mvc\Controller; + +use SP\Core\Session\Session; +use SP\Http\JsonResponse; +use SP\Http\Request; +use SP\Util\Checks; +use SP\Util\Json; +use SP\Util\Util; + + +/** + * Trait ControllerTrait + * + * @package SP\Mvc\Controller + */ +trait ControllerTrait +{ + /** + * @return string + */ + protected function getControllerName() + { + $class = static::class; + + return substr($class, strrpos($class, '\\') + 1, -strlen('Controller')) ?: ''; + } + + /** + * Comprobar si la sesión está activa + * + * @param Session $session + */ + protected function checkLoggedInSession(Session $session) + { + if (!$session->isLoggedIn()) { + if (Checks::isJson()) { + $JsonResponse = new JsonResponse(); + $JsonResponse->setDescription(__u('La sesión no se ha iniciado o ha caducado')); + $JsonResponse->setStatus(10); + Json::returnJson($JsonResponse); + } else { + Util::logout(); + } + } + } + + /** + * @param Session $session + */ + protected function checkSecurityToken(Session $session) + { + $sk = Request::analyze('sk'); + + if (!$sk || (null !== $session->getSecurityKey() && $session->getSecurityKey() === $sk)) { + $this->invalidAction(); + } + } + + /** + * Acción no disponible + */ + protected function invalidAction() + { + Json::returnJson((new JsonResponse())->setDescription(__u('Acción Inválida'))); + } +} \ No newline at end of file diff --git a/lib/SP/Repositories/CustomField/CustomFieldRepository.php b/lib/SP/Repositories/CustomField/CustomFieldRepository.php index 24aeab13..dbff56a2 100644 --- a/lib/SP/Repositories/CustomField/CustomFieldRepository.php +++ b/lib/SP/Repositories/CustomField/CustomFieldRepository.php @@ -2,8 +2,8 @@ /** * sysPass * - * @author nuxsmin - * @link http://syspass.org + * @author nuxsmin + * @link http://syspass.org * @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. @@ -24,11 +24,7 @@ namespace SP\Repositories\CustomField; -use Defuse\Crypto\Exception\CryptoException; -use SP\Core\Crypt\Crypt; -use SP\Core\Crypt\Session as CryptSession; use SP\Core\Exceptions\QueryException; -use SP\Core\Exceptions\SPException; use SP\DataModel\CustomFieldData; use SP\DataModel\ItemSearchData; use SP\Repositories\Repository; @@ -43,80 +39,16 @@ use SP\Storage\QueryData; */ class CustomFieldRepository extends Repository implements RepositoryItemInterface { - /** - * Returns the form Id for a given name - * - * @param $name - * @return string - */ - public static function getFormIdForName($name) - { - return 'cf_' . strtolower(preg_replace('/\W*/', '', $name)); - } - - /** - * Desencriptar y formatear los datos del campo - * - * @param CustomFieldData $CustomFieldData - * @return string - * @throws \Defuse\Crypto\Exception\CryptoException - */ - public static function unencryptData(CustomFieldData $CustomFieldData) - { - if ($CustomFieldData->getData() !== '') { - $securedKey = Crypt::unlockSecuredKey($CustomFieldData->getKey(), CryptSession::getSessionKey()); - - return self::formatValue(Crypt::decrypt($CustomFieldData->getData(), $securedKey)); - } - - return ''; - } - - /** - * Formatear el valor del campo - * - * @param $value string El valor del campo - * @return string - */ - public static function formatValue($value) - { - if (preg_match('#https?://#', $value)) { - return '' . $value . ''; - } - - return $value; - } - /** * Updates an item * * @param CustomFieldData $itemData * @return bool - * @throws CryptoException * @throws QueryException * @throws \SP\Core\Exceptions\ConstraintException */ public function update($itemData) { - $exists = $this->checkExists($itemData); - - // Deletes item's custom field data if value is left blank - if ($exists && $itemData->getData() === '') { - return $this->delete($itemData->getId()); - } - - // Create item's custom field data if value is set - if (!$exists && $itemData->getData() !== '') { - return $this->create($itemData); - } - - $sessionKey = CryptSession::getSessionKey(); - $securedKey = Crypt::makeSecuredKey($sessionKey); - - if (strlen($securedKey) > 1000) { - throw new QueryException(SPException::ERROR, __u('Error interno')); - } - $query = /** @lang SQL */ 'UPDATE CustomFieldData SET `data` = ?, @@ -127,8 +59,8 @@ class CustomFieldRepository extends Repository implements RepositoryItemInterfac $Data = new QueryData(); $Data->setQuery($query); - $Data->addParam(Crypt::encrypt($itemData->getData(), $securedKey, $sessionKey)); - $Data->addParam($securedKey); + $Data->addParam($itemData->getData()); + $Data->addParam($itemData->getKey()); $Data->addParam($itemData->getModuleId()); $Data->addParam($itemData->getId()); $Data->addParam($itemData->getDefinitionId()); @@ -144,7 +76,7 @@ class CustomFieldRepository extends Repository implements RepositoryItemInterfac * @throws QueryException * @throws \SP\Core\Exceptions\ConstraintException */ - protected function checkExists($itemData) + public function checkExists($itemData) { $query = /** @lang SQL */ 'SELECT id @@ -180,23 +112,11 @@ class CustomFieldRepository extends Repository implements RepositoryItemInterfac * * @param CustomFieldData $itemData * @return bool - * @throws CryptoException * @throws QueryException * @throws \SP\Core\Exceptions\ConstraintException */ public function create($itemData) { - if ($itemData->getData() === '') { - return true; - } - - $sessionKey = CryptSession::getSessionKey(); - $securedKey = Crypt::makeSecuredKey($sessionKey); - - if (strlen($securedKey) > 1000) { - throw new QueryException(SPException::ERROR, __u('Error interno')); - } - $query = /** @lang SQL */ 'INSERT INTO CustomFieldData SET itemId = ?, moduleId = ?, definitionId = ?, `data` = ?, `key` = ?'; @@ -205,8 +125,8 @@ class CustomFieldRepository extends Repository implements RepositoryItemInterfac $Data->addParam($itemData->getId()); $Data->addParam($itemData->getModuleId()); $Data->addParam($itemData->getDefinitionId()); - $Data->addParam(Crypt::encrypt($itemData->getData(), $securedKey, $sessionKey)); - $Data->addParam($securedKey); + $Data->addParam($itemData->getData()); + $Data->addParam($itemData->getKey()); return DbWrapper::getQuery($Data, $this->db); } diff --git a/lib/SP/Services/CustomField/CustomFieldService.php b/lib/SP/Services/CustomField/CustomFieldService.php new file mode 100644 index 00000000..8f794bd7 --- /dev/null +++ b/lib/SP/Services/CustomField/CustomFieldService.php @@ -0,0 +1,192 @@ +. + */ + +namespace SP\Services\CustomField; + +use Defuse\Crypto\Exception\CryptoException; +use SP\Core\Crypt\Crypt; +use SP\Core\Crypt\Session as CryptSession; +use SP\Core\Exceptions\QueryException; +use SP\Core\Exceptions\SPException; +use SP\DataModel\CustomFieldData; +use SP\Repositories\CustomField\CustomFieldRepository; +use SP\Services\Service; + +/** + * Class CustomFieldService + * + * @package SP\Services\CustomField + */ +class CustomFieldService extends Service +{ + /** + * @var CustomFieldRepository + */ + protected $customFieldRepository; + + /** + * Returns the form Id for a given name + * + * @param $name + * @return string + */ + public static function getFormIdForName($name) + { + return 'cf_' . strtolower(preg_replace('/\W*/', '', $name)); + } + + /** + * Desencriptar y formatear los datos del campo + * + * @param CustomFieldData $CustomFieldData + * @return string + * @throws \Defuse\Crypto\Exception\CryptoException + */ + public static function decryptData(CustomFieldData $CustomFieldData) + { + if ($CustomFieldData->getData() !== '') { + $securedKey = Crypt::unlockSecuredKey($CustomFieldData->getKey(), CryptSession::getSessionKey()); + + return self::formatValue(Crypt::decrypt($CustomFieldData->getData(), $securedKey)); + } + + return ''; + } + + /** + * Formatear el valor del campo + * + * @param $value string El valor del campo + * @return string + */ + public static function formatValue($value) + { + if (preg_match('#https?://#', $value)) { + return '' . $value . ''; + } + + return $value; + } + + /** + * Returns the module's item for given id + * + * @param $moduleId + * @param $itemId + * @return array + */ + public function getForModuleById($moduleId, $itemId) + { + return $this->customFieldRepository->getForModuleById($moduleId, $itemId); + } + + /** + * Updates an item + * + * @param CustomFieldData $customFieldData + * @return bool + * @throws CryptoException + * @throws QueryException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws SPException + */ + public function update(CustomFieldData $customFieldData) + { + $exists = $this->customFieldRepository->checkExists($customFieldData); + + // Deletes item's custom field data if value is left blank + if ($exists && $customFieldData->getData() === '') { + return $this->deleteCustomFieldData($customFieldData->getId(), $customFieldData->getModuleId()); + } + + // Create item's custom field data if value is set + if (!$exists && $customFieldData->getData() !== '') { + return $this->create($customFieldData); + } + + $this->setSecureData($customFieldData); + + return $this->customFieldRepository->update($customFieldData); + } + + /** + * Eliminar los datos de los campos personalizados del módulo + * + * @param int $id + * @param int $moduleId + * @return bool + * @throws \SP\Core\Exceptions\SPException + */ + public function deleteCustomFieldData($id, $moduleId) + { + return $this->customFieldRepository->deleteCustomFieldData($id, $moduleId); + } + + /** + * Creates an item + * + * @param CustomFieldData $customFieldData + * @return bool + * @throws CryptoException + * @throws QueryException + * @throws \SP\Core\Exceptions\ConstraintException + */ + public function create(CustomFieldData $customFieldData) + { + if ($customFieldData->getData() === '') { + return true; + } + + $this->setSecureData($customFieldData); + + return $this->customFieldRepository->create($customFieldData); + } + + /** + * @param CustomFieldData $customFieldData + * @throws CryptoException + * @throws QueryException + */ + protected function setSecureData(CustomFieldData $customFieldData) + { + $sessionKey = CryptSession::getSessionKey(); + $securedKey = Crypt::makeSecuredKey($sessionKey); + + if (strlen($securedKey) > 1000) { + throw new QueryException(__u('Error interno'), SPException::ERROR); + } + + $customFieldData->setData(Crypt::encrypt($customFieldData->getData(), $securedKey, $sessionKey)); + $customFieldData->setKey($securedKey); + } + + /** + * @throws \Psr\Container\ContainerExceptionInterface + * @throws \Psr\Container\NotFoundExceptionInterface + */ + protected function initialize() + { + $this->customFieldRepository = $this->dic->get(CustomFieldRepository::class); + } +} \ No newline at end of file