From 3ea87a4ecce616499f6a536d404373dc2325d16c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D?= Date: Wed, 30 Jan 2019 00:04:05 +0100 Subject: [PATCH] * [MOD] Improved plugins data handling by encrypting the plugin's data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rubén D --- .../UserSettingsManagerController.php | 5 +- lib/SP/Core/Events/Event.php | 2 +- lib/SP/DataModel/EncryptedModel.php | 100 ++++++ lib/SP/DataModel/ItemPresetData.php | 26 +- lib/SP/DataModel/SerializedModel.php | 62 ++++ lib/SP/Plugin/PluginBase.php | 26 +- lib/SP/Plugin/PluginInterface.php | 4 +- lib/SP/Plugin/PluginManager.php | 45 ++- lib/SP/Plugin/PluginOperation.php | 82 +++-- .../Repositories/Plugin/PluginDataModel.php | 28 +- .../Plugin/PluginDataRepository.php | 20 +- lib/SP/Services/Plugin/PluginDataService.php | 40 ++- schemas/30119012201.sql | 7 +- schemas/dbstructure.sql | 309 ++++++++++-------- .../Repositories/PluginDataRepositoryTest.php | 47 ++- .../Services/Plugin/PluginDataServiceTest.php | 29 +- .../Services/Plugin/PluginOperationTest.php | 247 ++++++++++++++ tests/res/config/config.xml | 8 +- tests/res/datasets/syspass_plugin.xml | 12 +- tests/res/datasets/syspass_userGroup.xml | 23 -- 20 files changed, 815 insertions(+), 307 deletions(-) create mode 100644 lib/SP/DataModel/EncryptedModel.php create mode 100644 lib/SP/DataModel/SerializedModel.php create mode 100644 tests/SP/Services/Plugin/PluginOperationTest.php diff --git a/app/modules/web/Controllers/UserSettingsManagerController.php b/app/modules/web/Controllers/UserSettingsManagerController.php index 568b68fa..ebf4a200 100644 --- a/app/modules/web/Controllers/UserSettingsManagerController.php +++ b/app/modules/web/Controllers/UserSettingsManagerController.php @@ -127,8 +127,9 @@ final class UserSettingsManagerController extends ControllerBase implements Exte } /** - * @throws \Psr\Container\ContainerExceptionInterface - * @throws \Psr\Container\NotFoundExceptionInterface + * @throws \DI\DependencyException + * @throws \DI\NotFoundException + * @throws \SP\Core\Exceptions\SessionTimeout * @throws \SP\Services\Auth\AuthException */ protected function initialize() diff --git a/lib/SP/Core/Events/Event.php b/lib/SP/Core/Events/Event.php index c913f8fb..6944da18 100644 --- a/lib/SP/Core/Events/Event.php +++ b/lib/SP/Core/Events/Event.php @@ -64,7 +64,7 @@ final class Event /** * @param null $type * - * @return object + * @return mixed * @throws InvalidClassException */ public function getSource($type = null) diff --git a/lib/SP/DataModel/EncryptedModel.php b/lib/SP/DataModel/EncryptedModel.php new file mode 100644 index 00000000..108f52ad --- /dev/null +++ b/lib/SP/DataModel/EncryptedModel.php @@ -0,0 +1,100 @@ +. + */ + +namespace SP\DataModel; + + +use SP\Core\Crypt\Crypt; +use SP\Core\Exceptions\NoSuchPropertyException; + +/** + * Trait EncryptedModel + * + * @package SP\DataModel + */ +trait EncryptedModel +{ + /** + * @var string + */ + private $key; + + /** + * @param string $key + * @param string $property + * + * @return static|null + * @throws NoSuchPropertyException + * @throws \Defuse\Crypto\Exception\CryptoException + */ + public function encrypt(string $key, string $property = 'data') + { + if (property_exists($this, $property)) { + if ($this->$property === null) { + return null; + } + + $this->key = Crypt::makeSecuredKey($key); + + $this->$property = Crypt::encrypt($this->$property, $this->key, $key); + + return $this; + } + + throw new NoSuchPropertyException($property); + } + + /** + * @param string $key + * @param string $property + * + * @return static|null + * @throws NoSuchPropertyException + * @throws \Defuse\Crypto\Exception\CryptoException + */ + public function decrypt(string $key, string $property = 'data') + { + if (property_exists($this, $property) + && !empty($this->key) + ) { + if ($this->$property === null) { + return null; + } + + $this->$property = Crypt::decrypt($this->$property, $this->key, $key); + + return $this; + } + + throw new NoSuchPropertyException($property); + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } +} \ No newline at end of file diff --git a/lib/SP/DataModel/ItemPresetData.php b/lib/SP/DataModel/ItemPresetData.php index 9826e861..35e71036 100644 --- a/lib/SP/DataModel/ItemPresetData.php +++ b/lib/SP/DataModel/ItemPresetData.php @@ -24,9 +24,6 @@ namespace SP\DataModel; -use SP\Core\Exceptions\NoSuchPropertyException; -use SP\Util\Util; - /** * Class ItemPresetData * @@ -34,6 +31,8 @@ use SP\Util\Util; */ class ItemPresetData extends DataModelBase implements HydratableInterface { + use SerializedModel; + /** * @var int */ @@ -211,27 +210,6 @@ class ItemPresetData extends DataModelBase implements HydratableInterface return sha1($this->type . (int)$this->userId . (int)$this->userGroupId . (int)$this->userProfileId . (int)$this->priority); } - /** - * @param string $class - * - * @param string $property - * - * @return mixed - * @throws NoSuchPropertyException - */ - public function hydrate(string $class = null, string $property = 'data') - { - if (property_exists($this, $property)) { - if ($this->data !== null) { - return $class !== null ? Util::unserialize($class, $this->data) : unserialize($this->data); - } - - return null; - } - - throw new NoSuchPropertyException($property); - } - /** * @return string */ diff --git a/lib/SP/DataModel/SerializedModel.php b/lib/SP/DataModel/SerializedModel.php new file mode 100644 index 00000000..0d239a7a --- /dev/null +++ b/lib/SP/DataModel/SerializedModel.php @@ -0,0 +1,62 @@ +. + */ + +namespace SP\DataModel; + + +use SP\Core\Exceptions\NoSuchPropertyException; +use SP\Util\Util; + +/** + * Trait Datamodel + * + * @package SP\DataModel + */ +trait SerializedModel +{ + /** + * @param string $class + * + * @param string $property + * + * @return mixed|null + * @throws NoSuchPropertyException + */ + public function hydrate(string $class = null, string $property = 'data') + { + if (property_exists($this, $property)) { + if ($this->$property === null) { + return null; + } + + if ($class !== null) { + return Util::unserialize($class, $this->$property); + } + + return unserialize($this->$property); + } + + throw new NoSuchPropertyException($property); + } +} \ No newline at end of file diff --git a/lib/SP/Plugin/PluginBase.php b/lib/SP/Plugin/PluginBase.php index b069a0f2..6c5a63da 100644 --- a/lib/SP/Plugin/PluginBase.php +++ b/lib/SP/Plugin/PluginBase.php @@ -54,6 +54,10 @@ abstract class PluginBase implements PluginInterface * @var int */ protected $enabled; + /** + * @var PluginOperation + */ + protected $pluginOperation; /** * @var PluginService */ @@ -63,10 +67,12 @@ abstract class PluginBase implements PluginInterface * PluginBase constructor. * * @param ContainerInterface $dic + * @param PluginOperation $pluginOperation */ - public final function __construct(ContainerInterface $dic) + public final function __construct(ContainerInterface $dic, PluginOperation $pluginOperation) { $this->pluginService = $dic->get(PluginService::class); + $this->pluginOperation = $pluginOperation; $this->init($dic); } @@ -119,16 +125,24 @@ abstract class PluginBase implements PluginInterface } /** + * @param int $id + * @param mixed $data + * + * @throws \Defuse\Crypto\Exception\CryptoException * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException - * @throws \SP\Repositories\NoSuchItemException + * @throws \SP\Services\ServiceException */ - final public function saveData() + final public function saveData(int $id, $data) { - $pluginData = $this->pluginService->getByName($this->getName()); - $pluginData->setData(serialize($this->data)); + if ($this->data === null) { + $this->pluginOperation->create($id, $data); + } else { + $this->pluginOperation->update($id, $data); + } - return $this->pluginService->update($pluginData); + $this->data = $data; } /** diff --git a/lib/SP/Plugin/PluginInterface.php b/lib/SP/Plugin/PluginInterface.php index e48a7977..bd875d53 100644 --- a/lib/SP/Plugin/PluginInterface.php +++ b/lib/SP/Plugin/PluginInterface.php @@ -86,9 +86,9 @@ interface PluginInterface extends PluginEventReceiver public function getData(); /** - * @param PluginOperation $pluginOperation + * onLoad */ - public function onLoad(PluginOperation $pluginOperation); + public function onLoad(); /** * @return int diff --git a/lib/SP/Plugin/PluginManager.php b/lib/SP/Plugin/PluginManager.php index 5109e862..8a68f16b 100644 --- a/lib/SP/Plugin/PluginManager.php +++ b/lib/SP/Plugin/PluginManager.php @@ -135,10 +135,11 @@ final class PluginManager * Obtener la información de un plugin * * @param string $name Nombre del plugin + * @param bool $initialize * * @return PluginInterface */ - public function getPlugin($name) + public function getPlugin($name, bool $initialize = false) { if (isset(self::$pluginsAvailable[$name])) { $plugin = $this->loadPluginClass( @@ -146,7 +147,10 @@ final class PluginManager self::$pluginsAvailable[$name]['namespace'] ); - $this->initPluginData($plugin); + if ($initialize) { + $this->initPlugin($plugin); + $plugin->onLoad(); + } return $plugin; } @@ -164,10 +168,10 @@ final class PluginManager */ private function loadPluginClass(string $name, string $namespace) { - $name = ucfirst($name); + $pluginName = ucfirst($name); - if (isset($this->loadedPlugins[$name])) { - return $this->loadedPlugins[$name]; + if (isset($this->loadedPlugins[$pluginName])) { + return $this->loadedPlugins[$pluginName]; } try { @@ -175,7 +179,10 @@ final class PluginManager $reflectionClass = new ReflectionClass($class); /** @var PluginInterface $plugin */ - $plugin = $reflectionClass->newInstance(Bootstrap::getContainer()); + $plugin = $reflectionClass->newInstance( + Bootstrap::getContainer(), + new PluginOperation($this->pluginDataService, $pluginName) + ); // Do not load plugin's data if not compatible. // Just return the plugin instance before disabling it @@ -185,7 +192,7 @@ final class PluginManager ->addDescription(sprintf(__('Plugin version not compatible (%s)'), implode('.', $plugin->getVersion())))) ); - $this->disabledPlugins[] = $name; + $this->disabledPlugins[] = $pluginName; } return $plugin; @@ -194,9 +201,9 @@ final class PluginManager $this->eventDispatcher->notifyEvent('exception', new Event($e, EventMessage::factory() - ->addDescription(sprintf(__('Unable to load the "%s" plugin'), $name)) + ->addDescription(sprintf(__('Unable to load the "%s" plugin'), $pluginName)) ->addDescription($e->getMessage()) - ->addDetail(__u('Plugin'), $name)) + ->addDetail(__u('Plugin'), $pluginName)) ); } @@ -232,17 +239,19 @@ final class PluginManager /** * @param PluginInterface $plugin + * + * @return bool */ - private function initPluginData(PluginInterface $plugin) + private function initPlugin(PluginInterface $plugin) { try { - $pluginData = $this->pluginService->getByName($plugin->getName()); + $pluginModel = $this->pluginService->getByName($plugin->getName()); - if ($pluginData->getEnabled() === 1) { - $plugin->onLoad(new PluginOperation($this->pluginDataService, $plugin->getName())); - } else { + if ($pluginModel->getEnabled() !== 1) { $this->disabledPlugins[] = $plugin->getName(); } + + return true; } catch (\Exception $e) { processException($e); @@ -253,6 +262,8 @@ final class PluginManager ->addDetail(__u('Plugin'), $plugin->getName())) ); } + + return false; } /** @@ -316,9 +327,9 @@ final class PluginManager self::$pluginsAvailable[$pluginName]['namespace'] ); - if ($plugin !== null) { - $this->initPluginData($plugin); - + if ($plugin !== null + && $this->initPlugin($plugin) + ) { logger(sprintf('Plugin loaded: %s', $pluginName)); $this->eventDispatcher->notifyEvent('plugin.load', diff --git a/lib/SP/Plugin/PluginOperation.php b/lib/SP/Plugin/PluginOperation.php index a0b2c917..6f64359e 100644 --- a/lib/SP/Plugin/PluginOperation.php +++ b/lib/SP/Plugin/PluginOperation.php @@ -24,8 +24,14 @@ namespace SP\Plugin; +use Defuse\Crypto\Exception\CryptoException; +use SP\Core\Exceptions\ConstraintException; +use SP\Core\Exceptions\NoSuchPropertyException; +use SP\Core\Exceptions\QueryException; +use SP\Repositories\NoSuchItemException; use SP\Repositories\Plugin\PluginDataModel; use SP\Services\Plugin\PluginDataService; +use SP\Services\ServiceException; /** * Class PluginOperation @@ -41,51 +47,58 @@ final class PluginOperation /** * @var string */ - private $name; + private $pluginName; /** * PluginOperation constructor. * * @param PluginDataService $pluginDataService - * @param string $name + * @param string $pluginName */ - public function __construct(PluginDataService $pluginDataService, string $name) + public function __construct(PluginDataService $pluginDataService, string $pluginName) { $this->pluginDataService = $pluginDataService; - $this->name = $name; + $this->pluginName = $pluginName; } /** - * @param int $itemId - * @param string $data - * - * @throws \SP\Core\Exceptions\ConstraintException - * @throws \SP\Core\Exceptions\QueryException - */ - public function create(int $itemId, string $data) - { - $itemData = new PluginDataModel(); - $itemData->setName($this->name); - $itemData->setItemId($itemId); - $itemData->setData($data); - - $this->pluginDataService->create($itemData); - } - - /** - * @param int $itemId - * @param string $data + * @param int $itemId + * @param mixed $data * * @return int + * @throws \Defuse\Crypto\Exception\CryptoException * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException */ - public function update(int $itemId, string $data) + public function create(int $itemId, $data) { $itemData = new PluginDataModel(); - $itemData->setName($this->name); + $itemData->setName($this->pluginName); $itemData->setItemId($itemId); - $itemData->setData($data); + $itemData->setData(serialize($data)); + + return $this->pluginDataService->create($itemData)->getLastId(); + } + + /** + * @param int $itemId + * @param mixed $data + * + * @return int + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException + */ + public function update(int $itemId, $data) + { + $itemData = new PluginDataModel(); + $itemData->setName($this->pluginName); + $itemData->setItemId($itemId); + $itemData->setData(serialize($data)); return $this->pluginDataService->update($itemData); } @@ -99,7 +112,7 @@ final class PluginOperation */ public function delete(int $itemId) { - $this->pluginDataService->deleteByItemId($this->name, $itemId); + $this->pluginDataService->deleteByItemId($this->pluginName, $itemId); } /** @@ -107,13 +120,18 @@ final class PluginOperation * @param string|null $class * * @return mixed|null - * @throws \SP\Core\Exceptions\ConstraintException - * @throws \SP\Core\Exceptions\NoSuchPropertyException - * @throws \SP\Core\Exceptions\QueryException - * @throws \SP\Repositories\NoSuchItemException + * @throws ConstraintException + * @throws CryptoException + * @throws NoSuchPropertyException + * @throws QueryException + * @throws ServiceException */ public function get(int $itemId, string $class = null) { - return $this->pluginDataService->getByItemId($this->name, $itemId)->hydrate($class); + try { + return $this->pluginDataService->getByItemId($this->pluginName, $itemId)->hydrate($class); + } catch (NoSuchItemException $e) { + return null; + } } } \ No newline at end of file diff --git a/lib/SP/Repositories/Plugin/PluginDataModel.php b/lib/SP/Repositories/Plugin/PluginDataModel.php index 3b42656e..3f2db046 100644 --- a/lib/SP/Repositories/Plugin/PluginDataModel.php +++ b/lib/SP/Repositories/Plugin/PluginDataModel.php @@ -24,9 +24,9 @@ namespace SP\Repositories\Plugin; -use SP\Core\Exceptions\NoSuchPropertyException; +use SP\DataModel\EncryptedModel; use SP\DataModel\HydratableInterface; -use SP\Util\Util; +use SP\DataModel\SerializedModel; /** * Class PluginData @@ -35,6 +35,9 @@ use SP\Util\Util; */ final class PluginDataModel implements HydratableInterface { + use SerializedModel; + use EncryptedModel; + /** * @var string */ @@ -95,25 +98,4 @@ final class PluginDataModel implements HydratableInterface { $this->data = $data; } - - /** - * @param string $class - * - * @param string $property - * - * @return mixed|null - * @throws NoSuchPropertyException - */ - public function hydrate(string $class = null, string $property = 'data') - { - if (property_exists($this, $property)) { - if ($this->data !== null) { - return $class !== null ? Util::unserialize($class, $this->data) : unserialize($this->data); - } - - return null; - } - - throw new NoSuchPropertyException($property); - } } \ No newline at end of file diff --git a/lib/SP/Repositories/Plugin/PluginDataRepository.php b/lib/SP/Repositories/Plugin/PluginDataRepository.php index ce5437a1..3b7aeb5d 100644 --- a/lib/SP/Repositories/Plugin/PluginDataRepository.php +++ b/lib/SP/Repositories/Plugin/PluginDataRepository.php @@ -54,14 +54,15 @@ final class PluginDataRepository extends Repository implements RepositoryItemInt public function create($itemData) { $query = /** @lang SQL */ - 'INSERT INTO PluginData SET `name` = ?, itemId = ?, `data` = ?'; + 'INSERT INTO PluginData SET `name` = ?, itemId = ?, `data` = ?, `key` = ?'; $queryData = new QueryData(); $queryData->setQuery($query); $queryData->setParams([ $itemData->getName(), $itemData->getItemId(), - $itemData->getData() + $itemData->getData(), + $itemData->getKey() ]); $queryData->setOnErrorMessage(__u('Error while adding plugin\'s data')); @@ -81,13 +82,14 @@ final class PluginDataRepository extends Repository implements RepositoryItemInt { $query = /** @lang SQL */ 'UPDATE PluginData - SET `data` = ? + SET `data` = ?, `key` = ? WHERE `name` = ? AND itemId = ? LIMIT 1'; $queryData = new QueryData(); $queryData->setQuery($query); $queryData->setParams([ $itemData->getData(), + $itemData->getKey(), $itemData->getName(), $itemData->getItemId() ]); @@ -149,7 +151,8 @@ final class PluginDataRepository extends Repository implements RepositoryItemInt $query = /** @lang SQL */ 'SELECT itemId, `name`, - `data` + `data`, + `key` FROM PluginData WHERE `name` = ?'; @@ -173,7 +176,8 @@ final class PluginDataRepository extends Repository implements RepositoryItemInt $query = /** @lang SQL */ 'SELECT itemId, `name`, - `data` + `data`, + `key` FROM PluginData ORDER BY `name`'; @@ -202,7 +206,8 @@ final class PluginDataRepository extends Repository implements RepositoryItemInt $query = /** @lang SQL */ 'SELECT itemId, `name`, - `data` + `data`, + `key` FROM PluginData WHERE `name` IN (' . $this->getParamsFromArray($ids) . ') ORDER BY `name`'; @@ -301,7 +306,8 @@ final class PluginDataRepository extends Repository implements RepositoryItemInt $query = /** @lang SQL */ 'SELECT itemId, `name`, - `data` + `data`, + `key` FROM PluginData WHERE `name` = ? AND itemId = ? LIMIT 1'; diff --git a/lib/SP/Services/Plugin/PluginDataService.php b/lib/SP/Services/Plugin/PluginDataService.php index 6c292063..0f2ba77b 100644 --- a/lib/SP/Services/Plugin/PluginDataService.php +++ b/lib/SP/Services/Plugin/PluginDataService.php @@ -47,14 +47,15 @@ final class PluginDataService extends Service * @param PluginDataModel $itemData * * @return \SP\Storage\Database\QueryResult + * @throws \Defuse\Crypto\Exception\CryptoException * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException */ public function create(PluginDataModel $itemData) { - $itemData->setData(serialize($itemData->getData())); - - return $this->pluginRepository->create($itemData); + return $this->pluginRepository->create($itemData->encrypt($this->getMasterKeyFromContext())); } /** @@ -63,14 +64,15 @@ final class PluginDataService extends Service * @param PluginDataModel $itemData * * @return int + * @throws \Defuse\Crypto\Exception\CryptoException * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException */ public function update(PluginDataModel $itemData) { - $itemData->setData(serialize($itemData->getData())); - - return $this->pluginRepository->update($itemData); + return $this->pluginRepository->update($itemData->encrypt($this->getMasterKeyFromContext())); } /** @@ -81,8 +83,11 @@ final class PluginDataService extends Service * * @return PluginDataModel * @throws NoSuchItemException + * @throws \Defuse\Crypto\Exception\CryptoException * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException */ public function getByItemId(string $name, int $id) { @@ -92,7 +97,10 @@ final class PluginDataService extends Service throw new NoSuchItemException(__u('Plugin\'s data not found'), NoSuchItemException::INFO); } - return $result->getData(); + /** @var PluginDataModel $itemData */ + $itemData = $result->getData(); + + return $itemData->decrypt($this->getMasterKeyFromContext()); } /** @@ -113,7 +121,14 @@ final class PluginDataService extends Service throw new NoSuchItemException(__u('Plugin\'s data not found'), NoSuchItemException::INFO); } - return $result->getDataAsArray(); + $data = $result->getDataAsArray(); + + array_walk($data, function ($itemData) { + /** @var PluginDataModel $itemData */ + $itemData->decrypt($this->getMasterKeyFromContext()); + }); + + return $data; } /** @@ -125,7 +140,14 @@ final class PluginDataService extends Service */ public function getAll() { - return $this->pluginRepository->getAll()->getDataAsArray(); + $data = $this->pluginRepository->getAll()->getDataAsArray(); + + array_walk($data, function ($itemData) { + /** @var PluginDataModel $itemData */ + $itemData->decrypt($this->getMasterKeyFromContext()); + }); + + return $data; } /** diff --git a/schemas/30119012201.sql b/schemas/30119012201.sql index 82781dec..d6b06dc3 100644 --- a/schemas/30119012201.sql +++ b/schemas/30119012201.sql @@ -5,9 +5,10 @@ alter table Plugin create table PluginData ( - name varchar(100) not null, - itemId int null, - data blob not null, + name varchar(100) not null, + itemId int null, + `data` blob not null, + `key` varbinary(2000) not null, constraint `PRIMARY` primary key (name, itemId), constraint fk_PluginData_name diff --git a/schemas/dbstructure.sql b/schemas/dbstructure.sql index 50c6480e..60b304bb 100644 --- a/schemas/dbstructure.sql +++ b/schemas/dbstructure.sql @@ -11,7 +11,8 @@ DROP TABLE IF EXISTS `Account`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `Account` ( +CREATE TABLE `Account` +( `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, `userGroupId` smallint(5) unsigned NOT NULL, `userId` smallint(5) unsigned NOT NULL, @@ -68,17 +69,17 @@ CREATE TABLE `ItemPreset` `hash` varbinary(40) NOT NULL, UNIQUE INDEX `uk_ItemPreset_01` (`hash`), CONSTRAINT `fk_ItemPreset_userId` - FOREIGN KEY (`userId`) REFERENCES `User` (`id`) - ON DELETE CASCADE - ON UPDATE CASCADE, + FOREIGN KEY (`userId`) REFERENCES `User` (`id`) + ON DELETE CASCADE + ON UPDATE CASCADE, CONSTRAINT `fk_ItemPreset_userGroupId` - FOREIGN KEY (`userGroupId`) REFERENCES `UserGroup` (`id`) - ON DELETE CASCADE - ON UPDATE CASCADE, + FOREIGN KEY (`userGroupId`) REFERENCES `UserGroup` (`id`) + ON DELETE CASCADE + ON UPDATE CASCADE, CONSTRAINT `fk_ItemPreset_userProfileId` - FOREIGN KEY (`userProfileId`) REFERENCES `UserProfile` (`id`) - ON DELETE CASCADE - ON UPDATE CASCADE, + FOREIGN KEY (`userProfileId`) REFERENCES `UserProfile` (`id`) + ON DELETE CASCADE + ON UPDATE CASCADE, PRIMARY KEY (`id`) ) ENGINE = InnoDB @@ -88,7 +89,8 @@ CREATE TABLE `ItemPreset` DROP TABLE IF EXISTS `AccountFile`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `AccountFile` ( +CREATE TABLE `AccountFile` +( `id` int(11) NOT NULL AUTO_INCREMENT, `accountId` mediumint(5) unsigned NOT NULL, `name` varchar(100) NOT NULL, @@ -96,7 +98,7 @@ CREATE TABLE `AccountFile` ( `size` int(11) NOT NULL, `content` mediumblob NOT NULL, `extension` varchar(10) NOT NULL, - `thumb` mediumblob DEFAULT NULL, + `thumb` mediumblob DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_AccountFile_01` (`accountId`), CONSTRAINT `fk_AccountFile_accountId` FOREIGN KEY (`accountId`) REFERENCES `Account` (`id`) @@ -110,7 +112,8 @@ CREATE TABLE `AccountFile` ( DROP TABLE IF EXISTS `AccountHistory`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `AccountHistory` ( +CREATE TABLE `AccountHistory` +( `id` int(11) NOT NULL AUTO_INCREMENT, `accountId` mediumint(8) unsigned NOT NULL, `userGroupId` smallint(5) unsigned NOT NULL, @@ -159,7 +162,8 @@ CREATE TABLE `AccountHistory` ( DROP TABLE IF EXISTS `AccountToFavorite`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `AccountToFavorite` ( +CREATE TABLE `AccountToFavorite` +( `accountId` mediumint(8) unsigned NOT NULL, `userId` smallint(5) unsigned NOT NULL, PRIMARY KEY (`accountId`, `userId`), @@ -179,7 +183,8 @@ CREATE TABLE `AccountToFavorite` ( DROP TABLE IF EXISTS `AccountToTag`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `AccountToTag` ( +CREATE TABLE `AccountToTag` +( `accountId` mediumint(8) unsigned NOT NULL, `tagId` int(10) unsigned NOT NULL, PRIMARY KEY (`accountId`, `tagId`), @@ -199,7 +204,8 @@ CREATE TABLE `AccountToTag` ( DROP TABLE IF EXISTS `AccountToUser`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `AccountToUser` ( +CREATE TABLE `AccountToUser` +( `accountId` mediumint(8) unsigned NOT NULL, `userId` smallint(5) unsigned NOT NULL, `isEdit` tinyint(1) unsigned DEFAULT 0 NULL, @@ -220,7 +226,8 @@ CREATE TABLE `AccountToUser` ( DROP TABLE IF EXISTS `AccountToUserGroup`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `AccountToUserGroup` ( +CREATE TABLE `AccountToUserGroup` +( `accountId` mediumint(8) unsigned NOT NULL, `userGroupId` smallint(5) unsigned NOT NULL, `isEdit` tinyint(1) unsigned DEFAULT 0 NULL, @@ -241,15 +248,16 @@ CREATE TABLE `AccountToUserGroup` ( DROP TABLE IF EXISTS `AuthToken`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `AuthToken` ( +CREATE TABLE `AuthToken` +( `id` int(11) NOT NULL AUTO_INCREMENT, `userId` smallint(5) unsigned NOT NULL, `token` varbinary(255) NOT NULL, `actionId` smallint(5) unsigned NOT NULL, `createdBy` smallint(5) unsigned NOT NULL, `startDate` int(10) unsigned NOT NULL, - `vault` varbinary(2000) DEFAULT NULL, - `hash` varbinary(500) DEFAULT NULL, + `vault` varbinary(2000) DEFAULT NULL, + `hash` varbinary(500) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_AuthToken_01` (`token`, `actionId`), KEY `idx_AuthToken_01` (`userId`, `actionId`, `token`), @@ -265,10 +273,11 @@ CREATE TABLE `AuthToken` ( DROP TABLE IF EXISTS `Category`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `Category` ( +CREATE TABLE `Category` +( `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, - `description` varchar(255) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, `hash` varbinary(40) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_Category_01` (`hash`) @@ -280,12 +289,13 @@ CREATE TABLE `Category` ( DROP TABLE IF EXISTS `Client`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `Client` ( +CREATE TABLE `Client` +( `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `hash` varbinary(40) NOT NULL, - `description` varchar(255) DEFAULT NULL, - `isGlobal` tinyint(1) DEFAULT 0, + `description` varchar(255) DEFAULT NULL, + `isGlobal` tinyint(1) DEFAULT 0, PRIMARY KEY (`id`), KEY `uk_Client_01` (`hash`) ) @@ -296,7 +306,8 @@ CREATE TABLE `Client` ( DROP TABLE IF EXISTS `Config`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `Config` ( +CREATE TABLE `Config` +( `parameter` varchar(50) NOT NULL, `value` varchar(4000) DEFAULT NULL, PRIMARY KEY (`parameter`) @@ -308,13 +319,14 @@ CREATE TABLE `Config` ( DROP TABLE IF EXISTS `CustomFieldData`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `CustomFieldData` ( +CREATE TABLE `CustomFieldData` +( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `moduleId` smallint(5) unsigned NOT NULL, `itemId` int(10) unsigned NOT NULL, `definitionId` int(10) unsigned NOT NULL, - `data` longblob DEFAULT NULL, - `key` varbinary(2000) DEFAULT NULL, + `data` longblob DEFAULT NULL, + `key` varbinary(2000) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_CustomFieldData_01` (`definitionId`), KEY `idx_CustomFieldData_02` (`itemId`, `moduleId`), @@ -329,13 +341,14 @@ CREATE TABLE `CustomFieldData` ( DROP TABLE IF EXISTS `CustomFieldDefinition`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `CustomFieldDefinition` ( +CREATE TABLE `CustomFieldDefinition` +( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `moduleId` smallint(5) unsigned NOT NULL, - `required` tinyint(1) unsigned DEFAULT NULL, - `help` varchar(255) DEFAULT NULL, - `showInList` tinyint(1) unsigned DEFAULT NULL, + `required` tinyint(1) unsigned DEFAULT NULL, + `help` varchar(255) DEFAULT NULL, + `showInList` tinyint(1) unsigned DEFAULT NULL, `typeId` tinyint(3) unsigned NOT NULL, `isEncrypted` tinyint(1) unsigned DEFAULT 1 NULL, PRIMARY KEY (`id`), @@ -350,7 +363,8 @@ CREATE TABLE `CustomFieldDefinition` ( DROP TABLE IF EXISTS `CustomFieldType`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `CustomFieldType` ( +CREATE TABLE `CustomFieldType` +( `id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `text` varchar(50) NOT NULL, @@ -364,14 +378,15 @@ CREATE TABLE `CustomFieldType` ( DROP TABLE IF EXISTS `EventLog`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `EventLog` ( +CREATE TABLE `EventLog` +( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `date` int(10) unsigned NOT NULL, - `login` varchar(25) DEFAULT NULL, - `userId` smallint(5) unsigned DEFAULT NULL, + `login` varchar(25) DEFAULT NULL, + `userId` smallint(5) unsigned DEFAULT NULL, `ipAddress` varchar(45) NOT NULL, `action` varchar(50) NOT NULL, - `description` text DEFAULT NULL, + `description` text DEFAULT NULL, `level` varchar(20) NOT NULL, PRIMARY KEY (`id`) ) @@ -393,16 +408,17 @@ VALUES (1, 'text', 'Text'), DROP TABLE IF EXISTS `Notification`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `Notification` ( +CREATE TABLE `Notification` +( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `type` varchar(100) DEFAULT NULL, + `type` varchar(100) DEFAULT NULL, `component` varchar(100) NOT NULL, `description` text NOT NULL, `date` int(10) unsigned NOT NULL, - `checked` tinyint(1) DEFAULT 0, - `userId` smallint(5) unsigned DEFAULT NULL, - `sticky` tinyint(1) DEFAULT 0, - `onlyAdmin` tinyint(1) DEFAULT 0, + `checked` tinyint(1) DEFAULT 0, + `userId` smallint(5) unsigned DEFAULT NULL, + `sticky` tinyint(1) DEFAULT 0, + `onlyAdmin` tinyint(1) DEFAULT 0, PRIMARY KEY (`id`), KEY `idx_Notification_01` (`userId`, `checked`, `date`), KEY `idx_Notification_02` (`component`, `date`, `checked`, `userId`), @@ -416,13 +432,14 @@ CREATE TABLE `Notification` ( DROP TABLE IF EXISTS `Plugin`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `Plugin` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `name` varchar(100) NOT NULL, - `data` mediumblob DEFAULT NULL, - `enabled` tinyint(1) NOT NULL DEFAULT 0, - `available` tinyint(1) DEFAULT 0, - `versionLevel` varchar(15) NULL, +CREATE TABLE `Plugin` +( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(100) NOT NULL, + `data` mediumblob DEFAULT NULL, + `enabled` tinyint(1) NOT NULL DEFAULT 0, + `available` tinyint(1) DEFAULT 0, + `versionLevel` varchar(15) NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_Plugin_01` (`name`) ) @@ -433,7 +450,8 @@ CREATE TABLE `Plugin` ( DROP TABLE IF EXISTS `PublicLink`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `PublicLink` ( +CREATE TABLE `PublicLink` +( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `itemId` int(10) unsigned NOT NULL, `hash` varbinary(100) NOT NULL, @@ -461,7 +479,8 @@ CREATE TABLE `PublicLink` ( DROP TABLE IF EXISTS `Tag`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `Tag` ( +CREATE TABLE `Tag` +( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(45) NOT NULL, `hash` varbinary(40) NOT NULL, @@ -476,14 +495,15 @@ CREATE TABLE `Tag` ( DROP TABLE IF EXISTS `Track`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `Track` ( +CREATE TABLE `Track` +( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `userId` smallint(5) unsigned DEFAULT NULL, + `userId` smallint(5) unsigned DEFAULT NULL, `source` varchar(100) NOT NULL, `time` int(10) unsigned NOT NULL, `timeUnlock` int(10) unsigned, - `ipv4` binary(4) DEFAULT NULL, - `ipv6` binary(16) DEFAULT NULL, + `ipv4` binary(4) DEFAULT NULL, + `ipv6` binary(16) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_Track_01` (`userId`), KEY `idx_Track_02` (`time`, `ipv4`, `ipv6`, `source`) @@ -495,7 +515,8 @@ CREATE TABLE `Track` ( DROP TABLE IF EXISTS `User`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `User` ( +CREATE TABLE `User` +( `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(80) NOT NULL, `userGroupId` smallint(5) unsigned NOT NULL, @@ -535,10 +556,11 @@ CREATE TABLE `User` ( DROP TABLE IF EXISTS `UserGroup`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `UserGroup` ( +CREATE TABLE `UserGroup` +( `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, - `description` varchar(255) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE = InnoDB @@ -548,12 +570,13 @@ CREATE TABLE `UserGroup` ( DROP TABLE IF EXISTS `UserPassRecover`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `UserPassRecover` ( +CREATE TABLE `UserPassRecover` +( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `userId` smallint(5) unsigned NOT NULL, `hash` varbinary(255) NOT NULL, `date` int(10) unsigned NOT NULL, - `used` tinyint(1) DEFAULT 0, + `used` tinyint(1) DEFAULT 0, PRIMARY KEY (`id`), KEY `idx_UserPassRecover_01` (`userId`, `date`), CONSTRAINT `fk_UserPassRecover_userId` FOREIGN KEY (`userId`) REFERENCES `User` (`id`) @@ -567,7 +590,8 @@ CREATE TABLE `UserPassRecover` ( DROP TABLE IF EXISTS `UserProfile`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `UserProfile` ( +CREATE TABLE `UserProfile` +( `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(45) NOT NULL, `profile` blob NOT NULL, @@ -580,7 +604,8 @@ CREATE TABLE `UserProfile` ( DROP TABLE IF EXISTS `UserToUserGroup`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE `UserToUserGroup` ( +CREATE TABLE `UserToUserGroup` +( `userId` smallint(5) unsigned NOT NULL, `userGroupId` smallint(5) unsigned NOT NULL, KEY `idx_UserToUserGroup_01` (`userId`), @@ -602,24 +627,26 @@ DROP TABLE IF EXISTS `PluginData`; /*!40101 SET character_set_client = utf8 */; create table PluginData ( - name varchar(100) not null, - itemId int not null, - data blob not null, + name varchar(100) not null, + itemId int not null, + `data` blob not null, + `key` varbinary(2000) not null, primary key (name, itemId), constraint fk_PluginData_name foreign key (name) references Plugin (name) on update cascade on delete cascade ) - ENGINE = InnoDB - DEFAULT CHARSET = utf8 - COLLATE utf8_unicode_ci; + ENGINE = InnoDB + DEFAULT CHARSET = utf8 + COLLATE utf8_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; DROP TABLE IF EXISTS `account_data_v`; /*!50001 DROP VIEW IF EXISTS `account_data_v`*/; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; -/*!50001 CREATE TABLE `account_data_v` ( +/*!50001 CREATE TABLE `account_data_v` +( `id` tinyint NOT NULL, `name` tinyint NOT NULL, `categoryId` tinyint NOT NULL, @@ -656,7 +683,8 @@ DROP TABLE IF EXISTS `account_search_v`; /*!50001 DROP VIEW IF EXISTS `account_search_v`*/; SET @saved_cs_client = @@character_set_client; SET character_set_client = utf8; -/*!50001 CREATE TABLE `account_search_v` ( +/*!50001 CREATE TABLE `account_search_v` +( `id` tinyint NOT NULL, `clientId` tinyint NOT NULL, `categoryId` tinyint NOT NULL, @@ -695,40 +723,41 @@ SET character_set_client = @saved_cs_client; /*!50001 CREATE ALGORITHM = UNDEFINED */ /*!50013 SQL SECURITY DEFINER */ /*!50001 VIEW `account_data_v` AS - select `Account`.`id` AS `id`, - `Account`.`name` AS `name`, - `Account`.`categoryId` AS `categoryId`, - `Account`.`userId` AS `userId`, - `Account`.`clientId` AS `clientId`, - `Account`.`userGroupId` AS `userGroupId`, - `Account`.`userEditId` AS `userEditId`, - `Account`.`login` AS `login`, - `Account`.`url` AS `url`, - `Account`.`notes` AS `notes`, - `Account`.`countView` AS `countView`, - `Account`.`countDecrypt` AS `countDecrypt`, - `Account`.`dateAdd` AS `dateAdd`, - `Account`.`dateEdit` AS `dateEdit`, - conv(`Account`.`otherUserEdit`, 10, 2) AS `otherUserEdit`, - conv(`Account`.`otherUserGroupEdit`, 10, 2) AS `otherUserGroupEdit`, - conv(`Account`.`isPrivate`, 10, 2) AS `isPrivate`, - conv(`Account`.`isPrivateGroup`, 10, 2) AS `isPrivateGroup`, - `Account`.`passDate` AS `passDate`, - `Account`.`passDateChange` AS `passDateChange`, - `Account`.`parentId` AS `parentId`, - `Category`.`name` AS `categoryName`, - `Client`.`name` AS `clientName`, - `ug`.`name` AS `userGroupName`, - `u1`.`name` AS `userName`, - `u1`.`login` AS `userLogin`, - `u2`.`name` AS `userEditName`, - `u2`.`login` AS `userEditLogin`, - `PublicLink`.`hash` AS `publicLinkHash` - from ((((((`Account` - left join `Category` on (`Account`.`categoryId` = `Category`.`id`)) join `UserGroup` `ug` - on (`Account`.`userGroupId` = `ug`.`id`)) join `User` `u1` on (`Account`.`userId` = `u1`.`id`)) join `User` `u2` - on (`Account`.`userEditId` = `u2`.`id`)) left join `Client` on (`Account`.`clientId` = `Client`.`id`)) left join - `PublicLink` on (`Account`.`id` = `PublicLink`.`itemId`)) */; +select `Account`.`id` AS `id`, + `Account`.`name` AS `name`, + `Account`.`categoryId` AS `categoryId`, + `Account`.`userId` AS `userId`, + `Account`.`clientId` AS `clientId`, + `Account`.`userGroupId` AS `userGroupId`, + `Account`.`userEditId` AS `userEditId`, + `Account`.`login` AS `login`, + `Account`.`url` AS `url`, + `Account`.`notes` AS `notes`, + `Account`.`countView` AS `countView`, + `Account`.`countDecrypt` AS `countDecrypt`, + `Account`.`dateAdd` AS `dateAdd`, + `Account`.`dateEdit` AS `dateEdit`, + conv(`Account`.`otherUserEdit`, 10, 2) AS `otherUserEdit`, + conv(`Account`.`otherUserGroupEdit`, 10, 2) AS `otherUserGroupEdit`, + conv(`Account`.`isPrivate`, 10, 2) AS `isPrivate`, + conv(`Account`.`isPrivateGroup`, 10, 2) AS `isPrivateGroup`, + `Account`.`passDate` AS `passDate`, + `Account`.`passDateChange` AS `passDateChange`, + `Account`.`parentId` AS `parentId`, + `Category`.`name` AS `categoryName`, + `Client`.`name` AS `clientName`, + `ug`.`name` AS `userGroupName`, + `u1`.`name` AS `userName`, + `u1`.`login` AS `userLogin`, + `u2`.`name` AS `userEditName`, + `u2`.`login` AS `userEditLogin`, + `PublicLink`.`hash` AS `publicLinkHash` +from ((((((`Account` + left join `Category` on (`Account`.`categoryId` = `Category`.`id`)) join `UserGroup` `ug` + on (`Account`.`userGroupId` = `ug`.`id`)) join `User` `u1` on (`Account`.`userId` = `u1`.`id`)) join `User` `u2` + on (`Account`.`userEditId` = `u2`.`id`)) left join `Client` on (`Account`.`clientId` = `Client`.`id`)) + left join + `PublicLink` on (`Account`.`id` = `PublicLink`.`itemId`)) */; /*!50001 SET character_set_client = @saved_cs_client */; /*!50001 SET character_set_results = @saved_cs_results */; /*!50001 SET collation_connection = @saved_col_connection */; @@ -743,39 +772,41 @@ SET character_set_client = @saved_cs_client; /*!50001 CREATE ALGORITHM = UNDEFINED */ /*!50013 SQL SECURITY DEFINER */ /*!50001 VIEW `account_search_v` AS - SELECT `Account`.`id` AS `id`, - `Account`.`clientId` AS `clientId`, - `Account`.`categoryId` AS `categoryId`, - `Account`.`name` AS `name`, - `Account`.`login` AS `login`, - `Account`.`url` AS `url`, - `Account`.`notes` AS `notes`, - `Account`.`userId` AS `userId`, - `Account`.`userGroupId` AS `userGroupId`, - `Account`.`otherUserEdit` AS `otherUserEdit`, - `Account`.`otherUserGroupEdit` AS `otherUserGroupEdit`, - `Account`.`isPrivate` AS `isPrivate`, - `Account`.`isPrivateGroup` AS `isPrivateGroup`, - `Account`.`passDate` AS `passDate`, - `Account`.`passDateChange` AS `passDateChange`, - `Account`.`parentId` AS `parentId`, - `Account`.`countView` AS `countView`, - `Account`.`dateEdit` AS `dateEdit`, - `User`.`name` AS `userName`, - `User`.`login` AS `userLogin`, - `UserGroup`.`name` AS `userGroupName`, - `Category`.`name` AS `categoryName`, - `Client`.`name` AS `clientName`, - (SELECT count(0) FROM `AccountFile` WHERE (`AccountFile`.`accountId` = `Account`.`id`)) AS `num_files`, - `PublicLink`.`hash` AS `publicLinkHash`, - `PublicLink`.`dateExpire` AS `publicLinkDateExpire`, - `PublicLink`.`totalCountViews` AS `publicLinkTotalCountViews` - FROM `Account` - INNER JOIN `Category` ON `Account`.`categoryId` = `Category`.`id` - INNER JOIN `Client` ON `Client`.`id` = `Account`.`clientId` - INNER JOIN `User` ON `Account`.`userId` = `User`.`id` - INNER JOIN `UserGroup` ON `Account`.`userGroupId` = `UserGroup`.`id` - LEFT JOIN `PublicLink` ON `Account`.`id` = `PublicLink`.`itemId` */; +SELECT `Account`.`id` AS `id`, + `Account`.`clientId` AS `clientId`, + `Account`.`categoryId` AS `categoryId`, + `Account`.`name` AS `name`, + `Account`.`login` AS `login`, + `Account`.`url` AS `url`, + `Account`.`notes` AS `notes`, + `Account`.`userId` AS `userId`, + `Account`.`userGroupId` AS `userGroupId`, + `Account`.`otherUserEdit` AS `otherUserEdit`, + `Account`.`otherUserGroupEdit` AS `otherUserGroupEdit`, + `Account`.`isPrivate` AS `isPrivate`, + `Account`.`isPrivateGroup` AS `isPrivateGroup`, + `Account`.`passDate` AS `passDate`, + `Account`.`passDateChange` AS `passDateChange`, + `Account`.`parentId` AS `parentId`, + `Account`.`countView` AS `countView`, + `Account`.`dateEdit` AS `dateEdit`, + `User`.`name` AS `userName`, + `User`.`login` AS `userLogin`, + `UserGroup`.`name` AS `userGroupName`, + `Category`.`name` AS `categoryName`, + `Client`.`name` AS `clientName`, + (SELECT count(0) + FROM `AccountFile` + WHERE (`AccountFile`.`accountId` = `Account`.`id`)) AS `num_files`, + `PublicLink`.`hash` AS `publicLinkHash`, + `PublicLink`.`dateExpire` AS `publicLinkDateExpire`, + `PublicLink`.`totalCountViews` AS `publicLinkTotalCountViews` +FROM `Account` + INNER JOIN `Category` ON `Account`.`categoryId` = `Category`.`id` + INNER JOIN `Client` ON `Client`.`id` = `Account`.`clientId` + INNER JOIN `User` ON `Account`.`userId` = `User`.`id` + INNER JOIN `UserGroup` ON `Account`.`userGroupId` = `UserGroup`.`id` + LEFT JOIN `PublicLink` ON `Account`.`id` = `PublicLink`.`itemId` */; /*!50001 SET character_set_client = @saved_cs_client */; /*!50001 SET character_set_results = @saved_cs_results */; /*!50001 SET collation_connection = @saved_col_connection */; diff --git a/tests/SP/Repositories/PluginDataRepositoryTest.php b/tests/SP/Repositories/PluginDataRepositoryTest.php index c7a159df..bd17a8d7 100644 --- a/tests/SP/Repositories/PluginDataRepositoryTest.php +++ b/tests/SP/Repositories/PluginDataRepositoryTest.php @@ -63,7 +63,9 @@ class PluginDataRepositoryTest extends DatabaseTestCase } /** - * @throws \SP\Core\Exceptions\ConstraintException + * @throws ConstraintException + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException */ public function testUpdate() @@ -73,23 +75,33 @@ class PluginDataRepositoryTest extends DatabaseTestCase $data->setName('Authenticator'); $data->setData('data_updated'); + $data->encrypt('12345678900'); + $this->assertEquals(1, self::$repository->update($data)); $result = self::$repository->getByItemId($data->getName(), $data->getItemId()); $this->assertEquals(1, $result->getNumRows()); - $this->assertEquals($data, $result->getData()); + + /** @var PluginDataModel $itemData */ + $itemData = $result->getData(); + + $this->assertEquals($data->getData(), $itemData->getData()); $data = new PluginDataModel(); $data->setItemId(0); $data->setName('Authenticator'); $data->setData('data_updated'); + $data->encrypt('test'); + $this->assertEquals(0, self::$repository->update($data)); } /** - * @throws \SP\Core\Exceptions\ConstraintException + * @throws ConstraintException + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException */ public function testUpdateUnkown() @@ -99,6 +111,8 @@ class PluginDataRepositoryTest extends DatabaseTestCase $data->setName('Test'); $data->setData('data'); + $data->encrypt('test'); + $this->assertEquals(0, self::$repository->update($data)); } @@ -116,7 +130,8 @@ class PluginDataRepositoryTest extends DatabaseTestCase $this->assertCount(4, $data); $this->assertEquals(1, $data[0]->getItemId()); $this->assertEquals('Authenticator', $data[0]->getName()); - $this->assertEquals('data_item1', $data[0]->getData()); + $this->assertNotEmpty($data[0]->getData()); + $this->assertNotEmpty($data[0]->getKey()); $this->assertEquals(2, $data[1]->getItemId()); $this->assertEquals(3, $data[2]->getItemId()); @@ -166,12 +181,14 @@ class PluginDataRepositoryTest extends DatabaseTestCase $this->assertInstanceOf(PluginDataModel::class, $data[0]); $this->assertEquals(1, $data[0]->getItemId()); $this->assertEquals('Authenticator', $data[0]->getName()); - $this->assertEquals('data_item1', $data[0]->getData()); + $this->assertNotEmpty($data[0]->getData()); + $this->assertNotEmpty($data[0]->getKey()); $this->assertInstanceOf(PluginDataModel::class, $data[1]); $this->assertEquals(2, $data[1]->getItemId()); $this->assertEquals('Authenticator', $data[1]->getName()); - $this->assertEquals('plugin_data', $data[1]->getData()); + $this->assertNotEmpty($data[1]->getData()); + $this->assertNotEmpty($data[1]->getKey()); $this->assertEquals(1, self::$repository->getById('XML Exporter')->getNumRows()); @@ -192,7 +209,8 @@ class PluginDataRepositoryTest extends DatabaseTestCase $this->assertInstanceOf(PluginDataModel::class, $data); $this->assertEquals(1, $data->getItemId()); $this->assertEquals('Authenticator', $data->getName()); - $this->assertEquals('data_item1', $data->getData()); + $this->assertNotEmpty($data->getData()); + $this->assertNotEmpty($data->getKey()); $this->assertEquals(0, self::$repository->getByItemId('Test', 1)->getNumRows()); } @@ -210,6 +228,8 @@ class PluginDataRepositoryTest extends DatabaseTestCase /** * @throws ConstraintException + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException */ public function testCreate() @@ -219,12 +239,19 @@ class PluginDataRepositoryTest extends DatabaseTestCase $data->setName('Authenticator'); $data->setData('data'); + $data->encrypt('12345678900'); + self::$repository->create($data); $result = self::$repository->getByItemId($data->getName(), $data->getItemId()); $this->assertEquals(1, $result->getNumRows()); - $this->assertEquals($data, $result->getData()); + + /** @var PluginDataModel $itemData */ + $itemData = $result->getData(); + + $this->assertEquals($data->getName(), $itemData->getName()); + $this->assertEquals($data->getData(), $itemData->getData()); $this->expectException(ConstraintException::class); @@ -233,6 +260,8 @@ class PluginDataRepositoryTest extends DatabaseTestCase /** * @throws ConstraintException + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException */ public function testCreateUnknown() @@ -244,6 +273,8 @@ class PluginDataRepositoryTest extends DatabaseTestCase $data->setName('Test'); $data->setData('data'); + $data->encrypt('test'); + self::$repository->create($data); } diff --git a/tests/SP/Services/Plugin/PluginDataServiceTest.php b/tests/SP/Services/Plugin/PluginDataServiceTest.php index e682b1f4..f1092f31 100644 --- a/tests/SP/Services/Plugin/PluginDataServiceTest.php +++ b/tests/SP/Services/Plugin/PluginDataServiceTest.php @@ -65,7 +65,10 @@ class PluginDataServiceTest extends DatabaseTestCase /** * @throws ConstraintException * @throws NoSuchItemException + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException */ public function testUpdate() { @@ -76,7 +79,9 @@ class PluginDataServiceTest extends DatabaseTestCase $this->assertEquals(1, self::$service->update($data)); - $this->assertEquals($data, self::$service->getByItemId($data->getName(), $data->getItemId())); + $itemData = self::$service->getByItemId($data->getName(), $data->getItemId()); + + $this->assertEquals('data_updated', $itemData->getData()); $data = new PluginDataModel(); $data->setItemId(0); @@ -87,8 +92,11 @@ class PluginDataServiceTest extends DatabaseTestCase } /** - * @throws \SP\Core\Exceptions\ConstraintException + * @throws ConstraintException + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException */ public function testUpdateUnkown() { @@ -149,7 +157,10 @@ class PluginDataServiceTest extends DatabaseTestCase /** * @throws ConstraintException * @throws NoSuchItemException + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException */ public function testCreate() { @@ -160,7 +171,10 @@ class PluginDataServiceTest extends DatabaseTestCase self::$service->create($data); - $this->assertEquals($data, self::$service->getByItemId($data->getName(), $data->getItemId())); + $itemData = self::$service->getByItemId($data->getName(), $data->getItemId()); + + $this->assertEquals($data->getName(), $itemData->getName()); + $this->assertEquals('data', $itemData->getData()); $this->expectException(ConstraintException::class); @@ -169,7 +183,10 @@ class PluginDataServiceTest extends DatabaseTestCase /** * @throws ConstraintException + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException */ public function testCreateUnknown() { @@ -186,7 +203,10 @@ class PluginDataServiceTest extends DatabaseTestCase /** * @throws ConstraintException * @throws NoSuchItemException + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException */ public function testGetByItemId() { @@ -201,7 +221,10 @@ class PluginDataServiceTest extends DatabaseTestCase /** * @throws ConstraintException * @throws NoSuchItemException + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\NoSuchPropertyException * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException */ public function testGetByItemIdUnkown() { diff --git a/tests/SP/Services/Plugin/PluginOperationTest.php b/tests/SP/Services/Plugin/PluginOperationTest.php new file mode 100644 index 00000000..f6e775b0 --- /dev/null +++ b/tests/SP/Services/Plugin/PluginOperationTest.php @@ -0,0 +1,247 @@ +. + */ + +namespace SP\Tests\Services\Plugin; + +use SP\Core\Exceptions\ConstraintException; +use SP\Plugin\PluginOperation; +use SP\Repositories\NoSuchItemException; +use SP\Services\Plugin\PluginDataService; +use SP\Storage\Database\DatabaseConnectionData; +use SP\Tests\DatabaseTestCase; +use function SP\Tests\setupContext; + +/** + * Class PluginOperationTest + * + * @package SP\Tests\Services\Plugin + */ +class PluginOperationTest extends DatabaseTestCase +{ + + /** + * @var \Closure + */ + private static $pluginOperation; + + /** + * @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 servicio + self::$pluginOperation = function ($name) use ($dic) { + return new PluginOperation($dic->get(PluginDataService::class), $name); + }; + } + + /** + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException + */ + public function testUpdate() + { + /** @var PluginOperation $pluginOperation */ + $pluginOperation = self::$pluginOperation->call($this, 'Authenticator'); + + $data = [1, 2, 3]; + + $this->assertEquals(1, $pluginOperation->update(1, $data)); + $this->assertEquals($data, $pluginOperation->get(1)); + + $data = new \stdClass(); + $data->id = 1; + $data->name = 'test'; + $data->test = new \stdClass(); + + $this->assertEquals(1, $pluginOperation->update(1, $data)); + $this->assertEquals($data, $pluginOperation->get(1)); + } + + /** + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException + */ + public function testUpdateUnknown() + { + /** @var PluginOperation $pluginOperation */ + $pluginOperation = self::$pluginOperation->call($this, 'Authenticator'); + + $data = [1, 2, 3]; + + $this->assertEquals(0, $pluginOperation->update(4, $data)); + $this->assertNull($pluginOperation->get(4)); + + } + + /** + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException + */ + public function testUpdateWrongPlugin() + { + /** @var PluginOperation $pluginOperation */ + $pluginOperation = self::$pluginOperation->call($this, 'Test'); + + $data = [1, 2, 3]; + + $this->assertEquals(0, $pluginOperation->update(1, $data)); + } + + /** + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Repositories\NoSuchItemException + */ + public function testDelete() + { + $this->assertTableRowCount('PluginData', 4); + + /** @var PluginOperation $pluginOperation */ + $pluginOperation = self::$pluginOperation->call($this, 'Authenticator'); + $pluginOperation->delete(1); + + $this->assertTableRowCount('PluginData', 3); + } + + /** + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Repositories\NoSuchItemException + */ + public function testDeleteUnknown() + { + /** @var PluginOperation $pluginOperation */ + $pluginOperation = self::$pluginOperation->call($this, 'Authenticator'); + + $this->expectException(NoSuchItemException::class); + + $pluginOperation->delete(4); + } + + + public function testGet() + { + $this->markTestSkipped('Already tested'); + } + + /** + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException + */ + public function testGetUnknown() + { + /** @var PluginOperation $pluginOperation */ + $pluginOperation = self::$pluginOperation->call($this, 'Authenticator'); + + $this->assertNull($pluginOperation->get(4)); + } + + /** + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException + */ + public function testCreate() + { + /** @var PluginOperation $pluginOperation */ + $pluginOperation = self::$pluginOperation->call($this, 'Authenticator'); + + $data = new \stdClass(); + $data->id = 1; + $data->name = 'test'; + $data->test = new \stdClass(); + + $pluginOperation->create(4, $data); + + $this->assertEquals($data, $pluginOperation->get(4)); + } + + /** + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException + */ + public function testCreateDuplicated() + { + /** @var PluginOperation $pluginOperation */ + $pluginOperation = self::$pluginOperation->call($this, 'Authenticator'); + + $data = new \stdClass(); + $data->id = 1; + $data->name = 'test'; + $data->test = new \stdClass(); + + $this->expectException(ConstraintException::class); + + $this->assertEquals(1, $pluginOperation->create(2, $data)); + } + + /** + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\NoSuchPropertyException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Services\ServiceException + */ + public function testCreateWrongPlugin() + { + /** @var PluginOperation $pluginOperation */ + $pluginOperation = self::$pluginOperation->call($this, 'Test'); + + $data = new \stdClass(); + $data->id = 1; + $data->name = 'test'; + $data->test = new \stdClass(); + + $this->expectException(ConstraintException::class); + + $this->assertEquals(1, $pluginOperation->create(2, $data)); + } +} diff --git a/tests/res/config/config.xml b/tests/res/config/config.xml index 394f1008..f947cbd8 100644 --- a/tests/res/config/config.xml +++ b/tests/res/config/config.xml @@ -10,11 +10,11 @@ 1 1 - 4d7fc39824dba286bd33ae0e68353b75e1181f7f + 6e25e727e111c62fb67f71e79416188468cf6e42 0 0 - 1548499643 - 24275a94c07791c9af1ff211ff6e16c638a900bd + 1548757579 + 56f7423606d1826a78ed319dd580f58e2cd9ca89 sysPass @@ -33,7 +33,7 @@ 0 - c82d9a7be95b0c2acb10082b7fdc97c34ed726fc + 555f5a697f06b6760e3e71f409418743c8546781 PDF JPG diff --git a/tests/res/datasets/syspass_plugin.xml b/tests/res/datasets/syspass_plugin.xml index 96bc20e1..f8431817 100644 --- a/tests/res/datasets/syspass_plugin.xml +++ b/tests/res/datasets/syspass_plugin.xml @@ -28,22 +28,26 @@ 1 Authenticator - data_item1 + def502003606d6eb85aebcb1d9e635f0e6f969d05f064ffb719769a8a91864f0d094ff84674746f6c81ef122d04049fec4682337bada1d2ea272705d2631be4245d3c3dec2c341c5b6b7f0406f7cc9296740132e691c2b96b66057f54e27 + def10000def50200c35308f24d1f3b0501a873018043ca9c05762039fab3b3a9fdb6574cfecec65e2ec833a33c5b7698e37ce8e9b28fe371251b2b6513dfad95dbed69cc27e15c934b63951bce9649d42ca3c9e85e273c32583dad12653cf3ebb0f8b39bafeba085d04c62577ecad4229d91328caf8071e4a94fca947c1a3e5a9f13f7e32d80691e9f55f1779f8db85fb7b9ba463d5571904954df65ce9d7b7c4eb6c16066fd4dc79881c37f065ee656668695cee1f4649ac98f3530706649a5956a9dc5aa4e6a32870478b29ef6563551f5fbff7800c58e030774cd379f9144cd1cca85dd8620078fefe0d3d2a62feb81654d9dd5fc8638bd2c8a2dab01a4a5 2 Authenticator - plugin_data + def50200290e0767802bb0cf1304efb2b9900da6676d51ee1c7a7538e05ebd10a5d9af1fcf658322274a8b906efd2411d71c1e38df3ac68ac6c7e21263aad2bef48aaf719f1c43b369d773cd30087eaa168b26114c2097dff9763295d2d1d7 + def10000def50200235f986cd31997981128329a2a327416007538a5457b30360632a734469faf5247927f223ed2470f6ee4e8687bfafc44cb6cbc9f292aaaaf4adb73bc09cf189502f778ad20e9d55fbda905da11c9f39d51aff7da4c1c36c26676c53b482a96274e868448ff8f924605b87f0079f42934d51838677a368dde2bf0b994708b6181afd7e86ac5f856d25aac5ba9602fb4cd383f6d5cff0417764eabeeb61e615856ad6a424dd65c95805c51e1ceccee3470f0a488dae36157fb33bf115bc7d7e3a5a6fc9a9dc62926737bbea1fff509b0761cd56062d4f8cbe999182b0dccd6e2595a87ec626b315d1cfa4b32f62fb11b81ea6af45d8215203f 2 XML Exporter - data + def502004f363167a52704815e58bebb593b0be863052bbafac43bef4388a4692c124bf45f8968a5be7ce7f1b90a693f79d2f9147ed352334709b629297c34c432f986ff465033e899cddf80282fee6179124ebc12bb3a82 + def10000def50200a5e70a393f85c0bc81ee4a8555d14ca50d1845549e7851dd5e0b75695603819de6ac4f8860bc26b4b9432a9f6c0587f6e3f1b7081d528c7e9422ad7c52fd02be6772955ec0ba9dc3f83e644e8bc9e72e61039703ae17874066443f192d8c0840e13cf7f19d21c495ff81984bd3a2377893e8e5caf99aa25b529ff1fc264002f2372e7bc2ecf824865e7830af1aac2c344798c380cd071eee1d4e5bcd1633a2a9b308620a2136285e247f7b31a406074c858e3f9eaa5e3b3a44af41b02425790ec95f170ab7780f75cdbf448a513dfec71071700b4586b3384911f0ae8a7764076f98fbf5ed63e1b9651f73f6b73675a855a6d02693d3560c 3 DokuWiki - data_item3 + def502009fdf89235fd6c084779a79d720b9fd657ba9563d738cc64ad11f4074f674a79dba7a798c89f250243beae86fb7e7b0d67e57349b6eff051ee26662b297f9efaf572779ac96ee567cbb85d1c77a7197054111eb108da82c6a09da + def10000def50200ac689f83389580d9934abe4109a85f789c64ab443e182d0946fe55ba2a2b77b03227983d4eca8cd2abfa48f94e1752b435c5b70805ee1cbe0198fc5293f2a43098bdbf81ca1436f1b519b3159906ed4db45cd00774c935aeda4cd6cced42b5ad6df3da161a57d31ac46e6c3007dc4c3de7d19a6f11b949c1a09c98f1143c74dd006ecde5285f7b613cb18ce4c1e99d5accce12164d8d6e86e06529fd236091b7340b7a797a88b36b9b517c0b070e91977210153b2b82a2b253c4245b168a95e6238fb7c28bfca523013e0d1093d1b0c3f3e7b185cc12ec7df804c1370b2ea02977d17423433ebc8e38dad674a3d62f106a669f1df093c921 diff --git a/tests/res/datasets/syspass_userGroup.xml b/tests/res/datasets/syspass_userGroup.xml index 207598ba..9073cb58 100644 --- a/tests/res/datasets/syspass_userGroup.xml +++ b/tests/res/datasets/syspass_userGroup.xml @@ -1,27 +1,4 @@ - -