. */ namespace SP\Services\Crypt; use SP\Core\Crypt\Crypt; use SP\Core\Crypt\Hash; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; use SP\Services\Config\ConfigService; use SP\Services\Config\ParameterNotFoundException; use SP\Services\Service; use SP\Services\ServiceException; use SP\Util\Util; /** * Class TemporaryMasterPassService * * @package SP\Services\Crypt */ class TemporaryMasterPassService extends Service { /** * Número máximo de intentos */ const MAX_ATTEMPTS = 50; /** * @var ConfigService */ protected $configService; /** * @var int */ protected $maxTime; /** * Crea una clave temporal para encriptar la clave maestra y guardarla. * * @param int $maxTime El tiempo máximo de validez de la clave * @return string * @throws ServiceException */ public function create($maxTime = 14400) { try { $this->maxTime = time() + $maxTime; // Encriptar la clave maestra con hash aleatorio generado $randomKey = Util::generateRandomBytes(32); $this->configService->save('tempmaster_passkey', Crypt::makeSecuredKey($randomKey)); $this->configService->save('tempmaster_passhash', Hash::hashKey($randomKey)); $this->configService->save('tempmaster_passtime', time()); $this->configService->save('tempmaster_maxtime', $this->maxTime); $this->configService->save('tempmaster_attempts', 0); // Guardar la clave temporal hasta que finalice la sesión $this->context->setTemporaryMasterPass($randomKey); $this->eventDispatcher->notifyEvent('create.tempMasterPassword', new Event($this, EventMessage::factory() ->addDescription(__u('Generar Clave Temporal'))) ); return $randomKey; } catch (\Exception $e) { processException($e); throw new ServiceException(__u('Error al generar clave temporal')); } } /** * Comprueba si la clave temporal es válida * * @param string $pass clave a comprobar * @return bool * @throws ServiceException */ public function checkTempMasterPass($pass) { try { $isValid = false; $passTime = (int)$this->configService->getByParam('tempmaster_passtime'); $passMaxTime = (int)$this->configService->getByParam('tempmaster_maxtime'); $attempts = (int)$this->configService->getByParam('tempmaster_attempts'); // Comprobar si el tiempo de validez o los intentos se han superado if ($passMaxTime === 0) { $this->eventDispatcher->notifyEvent('check.tempMasterPassword', new Event($this, EventMessage::factory()->addDescription(__u('Clave temporal caducada'))) ); return $isValid; } if ((!empty($passTime) && time() > $passMaxTime) || $attempts >= self::MAX_ATTEMPTS ) { $this->expire(); return $isValid; } $isValid = Hash::checkHashKey($pass, $this->configService->getByParam('tempmaster_passhash')); if (!$isValid) { $this->configService->save('tempmaster_attempts', $attempts + 1); } return $isValid; } catch (ParameterNotFoundException $e) { return false; } catch (\Exception $e) { processException($e); throw new ServiceException(__u('Error al comprobar clave temporal')); } } /** * @throws \SP\Core\Exceptions\ConstraintException * @throws \SP\Core\Exceptions\QueryException */ protected function expire() { $this->configService->save('tempmaster_passkey', ''); $this->configService->save('tempmaster_passhash', ''); $this->configService->save('tempmaster_maxtime', ''); $this->configService->save('tempmaster_attempts', 0); $this->eventDispatcher->notifyEvent('expire.tempMasterPassword', new Event($this, EventMessage::factory() ->addDescription(__u('Clave temporal caducada'))) ); } /** * Devuelve la clave maestra que ha sido encriptada con la clave temporal * * @param $key string con la clave utilizada para encriptar * @return string con la clave maestra desencriptada * @throws \Defuse\Crypto\Exception\CryptoException * @throws \SP\Services\Config\ParameterNotFoundException */ public function getUsingKey($key) { return Crypt::decrypt($this->configService->getByParam('tempmaster_pass'), Crypt::unlockSecuredKey($this->configService->getByParam('tempmaster_passkey'), $key), $key); } /** * @return int */ public function getMaxTime() { return $this->maxTime; } /** * @throws \Psr\Container\ContainerExceptionInterface * @throws \Psr\Container\NotFoundExceptionInterface */ protected function initialize() { $this->configService = $this->dic->get(ConfigService::class); } }