diff --git a/app/modules/web/Controllers/ConfigEncryptionController.php b/app/modules/web/Controllers/ConfigEncryptionController.php index 5af6fa79..03c2fece 100644 --- a/app/modules/web/Controllers/ConfigEncryptionController.php +++ b/app/modules/web/Controllers/ConfigEncryptionController.php @@ -30,16 +30,13 @@ use SP\Core\Crypt\Hash; use SP\Core\Crypt\Session as CryptSession; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; -use SP\Core\Messages\MailMessage; use SP\Http\JsonResponse; use SP\Modules\Web\Controllers\Traits\JsonTrait; use SP\Services\Config\ConfigService; use SP\Services\Crypt\MasterPassService; use SP\Services\Crypt\TemporaryMasterPassService; use SP\Services\Crypt\UpdateMasterPassRequest; -use SP\Services\MailService; use SP\Services\Task\TaskFactory; -use SP\Services\User\UserService; use SP\Util\Util; /** @@ -101,19 +98,17 @@ class ConfigEncryptionController extends SimpleControllerBase $task = $taskId !== null ? TaskFactory::create(__FUNCTION__, $taskId) : null; - $request = new UpdateMasterPassRequest( - $currentMasterPass, - $newMasterPass, - $configService->getByParam('masterPwd'), - $task - ); - try { + $request = new UpdateMasterPassRequest( + $currentMasterPass, + $newMasterPass, + $configService->getByParam(MasterPassService::PARAM_MASTER_PASS_HASH), + $task + ); + $this->eventDispatcher->notifyEvent('update.masterPassword.start', new Event($this)); $mastePassService->changeMasterPassword($request); - $configService->save('masterPwd', $request->getHash()); - $configService->save('lastupdatempass', time()); $this->eventDispatcher->notifyEvent('update.masterPassword.end', new Event($this)); } catch (\Exception $e) { @@ -133,8 +128,7 @@ class ConfigEncryptionController extends SimpleControllerBase try { $this->eventDispatcher->notifyEvent('update.masterPassword.hash', new Event($this)); - $configService->save('masterPwd', Hash::hashKey($newMasterPass)); - $configService->save('lastupdatempass', time()); + $mastePassService->updateConfig(Hash::hashKey($newMasterPass)); } catch (\Exception $e) { processException($e); @@ -157,10 +151,10 @@ class ConfigEncryptionController extends SimpleControllerBase } try { - $configService = $this->dic->get(ConfigService::class); - $configService->save('masterPwd', Hash::hashKey(CryptSession::getSessionKey($this->session))); + $masterPassService = $this->dic->get(MasterPassService::class); + $masterPassService->updateConfig(Hash::hashKey(CryptSession::getSessionKey($this->session))); - $this->eventDispatcher->notifyEvent('refresh.masterPassword', + $this->eventDispatcher->notifyEvent('refresh.masterPassword.hash', new Event($this, EventMessage::factory()->addDescription(__u('Hash de clave maestra actualizado')))); $this->returnJsonResponse(JsonResponse::JSON_SUCCESS, __u('Hash de clave maestra actualizado')); @@ -184,25 +178,13 @@ class ConfigEncryptionController extends SimpleControllerBase $key = $temporaryMasterPassService->create($this->request->analyzeInt('temporary_masterpass_maxtime', 3600)); $groupId = $this->request->analyzeInt('temporary_masterpass_group'); - $sendEmail = $this->request->analyzeBool('temporary_masterpass_email'); - - if ($this->configData->isMailEnabled() && $sendEmail && $groupId) { - $mailMessage = new MailMessage(); - $mailMessage->setTitle(sprintf(__('Clave Maestra %s'), Util::getAppInfo('appname'))); - $mailMessage->addDescription(__('Se ha generado una nueva clave para el acceso a sysPass y se solicitará en el siguiente inicio.')); - $mailMessage->addDescriptionLine(); - $mailMessage->addDescription(sprintf(__('La nueva clave es: %s'), $key)); - $mailMessage->addDescriptionLine(); - $mailMessage->addDescription(sprintf(__('Esta clave estará activa hasta: %s'), date('r', $temporaryMasterPassService->getMaxTime()))); - $mailMessage->addDescriptionLine(); - $mailMessage->addDescription(__('No olvide acceder lo antes posible para guardar los cambios.')); + $sendEmail = $this->configData->isMailEnabled() + && $this->request->analyzeBool('temporary_masterpass_email') + && $groupId > 0; + if ($sendEmail) { try { - $emails = array_map(function ($value) { - return $value->email; - }, $this->dic->get(UserService::class)->getUserEmailForGroup($groupId)); - - $this->dic->get(MailService::class)->sendBatch($mailMessage->getTitle(), $emails, $mailMessage); + $temporaryMasterPassService->sendByEmailForGroup($groupId, $key); $this->returnJsonResponse(JsonResponse::JSON_SUCCESS, __u('Clave Temporal Generada'), [__u('Email enviado')]); } catch (\Exception $e) { diff --git a/lib/SP/Repositories/CustomField/CustomFieldRepository.php b/lib/SP/Repositories/CustomField/CustomFieldRepository.php index 8265f6b7..be1a288a 100644 --- a/lib/SP/Repositories/CustomField/CustomFieldRepository.php +++ b/lib/SP/Repositories/CustomField/CustomFieldRepository.php @@ -276,9 +276,9 @@ class CustomFieldRepository extends Repository implements RepositoryItemInterfac /** * Returns all the items * - * @return CustomFieldData[] - * @throws QueryException + * @return \SP\Storage\Database\QueryResult * @throws ConstraintException + * @throws QueryException */ public function getAll() { @@ -286,13 +286,13 @@ class CustomFieldRepository extends Repository implements RepositoryItemInterfac $queryData->setMapClassName(CustomFieldData::class); $queryData->setQuery('SELECT * FROM CustomFieldData'); - return $this->db->doSelect($queryData)->getDataAsArray(); + return $this->db->doSelect($queryData); } /** * Returns all the items that were encryptes * - * @return CustomFieldData[] + * @return \SP\Storage\Database\QueryResult * @throws QueryException * @throws ConstraintException */ @@ -302,7 +302,7 @@ class CustomFieldRepository extends Repository implements RepositoryItemInterfac $queryData->setMapClassName(CustomFieldData::class); $queryData->setQuery('SELECT * FROM CustomFieldData WHERE `key` IS NOT NULL'); - return $this->db->doSelect($queryData)->getDataAsArray(); + return $this->db->doSelect($queryData); } /** diff --git a/lib/SP/Services/Config/ConfigService.php b/lib/SP/Services/Config/ConfigService.php index 041dc2e5..2993eea9 100644 --- a/lib/SP/Services/Config/ConfigService.php +++ b/lib/SP/Services/Config/ConfigService.php @@ -56,23 +56,21 @@ class ConfigService extends Service public function getByParam($param, $default = null) { try { - /** @var ConfigData $data */ - $data = $this->configRepository->getByParam($param)->getData(); + $result = $this->configRepository->getByParam($param); } catch (\Exception $e) { throw new ServiceException($e->getMessage(), ServiceException::ERROR, null, $e->getCode(), $e); } - if (empty($data)) { - if ($default !== null) { - return $default; - } - + if ($result->getNumRows() === 0) { throw new NoSuchItemException( sprintf(__('Parámetro no encontrado (%s)'), $param) ); } + /** @var ConfigData $data */ + $data = $result->getData(); + return empty($data->value) ? $default : $data->value; } diff --git a/lib/SP/Services/Config/ParameterNotFoundException.php b/lib/SP/Services/Config/ParameterNotFoundException.php deleted file mode 100644 index 57972266..00000000 --- a/lib/SP/Services/Config/ParameterNotFoundException.php +++ /dev/null @@ -1,37 +0,0 @@ -. - */ - -namespace SP\Services\Config; - -use SP\Core\Exceptions\SPException; - -/** - * Class ParameterNotFoundException - * - * @package SP\Services\Config - */ -class ParameterNotFoundException extends SPException -{ - -} \ No newline at end of file diff --git a/lib/SP/Services/Crypt/MasterPassService.php b/lib/SP/Services/Crypt/MasterPassService.php index e20816b0..f147fc23 100644 --- a/lib/SP/Services/Crypt/MasterPassService.php +++ b/lib/SP/Services/Crypt/MasterPassService.php @@ -25,14 +25,11 @@ namespace SP\Services\Crypt; use SP\Core\Crypt\Hash; -use SP\Core\Events\Event; -use SP\Core\Events\EventMessage; use SP\Services\Account\AccountCryptService; use SP\Services\Config\ConfigService; use SP\Services\CustomField\CustomFieldCryptService; use SP\Services\Service; use SP\Services\ServiceException; -use SP\Storage\Database\Database; /** * Class MasterPassService @@ -41,6 +38,9 @@ use SP\Storage\Database\Database; */ class MasterPassService extends Service { + const PARAM_MASTER_PASS_TIME = 'lastupdatempass'; + const PARAM_MASTER_PASS_HASH = 'masterPwd'; + /** * @var ConfigService */ @@ -63,9 +63,7 @@ class MasterPassService extends Service */ public function checkUserUpdateMPass($userMPassTime) { - $lastUpdateMPass = $this->configService->getByParam('lastupdatempass'); - - return $userMPassTime >= $lastUpdateMPass; + return $userMPassTime >= $this->configService->getByParam(self::PARAM_MASTER_PASS_TIME, 0); } @@ -78,43 +76,37 @@ class MasterPassService extends Service */ public function checkMasterPassword($masterPassword) { - return Hash::checkHashKey($masterPassword, $this->configService->getByParam('masterPwd')); + return Hash::checkHashKey($masterPassword, $this->configService->getByParam(self::PARAM_MASTER_PASS_HASH)); } /** * @param UpdateMasterPassRequest $request + * * @throws \Exception */ public function changeMasterPassword(UpdateMasterPassRequest $request) { - $db = $this->dic->get(Database::class); + $this->transactionAware(function () use ($request) { + $this->accountCryptService->updateMasterPassword($request); - if (!$db->beginTransaction()) { - try { - $this->accountCryptService->updateMasterPassword($request); + $this->accountCryptService->updateHistoryMasterPassword($request); - $this->accountCryptService->updateHistoryMasterPassword($request); + $this->customFieldCryptService->updateMasterPassword($request); - $this->customFieldCryptService->updateMasterPassword($request); + $this->updateConfig($request->getHash()); + }); + } - if (!$db->endTransaction()) { - throw new ServiceException(__u('No es posible finalizar una transacción')); - } - } catch (\Exception $e) { - if ($db->rollbackTransaction()) { - $this->eventDispatcher->notifyEvent('update.masterPassword.rollback', - new Event($this, EventMessage::factory() - ->addDescription(__u('Rollback'))) - ); - - debugLog('Rollback'); - } - - throw $e; - } - } else { - throw new ServiceException(__u('No es posible iniciar una transacción')); - } + /** + * @param $hash + * + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException + */ + public function updateConfig($hash) + { + $this->configService->save(self::PARAM_MASTER_PASS_HASH, $hash); + $this->configService->save(self::PARAM_MASTER_PASS_TIME, time()); } /** diff --git a/lib/SP/Services/Crypt/SecureSessionService.php b/lib/SP/Services/Crypt/SecureSessionService.php index 5fdb5b8d..22e3bfc6 100644 --- a/lib/SP/Services/Crypt/SecureSessionService.php +++ b/lib/SP/Services/Crypt/SecureSessionService.php @@ -52,6 +52,10 @@ class SecureSessionService extends Service * @var string */ protected $seed; + /** + * @var Request + */ + protected $request; /** * Returns the encryption key @@ -134,6 +138,7 @@ class SecureSessionService extends Service protected function initialize() { $this->fileCache = $this->dic->get(FileCache::class); + $this->request = $this->dic->get(Request::class); $this->seed = $this->config->getConfigData()->getPasswordSalt(); } } \ No newline at end of file diff --git a/lib/SP/Services/Crypt/TemporaryMasterPassService.php b/lib/SP/Services/Crypt/TemporaryMasterPassService.php index 7f39fc07..510a8b49 100644 --- a/lib/SP/Services/Crypt/TemporaryMasterPassService.php +++ b/lib/SP/Services/Crypt/TemporaryMasterPassService.php @@ -29,11 +29,14 @@ use SP\Core\Crypt\Hash; use SP\Core\Crypt\Session; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; +use SP\Core\Messages\MailMessage; use SP\DataModel\Dto\ConfigRequest; use SP\Repositories\NoSuchItemException; use SP\Services\Config\ConfigService; +use SP\Services\MailService; use SP\Services\Service; use SP\Services\ServiceException; +use SP\Services\User\UserService; use SP\Util\Util; /** @@ -47,6 +50,15 @@ class TemporaryMasterPassService extends Service * Número máximo de intentos */ const MAX_ATTEMPTS = 50; + /** + * Parámetros de configuración + */ + const PARAM_PASS = 'tempmaster_pass'; + const PARAM_KEY = 'tempmaster_passkey'; + const PARAM_HASH = 'tempmaster_passhash'; + const PARAM_TIME = 'tempmaster_passtime'; + const PARAM_MAX_TIME = 'tempmaster_maxtime'; + const PARAM_ATTEMPTS = 'tempmaster_attempts'; /** * @var ConfigService */ @@ -74,12 +86,12 @@ class TemporaryMasterPassService extends Service $secureKey = Crypt::makeSecuredKey($randomKey); $configRequest = new ConfigRequest(); - $configRequest->add('tempmaster_pass', Crypt::encrypt(Session::getSessionKey($this->context), $secureKey, $randomKey)); - $configRequest->add('tempmaster_passkey', $secureKey); - $configRequest->add('tempmaster_passhash', Hash::hashKey($randomKey)); - $configRequest->add('tempmaster_passtime', time()); - $configRequest->add('tempmaster_maxtime', $this->maxTime); - $configRequest->add('tempmaster_attempts', 0); + $configRequest->add(self::PARAM_PASS, Crypt::encrypt(Session::getSessionKey($this->context), $secureKey, $randomKey)); + $configRequest->add(self::PARAM_KEY, $secureKey); + $configRequest->add(self::PARAM_HASH, Hash::hashKey($randomKey)); + $configRequest->add(self::PARAM_TIME, time()); + $configRequest->add(self::PARAM_MAX_TIME, $this->maxTime); + $configRequest->add(self::PARAM_ATTEMPTS, 0); $this->configService->saveBatch($configRequest); @@ -111,9 +123,9 @@ class TemporaryMasterPassService extends Service { try { $isValid = false; - $passTime = (int)$this->configService->getByParam('tempmaster_passtime'); - $passMaxTime = (int)$this->configService->getByParam('tempmaster_maxtime'); - $attempts = (int)$this->configService->getByParam('tempmaster_attempts'); + $passTime = (int)$this->configService->getByParam(self::PARAM_TIME); + $passMaxTime = (int)$this->configService->getByParam(self::PARAM_MAX_TIME); + $attempts = (int)$this->configService->getByParam(self::PARAM_ATTEMPTS); // Comprobar si el tiempo de validez o los intentos se han superado if ($passMaxTime === 0) { @@ -132,10 +144,10 @@ class TemporaryMasterPassService extends Service return $isValid; } - $isValid = Hash::checkHashKey($pass, $this->configService->getByParam('tempmaster_passhash')); + $isValid = Hash::checkHashKey($pass, $this->configService->getByParam(self::PARAM_HASH)); if (!$isValid) { - $this->configService->save('tempmaster_attempts', $attempts + 1); + $this->configService->save(self::PARAM_ATTEMPTS, $attempts + 1); } return $isValid; @@ -154,12 +166,12 @@ class TemporaryMasterPassService extends Service protected function expire() { $configRequest = new ConfigRequest(); - $configRequest->add('tempmaster_pass', ''); - $configRequest->add('tempmaster_passkey', ''); - $configRequest->add('tempmaster_passhash', ''); - $configRequest->add('tempmaster_passtime', 0); - $configRequest->add('tempmaster_maxtime', 0); - $configRequest->add('tempmaster_attempts', 0); + $configRequest->add(self::PARAM_PASS, ''); + $configRequest->add(self::PARAM_KEY, ''); + $configRequest->add(self::PARAM_HASH, ''); + $configRequest->add(self::PARAM_TIME, 0); + $configRequest->add(self::PARAM_MAX_TIME, 0); + $configRequest->add(self::PARAM_ATTEMPTS, 0); $this->configService->saveBatch($configRequest); @@ -169,6 +181,53 @@ class TemporaryMasterPassService extends Service ); } + /** + * @param $groupId + * @param $key + * + * @throws ServiceException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException + */ + public function sendByEmailForGroup($groupId, $key) + { + $mailMessage = $this->getMessageForEmail($key); + + $emails = array_map(function ($value) { + return $value->email; + }, $this->dic->get(UserService::class)->getUserEmailForGroup($groupId)); + + $this->dic->get(MailService::class)->sendBatch($mailMessage->getTitle(), $emails, $mailMessage); + } + + /** + * @param $key + * + * @return MailMessage + */ + private function getMessageForEmail($key) + { + $mailMessage = new MailMessage(); + $mailMessage->setTitle(sprintf(__('Clave Maestra %s'), Util::getAppInfo('appname'))); + $mailMessage->addDescription(__('Se ha generado una nueva clave para el acceso a sysPass y se solicitará en el siguiente inicio.')); + $mailMessage->addDescriptionLine(); + $mailMessage->addDescription(sprintf(__('La nueva clave es: %s'), $key)); + $mailMessage->addDescriptionLine(); + $mailMessage->addDescription(sprintf(__('Esta clave estará activa hasta: %s'), date('r', $this->getMaxTime()))); + $mailMessage->addDescriptionLine(); + $mailMessage->addDescription(__('No olvide acceder lo antes posible para guardar los cambios.')); + + return $mailMessage; + } + + /** + * @return int + */ + public function getMaxTime() + { + return $this->maxTime; + } + /** * Devuelve la clave maestra que ha sido encriptada con la clave temporal * @@ -181,19 +240,11 @@ class TemporaryMasterPassService extends Service */ public function getUsingKey($key) { - return Crypt::decrypt($this->configService->getByParam('tempmaster_pass'), - $this->configService->getByParam('tempmaster_passkey'), + return Crypt::decrypt($this->configService->getByParam(self::PARAM_PASS), + $this->configService->getByParam(self::PARAM_KEY), $key); } - /** - * @return int - */ - public function getMaxTime() - { - return $this->maxTime; - } - /** * @throws \Psr\Container\ContainerExceptionInterface * @throws \Psr\Container\NotFoundExceptionInterface diff --git a/lib/SP/Services/CustomField/CustomFieldService.php b/lib/SP/Services/CustomField/CustomFieldService.php index 8ed21dba..4e476f45 100644 --- a/lib/SP/Services/CustomField/CustomFieldService.php +++ b/lib/SP/Services/CustomField/CustomFieldService.php @@ -55,6 +55,7 @@ class CustomFieldService extends Service * Returns the form Id for a given name * * @param $name + * * @return string */ public static function getFormIdForName($name) @@ -65,15 +66,16 @@ class CustomFieldService extends Service /** * Desencriptar y formatear los datos del campo * - * @param string $data - * @param string $key + * @param string $data + * @param string $key * @param SessionContext $sessionContext + * * @return string * @throws CryptoException */ public static function decryptData($data, $key, SessionContext $sessionContext) { - if ($data !== '' && $key !== '') { + if (!empty($data) && empty($key)) { return self::formatValue(Crypt::decrypt($data, $key, CryptSession::getSessionKey($sessionContext))); } @@ -84,6 +86,7 @@ class CustomFieldService extends Service * Formatear el valor del campo * * @param $value string El valor del campo + * * @return string */ public static function formatValue($value) @@ -100,6 +103,7 @@ class CustomFieldService extends Service * * @param $moduleId * @param $itemId + * * @return array */ public function getForModuleById($moduleId, $itemId) @@ -111,6 +115,7 @@ class CustomFieldService extends Service * Updates an item * * @param CustomFieldData $customFieldData + * * @return bool * @throws CryptoException * @throws QueryException @@ -144,6 +149,7 @@ class CustomFieldService extends Service * @param int $id * @param int $moduleId * @param int $definitionId + * * @return bool * @throws SPException */ @@ -183,7 +189,8 @@ class CustomFieldService extends Service /** * @param CustomFieldData $customFieldData - * @param null $key + * @param null $key + * * @throws CryptoException * @throws ServiceException */ @@ -204,6 +211,7 @@ class CustomFieldService extends Service * Eliminar los datos de los campos personalizados del módulo * * @param int $definitionId + * * @return int * @throws QueryException * @throws \SP\Core\Exceptions\ConstraintException @@ -217,7 +225,8 @@ class CustomFieldService extends Service * Eliminar los datos de los campos personalizados del módulo * * @param int[] $ids - * @param int $moduleId + * @param int $moduleId + * * @return bool * @throws QueryException * @throws \SP\Core\Exceptions\ConstraintException @@ -231,6 +240,7 @@ class CustomFieldService extends Service * Eliminar los datos de los elementos de una definición * * @param array $definitionIds + * * @return int * @throws \SP\Core\Exceptions\ConstraintException * @throws \SP\Core\Exceptions\QueryException @@ -244,7 +254,8 @@ class CustomFieldService extends Service * Updates an item * * @param CustomFieldData $customFieldData - * @param string $masterPass + * @param string $masterPass + * * @return bool * @throws CryptoException * @throws QueryException @@ -260,18 +271,22 @@ class CustomFieldService extends Service /** * @return CustomFieldData[] + * @throws QueryException + * @throws \SP\Core\Exceptions\ConstraintException */ public function getAll() { - return $this->customFieldRepository->getAll(); + return $this->customFieldRepository->getAll()->getDataAsArray(); } /** * @return CustomFieldData[] + * @throws QueryException + * @throws \SP\Core\Exceptions\ConstraintException */ public function getAllEncrypted() { - return $this->customFieldRepository->getAllEncrypted(); + return $this->customFieldRepository->getAllEncrypted()->getDataAsArray(); } /** diff --git a/lib/SP/Services/Service.php b/lib/SP/Services/Service.php index b4f903ac..7f569d74 100644 --- a/lib/SP/Services/Service.php +++ b/lib/SP/Services/Service.php @@ -28,7 +28,9 @@ use DI\Container; use Psr\Container\ContainerInterface; use SP\Config\Config; use SP\Core\Context\ContextInterface; +use SP\Core\Events\Event; use SP\Core\Events\EventDispatcher; +use SP\Core\Events\EventMessage; use SP\Storage\Database\Database; /** @@ -61,6 +63,7 @@ abstract class Service * Service constructor. * * @param Container $dic + * * @throws \DI\DependencyException * @throws \DI\NotFoundException */ @@ -79,7 +82,7 @@ abstract class Service /** * Bubbles a Closure in a database transaction * - * @param \Closure $closure + * @param \Closure $closure * * @return mixed * @throws ServiceException @@ -101,6 +104,11 @@ abstract class Service debugLog('Transaction:Rollback'); + $this->eventDispatcher->notifyEvent('database.rollback', + new Event($this, EventMessage::factory() + ->addDescription(__u('Rollback'))) + ); + throw $e; } } else { diff --git a/tests/Services/Account/AccountCryptServiceTest.php b/tests/Services/Account/AccountCryptServiceTest.php index 6168a466..ff505c9a 100644 --- a/tests/Services/Account/AccountCryptServiceTest.php +++ b/tests/Services/Account/AccountCryptServiceTest.php @@ -2,8 +2,8 @@ /** * sysPass * - * @author nuxsmin - * @link https://syspass.org + * @author nuxsmin + * @link https://syspass.org * @copyright 2012-2018, Rubén Domínguez nuxsmin@$syspass.org * * This file is part of sysPass. @@ -43,7 +43,7 @@ class AccountCryptServiceTest extends DatabaseTestCase { const CURRENT_MASTERPASS = '12345678900'; const NEW_MASTERPASS = '00123456789'; - const CURRENT_HASH = '$2y$10$p/x8ECCP1Lz/SjbGQy.6/OJ/.OLICBLGkXPiVkaA5Kf1.1HvRQOWG'; + const CURRENT_HASH = '$2y$10$xtsuN2PUvgSH/0mrfBlsbOActVgCjYcqDqC6L3T9QraNxZC4RXGYa'; /** * @var AccountService */ @@ -114,7 +114,7 @@ class AccountCryptServiceTest extends DatabaseTestCase */ public function testUpdateHistoryMasterPassword() { - $request = new UpdateMasterPassRequest(self::CURRENT_MASTERPASS, self::NEW_MASTERPASS, '$2y$10$xtsuN2PUvgSH/0mrfBlsbOActVgCjYcqDqC6L3T9QraNxZC4RXGYa'); + $request = new UpdateMasterPassRequest(self::CURRENT_MASTERPASS, self::NEW_MASTERPASS, self::CURRENT_HASH); self::$service->updateHistoryMasterPassword($request); diff --git a/tests/Services/Crypt/MasterPassServiceTest.php b/tests/Services/Crypt/MasterPassServiceTest.php new file mode 100644 index 00000000..678cd513 --- /dev/null +++ b/tests/Services/Crypt/MasterPassServiceTest.php @@ -0,0 +1,194 @@ +. + */ + +namespace SP\Tests\Services\Crypt; + +use SP\Core\Crypt\Crypt; +use SP\Services\Account\AccountService; +use SP\Services\Crypt\MasterPassService; +use SP\Services\Crypt\UpdateMasterPassRequest; +use SP\Services\CustomField\CustomFieldService; +use SP\Storage\Database\DatabaseConnectionData; +use SP\Tests\DatabaseTestCase; +use SP\Tests\Services\Account\AccountCryptServiceTest; +use function SP\Tests\setupContext; + +/** + * Class MasterPassServiceTest + * + * @package SP\Tests\Services + */ +class MasterPassServiceTest extends DatabaseTestCase +{ + /** + * @var CustomFieldService + */ + private static $customFieldService; + /** + * @var AccountService + */ + private static $accountService; + /** + * @var MasterPassService + */ + private static $service; + + /** + * @throws \DI\NotFoundException + * @throws \SP\Core\Context\ContextException + * @throws \DI\DependencyException + */ + public static function setUpBeforeClass() + { + $dic = setupContext(); + + self::$dataset = 'syspass_accountCrypt.xml'; + + // Datos de conexión a la BBDD + self::$databaseConnectionData = $dic->get(DatabaseConnectionData::class); + + // Inicializar el repositorio + self::$service = $dic->get(MasterPassService::class); + self::$accountService = $dic->get(AccountService::class); + self::$customFieldService = $dic->get(CustomFieldService::class); + + } + + /** + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \Exception + */ + public function testChangeMasterPassword() + { + $request = new UpdateMasterPassRequest(AccountCryptServiceTest::CURRENT_MASTERPASS, AccountCryptServiceTest::NEW_MASTERPASS, AccountCryptServiceTest::CURRENT_HASH); + + self::$service->changeMasterPassword($request); + + $this->checckAccounts($request); + $this->checkAccountsHistory($request); + $this->checkCustomFields(); + + $this->assertTrue(self::$service->checkMasterPassword(AccountCryptServiceTest::NEW_MASTERPASS)); + + $this->assertTrue(self::$service->checkUserUpdateMPass(time())); + $this->assertFalse(self::$service->checkUserUpdateMPass(time() - 10)); + } + + /** + * @param UpdateMasterPassRequest $request + * + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Repositories\NoSuchItemException + */ + private function checckAccounts(UpdateMasterPassRequest $request) + { + $account = self::$accountService->getPasswordForId(1); + $pass = Crypt::decrypt($account->getPass(), $account->getKey(), $request->getNewMasterPass()); + + $this->assertEquals('&¿\'f!i$XwSwc', $pass); + + $account = self::$accountService->getPasswordForId(2); + $pass = Crypt::decrypt($account->getPass(), $account->getKey(), $request->getNewMasterPass()); + + $this->assertEquals('&¿\'f!i$XwSwc', $pass); + } + + /** + * @param UpdateMasterPassRequest $request + * + * @throws \Defuse\Crypto\Exception\CryptoException + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Repositories\NoSuchItemException + */ + private function checkAccountsHistory(UpdateMasterPassRequest $request) + { + // Verify accounts' password history data + $account = self::$accountService->getPasswordHistoryForId(3); + $pass = Crypt::decrypt($account->getPass(), $account->getKey(), $request->getNewMasterPass()); + + $this->assertEquals($request->getHash(), $account->getMPassHash()); + $this->assertEquals('_{/uHL\>\'Oj0', $pass); + + $account = self::$accountService->getPasswordHistoryForId(4); + $pass = Crypt::decrypt($account->getPass(), $account->getKey(), $request->getNewMasterPass()); + + $this->assertEquals($request->getHash(), $account->getMPassHash()); + $this->assertEquals('-{?^··\mjCgetPasswordHistoryForId(5); + $pass = Crypt::decrypt($account->getPass(), $account->getKey(), $request->getNewMasterPass()); + + $this->assertEquals($request->getHash(), $account->getMPassHash()); + $this->assertEquals('-{?^··\mjCgetPasswordHistoryForId(6); + $pass = Crypt::decrypt($account->getPass(), $account->getKey(), $request->getNewMasterPass()); + + $this->assertEquals($request->getHash(), $account->getMPassHash()); + $this->assertEquals('-{?^··\mjCgetPasswordHistoryForId(7); + $pass = Crypt::decrypt($account->getPass(), $account->getKey(), $request->getNewMasterPass()); + + $this->assertEquals($request->getHash(), $account->getMPassHash()); + $this->assertEquals('-{?^··\mjCgetAllEncrypted(); + + $data = Crypt::decrypt($result[0]->getData(), $result[0]->getKey(), AccountCryptServiceTest::NEW_MASTERPASS); + + $this->assertEquals('1234', $data); + } + + /** + * @throws \SP\Repositories\NoSuchItemException + * @throws \SP\Services\ServiceException + */ + public function testCheckUserUpdateMPass() + { + $this->assertTrue(self::$service->checkUserUpdateMPass(time())); + $this->assertFalse(self::$service->checkUserUpdateMPass(1528236611 - 10)); + } + + /** + * @throws \SP\Repositories\NoSuchItemException + * @throws \SP\Services\ServiceException + */ + public function testCheckMasterPassword() + { + $this->assertTrue(self::$service->checkMasterPassword(AccountCryptServiceTest::CURRENT_MASTERPASS)); + $this->assertFalse(self::$service->checkMasterPassword(AccountCryptServiceTest::NEW_MASTERPASS)); + } +} diff --git a/tests/res/datasets/syspass_accountCrypt.xml b/tests/res/datasets/syspass_accountCrypt.xml index ee2e2a22..92e2c754 100644 --- a/tests/res/datasets/syspass_accountCrypt.xml +++ b/tests/res/datasets/syspass_accountCrypt.xml @@ -223,5 +223,33 @@ 0 + + + 1 + 10 + 1 + 1 + 6465663530323030633262353536613539613465333330646461323833363730363462623861326463336630643963386565333935366134326631326135326261323035633036663063313933313263626465353630396562303133356364613461353738636534616263323436343235613739343338663461393231353433623437633062386134363566336466663131373061613162663532356466646434383165613664333763303537396132 + 6465663130303030646566353032303061356237393366343238663337393936356539393836656663363632396332613462336662323431666131343731326332333138323465376632366639313863383663653164636330393838333735343463326237316232383361663135633731363438326630303863313135326563623238383939313939346139376165613836623432613534333166383261343734343565636336376137643462633266396263343065653162333236343030373163333334386338626331613632323165613534346433396630636537343538356561653432376266373131633864366237336166316561613237623630643863626631643531666636366133366562636364353232643538633734653664626363613534646334366662303739626631653537626530646231643363316464313264303139633665663437633366353431303231633233376639303066333633323838613864346464393463323637306365313239393864626237396235333262623266383330323164663062656631326138363664646132343132653338333535636137646465613364336663366535303532346634653961313435366466313034626238376433633532353837643036613162383066613361613064643330633866356239373338663930336535653432653362363333333739333863 + + + 2 + 61 + 1 + 2 + 4C6F72656D20697073756D20646F6C6F722073697420616D65742C20636F6E73656374657475722061646970697363696E6720656C69742E205365642075742074696E636964756E74206C6F72656D2E205072616573656E74207665686963756C6120766F6C7574706174206C696265726F2073697420616D65742066617563696275732E2041656E65616E20766974616520617263752071756973206C616375732070756C76696E617220737573636970697420617420656765742074656C6C75732E204E616D2066656C6973207475727069732C207363656C657269737175652075742066656C69732061632C2074696E636964756E74206D6178696D7573206D692E205365642076756C7075746174652076697461652073656D20616320736F6C6C696369747564696E2E20446F6E6563206672696E67696C6C61206C6F626F7274697320657820657520706F72747469746F722E20457469616D2073656D70657220736F6C6C696369747564696E207665686963756C612E20467573636520766172697573206E756C6C61206D657475732C206E65632076697665727261206E696268206469676E697373696D2069642E + + + + + + lastupdatempass + 1528236611 + + + masterPwd + $2y$10$xtsuN2PUvgSH/0mrfBlsbOActVgCjYcqDqC6L3T9QraNxZC4RXGYa + +