diff --git a/.gitignore b/.gitignore index 2aa48837..c735930b 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,7 @@ app/temp/* app/modules/web/plugins/* vendor/* +.phpstorm.meta.php +composer.phar + !.blank \ No newline at end of file diff --git a/app/modules/web/Controllers/AccountController.php b/app/modules/web/Controllers/AccountController.php index ba191fc4..8481abcb 100644 --- a/app/modules/web/Controllers/AccountController.php +++ b/app/modules/web/Controllers/AccountController.php @@ -163,7 +163,7 @@ class AccountController extends ControllerBase implements CrudControllerInterfac } catch (\Exception $e) { processException($e); - ErrorUtil::showExceptionInView($this->view, $e); + ErrorUtil::showExceptionInView($this->view, $e, 'account'); } } @@ -267,7 +267,7 @@ class AccountController extends ControllerBase implements CrudControllerInterfac } catch (\Exception $e) { processException($e); - ErrorUtil::showExceptionInView($this->view, $e); + ErrorUtil::showExceptionInView($this->view, $e, 'account'); } } @@ -310,7 +310,7 @@ class AccountController extends ControllerBase implements CrudControllerInterfac } catch (\Exception $e) { processException($e); - ErrorUtil::showExceptionInView($this->view, $e); + ErrorUtil::showExceptionInView($this->view, $e, 'account'); } } @@ -356,7 +356,7 @@ class AccountController extends ControllerBase implements CrudControllerInterfac } catch (\Exception $e) { processException($e); - ErrorUtil::showExceptionInView($this->view, $e); + ErrorUtil::showExceptionInView($this->view, $e, 'account'); } } @@ -398,7 +398,7 @@ class AccountController extends ControllerBase implements CrudControllerInterfac } catch (\Exception $e) { processException($e); - ErrorUtil::showExceptionInView($this->view, $e); + ErrorUtil::showExceptionInView($this->view, $e, 'account'); } } @@ -442,7 +442,7 @@ class AccountController extends ControllerBase implements CrudControllerInterfac } catch (\Exception $e) { processException($e); - ErrorUtil::showExceptionInView($this->view, $e); + ErrorUtil::showExceptionInView($this->view, $e, 'account-editpass'); } } @@ -484,7 +484,7 @@ class AccountController extends ControllerBase implements CrudControllerInterfac } catch (\Exception $e) { processException($e); - ErrorUtil::showExceptionInView($this->view, $e); + ErrorUtil::showExceptionInView($this->view, $e, 'account-history'); } } @@ -515,7 +515,7 @@ class AccountController extends ControllerBase implements CrudControllerInterfac } catch (\Exception $e) { processException($e); - ErrorUtil::showExceptionInView($this->view, $e); + ErrorUtil::showExceptionInView($this->view, $e, 'account-request'); } } diff --git a/app/modules/web/Controllers/ConfigEncryptionController.php b/app/modules/web/Controllers/ConfigEncryptionController.php index ef0c36e3..2075bac0 100644 --- a/app/modules/web/Controllers/ConfigEncryptionController.php +++ b/app/modules/web/Controllers/ConfigEncryptionController.php @@ -68,6 +68,7 @@ class ConfigEncryptionController extends SimpleControllerBase $newMasterPassR = Request::analyzeEncrypted('newMasterPwdR'); $confirmPassChange = Request::analyzeBool('confirmPassChange', false); $noAccountPassChange = Request::analyzeBool('chkNoAccountChange', false); + $taskId = Request::analyzeString('taskId'); if (!$mastePassService->checkUserUpdateMPass($this->session->getUserData()->getLastUpdateMPass())) { $this->returnJsonResponse(JsonResponse::JSON_SUCCESS_STICKY, __u('Clave maestra actualizada'), [__u('Reinicie la sesión para cambiarla')]); @@ -102,11 +103,13 @@ class ConfigEncryptionController extends SimpleControllerBase if (!$noAccountPassChange) { Util::lockApp($this->session->getUserData()->getId(), 'masterpass'); + $task = $taskId !== null ? TaskFactory::create(__FUNCTION__, $taskId) : null; + $request = new UpdateMasterPassRequest( $currentMasterPass, $newMasterPass, $configService->getByParam('masterPwd'), - TaskFactory::create(__FUNCTION__, 'masterpass') + $task ); try { @@ -126,7 +129,9 @@ class ConfigEncryptionController extends SimpleControllerBase } finally { Util::unlockApp(); - TaskFactory::end($request->getTask()->getTaskId()); + if ($task) { + TaskFactory::end($task->getTaskId()); + } } } else { try { diff --git a/app/modules/web/Controllers/ConfigManagerController.php b/app/modules/web/Controllers/ConfigManagerController.php index 7d65032e..208c58c7 100644 --- a/app/modules/web/Controllers/ConfigManagerController.php +++ b/app/modules/web/Controllers/ConfigManagerController.php @@ -221,9 +221,12 @@ class ConfigManagerController extends ControllerBase $template->setBase('config'); $template->addTemplate('encryption'); - $template->assign('mailSecurity', ['SSL', 'TLS']); - $template->assign('numAccounts', $this->dic->get(AccountService::class)->getTotalNumAccounts()->num); - $template->assign('taskId', Task::genTaskId('masterpass')); + $numAccounts = $this->dic->get(AccountService::class)->getTotalNumAccounts()->num; + $template->assign('numAccounts', $numAccounts); + + if ($numAccounts > 500) { + $template->assign('taskId', Task::genTaskId('masterpass')); + } $configService = $this->dic->get(ConfigService::class); diff --git a/app/modules/web/Controllers/Helpers/Account/AccountActionsHelper.php b/app/modules/web/Controllers/Helpers/Account/AccountActionsHelper.php index a3cd2fdd..29e34527 100644 --- a/app/modules/web/Controllers/Helpers/Account/AccountActionsHelper.php +++ b/app/modules/web/Controllers/Helpers/Account/AccountActionsHelper.php @@ -105,8 +105,9 @@ class AccountActionsHelper extends HelperBase && $accountAcl->isShowViewPass() ) { $action = $accountActionsDto->getPublicLinkId() ? $this->getPublicLinkRefreshAction() : $this->getPublicLinkAction(); + $itemId = $accountActionsDto->getPublicLinkId() ?: $accountActionsDto->getAccountId(); - $actionsEnabled[] = $action->addData('item-id', $accountActionsDto->getPublicLinkId()); + $actionsEnabled[] = $action->addData('item-id', $itemId); } if ($accountAcl->isShowViewPass()) { diff --git a/app/modules/web/Controllers/Helpers/Account/AccountHelper.php b/app/modules/web/Controllers/Helpers/Account/AccountHelper.php index d94f4978..93927354 100644 --- a/app/modules/web/Controllers/Helpers/Account/AccountHelper.php +++ b/app/modules/web/Controllers/Helpers/Account/AccountHelper.php @@ -177,7 +177,7 @@ class AccountHelper extends HelperBase } if (!$this->dic->get(MasterPassService::class)->checkUserUpdateMPass($this->session->getUserData()->getLastUpdateMPass())) { - throw new UpdatedMasterPassException(UnauthorizedPageException::INFO); + throw new UpdatedMasterPassException(UpdatedMasterPassException::INFO); } } diff --git a/app/modules/web/Controllers/TaskController.php b/app/modules/web/Controllers/TaskController.php new file mode 100644 index 00000000..7da8b8d5 --- /dev/null +++ b/app/modules/web/Controllers/TaskController.php @@ -0,0 +1,92 @@ +. + */ + +namespace SP\Modules\Web\Controllers; + +use DI\Container; +use Klein\Klein; +use SP\Core\Session\Session; +use SP\Core\Task; +use SP\Core\TaskFactory; +use SP\Services\ServiceException; +use SP\Services\Task\TaskService; + +/** + * Class TaskController + * + * @package SP\Modules\Web\Controllers + */ +class TaskController +{ + /** + * @var Container + */ + private $container; + + /** + * TaskController constructor. + * + * @param Container $container + * @throws \Psr\Container\ContainerExceptionInterface + * @throws \Psr\Container\NotFoundExceptionInterface + */ + public function __construct(Container $container) + { + $this->container = $container; + } + + /** + * @param string $taskId + * @throws \Psr\Container\ContainerExceptionInterface + * @throws \Psr\Container\NotFoundExceptionInterface + */ + public function runTaskAction($taskId) + { + Session::close(); + + $router = $this->container->get(Klein::class); + $router->response()->header('Content-Type', 'text/event-stream'); + $router->response()->header('Cache-Control', 'no-store, no-cache'); + $router->response()->header('Access-Control-Allow-Origin', '*'); + $router->response()->send(true); + + try { + $this->container->get(TaskService::class)->run($taskId); + } catch (ServiceException $e) { + processException($e); + } + } + + /** + * @param $taskId + */ + public function testTaskAction($taskId) + { + $task = TaskFactory::create($taskId, Task::genTaskId($taskId)); + + TaskFactory::update($task->getTaskId(), TaskFactory::createMessage($task->getTaskId(), 'Prueba Tarea')); + + echo $task->getTaskId(); + } +} \ No newline at end of file diff --git a/app/modules/web/themes/material-blue/views/config/encryption.inc b/app/modules/web/themes/material-blue/views/config/encryption.inc index 0733c228..6532ac74 100644 --- a/app/modules/web/themes/material-blue/views/config/encryption.inc +++ b/app/modules/web/themes/material-blue/views/config/encryption.inc @@ -114,8 +114,7 @@ - = 500): ?> - + diff --git a/lib/SP/Core/Task.php b/lib/SP/Core/Task.php index d4308ba2..a81b2fe8 100644 --- a/lib/SP/Core/Task.php +++ b/lib/SP/Core/Task.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. @@ -25,6 +25,7 @@ namespace SP\Core; use SP\Core\Messages\TaskMessage; +use SP\Core\Session\Session; use SP\Util\Util; /** @@ -130,7 +131,7 @@ class Task */ public static function genTaskId($name) { - return uniqid($name, true); + return uniqid($name); } /** @@ -295,7 +296,7 @@ class Task file_put_contents($this->fileTask, serialize($this)); if ($lockSession === true) { - session_write_close(); + Session::close(); } return $this; diff --git a/lib/SP/Core/TaskFactory.php b/lib/SP/Core/TaskFactory.php index 4437dc6b..9b63b67d 100644 --- a/lib/SP/Core/TaskFactory.php +++ b/lib/SP/Core/TaskFactory.php @@ -41,13 +41,13 @@ class TaskFactory /** * Crear una tarea para la actualización de estado de la actualización * - * @param $name - * @param $id + * @param string $name + * @param string $id * @return Task */ public static function create($name, $id) { - return self::add((new Task($name, $id))->register(false)); + return self::add((new Task($name, $id))->register()); } /** diff --git a/lib/SP/Http/Request.php b/lib/SP/Http/Request.php index 83573851..0eee33e6 100644 --- a/lib/SP/Http/Request.php +++ b/lib/SP/Http/Request.php @@ -114,7 +114,7 @@ class Request { $encryptedData = self::analyzeString($param); - if ($encryptedData === '') { + if ($encryptedData === null) { return ''; } @@ -142,7 +142,7 @@ class Request public static function analyzeString($param, $default = null) { if (!isset($_REQUEST[$param])) { - return (string)$default; + return $default; } return filter_var($_REQUEST[$param], FILTER_SANITIZE_STRING); @@ -156,7 +156,7 @@ class Request public static function analyzeEmail($param, $default = null) { if (!isset($_REQUEST[$param])) { - return (string)$default; + return $default; } return filter_var($_REQUEST[$param], FILTER_SANITIZE_EMAIL); diff --git a/lib/SP/Repositories/Account/AccountHistoryRepository.php b/lib/SP/Repositories/Account/AccountHistoryRepository.php index 0bb45f55..be48e39c 100644 --- a/lib/SP/Repositories/Account/AccountHistoryRepository.php +++ b/lib/SP/Repositories/Account/AccountHistoryRepository.php @@ -66,13 +66,13 @@ class AccountHistoryRepository extends Repository implements RepositoryItemInter WHERE AH.accountId = ? ORDER BY AH.id DESC'; - $Data = new QueryData(); - $Data->setQuery($query); - $Data->addParam($id); + $queryData = new QueryData(); + $queryData->setQuery($query); + $queryData->addParam($id); $items = []; - foreach (DbWrapper::getResultsArray($Data, $this->db) as $history) { + foreach (DbWrapper::getResultsArray($queryData, $this->db) as $history) { // Comprobamos si la entrada en el historial es la primera (no tiene editor ni fecha de edición) if (empty($history->dateEdit) || $history->dateEdit === '0000-00-00 00:00:00') { $date = $history->dateAdd . ' - ' . $history->userAdd; @@ -130,7 +130,7 @@ class AccountHistoryRepository extends Repository implements RepositoryItemInter */ public function create($itemData) { - $Data = new QueryData(); + $queryData = new QueryData(); $query = /** @lang SQL */ 'INSERT INTO AccountHistory (accountId, @@ -178,14 +178,14 @@ class AccountHistoryRepository extends Repository implements RepositoryItemInter isPrivateGroup, ?,?,? FROM Account WHERE id = ?'; - $Data->setQuery($query); - $Data->addParam($itemData['isModify']); - $Data->addParam($itemData['isDelete']); - $Data->addParam($itemData['masterPassHash']); - $Data->addParam($itemData['id']); - $Data->setOnErrorMessage(__u('Error al actualizar el historial')); + $queryData->setQuery($query); + $queryData->addParam($itemData['isModify']); + $queryData->addParam($itemData['isDelete']); + $queryData->addParam($itemData['masterPassHash']); + $queryData->addParam($itemData['id']); + $queryData->setOnErrorMessage(__u('Error al actualizar el historial')); - return DbWrapper::getQuery($Data, $this->db); + return DbWrapper::getQuery($queryData, $this->db); } /** @@ -211,14 +211,14 @@ class AccountHistoryRepository extends Repository implements RepositoryItemInter $query = /** @lang SQL */ 'DELETE FROM AccountHistory WHERE id = ? LIMIT 1'; - $Data = new QueryData(); - $Data->setQuery($query); - $Data->addParam($id); - $Data->setOnErrorMessage(__u('Error al eliminar la cuenta')); + $queryData = new QueryData(); + $queryData->setQuery($query); + $queryData->addParam($id); + $queryData->setOnErrorMessage(__u('Error al eliminar la cuenta')); - DbWrapper::getQuery($Data, $this->db); + DbWrapper::getQuery($queryData, $this->db); - return $Data->getQueryNumRows() === 1; + return $queryData->getQueryNumRows() === 1; } /** @@ -278,12 +278,12 @@ class AccountHistoryRepository extends Repository implements RepositoryItemInter LEFT JOIN User U2 ON AH.userEditId = U2.id WHERE AH.id = ? LIMIT 1'; - $Data = new QueryData(); - $Data->setQuery($query); - $Data->setMapClassName(AccountHistoryData::class); - $Data->addParam($id); + $queryData = new QueryData(); + $queryData->setQuery($query); + $queryData->setMapClassName(AccountHistoryData::class); + $queryData->addParam($id); - $queryRes = DbWrapper::getResults($Data, $this->db); + $queryRes = DbWrapper::getResults($queryData, $this->db); if ($queryRes === false) { throw new SPException(__u('No se pudieron obtener los datos de la cuenta'), SPException::CRITICAL); @@ -310,12 +310,12 @@ class AccountHistoryRepository extends Repository implements RepositoryItemInter LEFT JOIN User U2 ON AH.userEditId = U2.id ORDER BY AH.id DESC'; - $Data = new QueryData(); - $Data->setQuery($query); + $queryData = new QueryData(); + $queryData->setQuery($query); $items = []; - foreach (DbWrapper::getResultsArray($Data, $this->db) as $history) { + foreach (DbWrapper::getResultsArray($queryData, $this->db) as $history) { // Comprobamos si la entrada en el historial es la primera (no tiene editor ni fecha de edición) if (empty($history->dateEdit) || $history->dateEdit === '0000-00-00 00:00:00') { $date = $history->dateAdd . ' - ' . $history->userAdd; @@ -432,7 +432,7 @@ class AccountHistoryRepository extends Repository implements RepositoryItemInter $queryData = new QueryData(); $queryData->setQuery($query); - return DbWrapper::getResultsArray($queryData); + return DbWrapper::getResultsArray($queryData, $this->db); } /** diff --git a/lib/SP/Services/Account/AccountCryptService.php b/lib/SP/Services/Account/AccountCryptService.php index 846ed048..a748888b 100644 --- a/lib/SP/Services/Account/AccountCryptService.php +++ b/lib/SP/Services/Account/AccountCryptService.php @@ -88,9 +88,11 @@ class AccountCryptService extends Service throw new ServiceException(__u('Error al obtener las claves de las cuentas'), ServiceException::ERROR); } - $taskId = $this->request->getTask()->getTaskId(); + if ($this->request->useTask()) { + $taskId = $this->request->getTask()->getTaskId(); - TaskFactory::update($taskId, TaskFactory::createMessage($taskId, __('Actualizar Clave Maestra'))); + TaskFactory::update($taskId, TaskFactory::createMessage($taskId, __('Actualizar Clave Maestra'))); + } $counter = 0; $startTime = time(); @@ -107,14 +109,25 @@ class AccountCryptService extends Service if ($counter % 100 === 0) { $eta = Util::getETA($startTime, $counter, $numAccounts); - $taskMessage = TaskFactory::createMessage($taskId, __('Actualizar Clave Maestra')) - ->setMessage(sprintf(__('Cuentas actualizadas: %d /%d'), $counter, $numAccounts)) - ->setProgress(round(($counter * 100) / $numAccounts, 2)) - ->setTime(sprintf('ETA: %ds (%.2f/s)', $eta[0], $eta[1])); + if (isset($taskId)) { + $taskMessage = TaskFactory::createMessage($taskId, __('Actualizar Clave Maestra')) + ->setMessage(sprintf(__('Cuentas actualizadas: %d / %d'), $counter, $numAccounts)) + ->setProgress(round(($counter * 100) / $numAccounts, 2)) + ->setTime(sprintf('ETA: %ds (%.2f/s)', $eta[0], $eta[1])); - TaskFactory::update($taskId, $taskMessage); - debugLog($taskMessage->composeText()); + TaskFactory::update($taskId, $taskMessage); + + debugLog($taskMessage->composeText()); + } else { + debugLog( + sprintf(__('Cuentas actualizadas: %d / %d - %d%% - ETA: %ds (%.2f/s)'), + $counter, + $numAccounts, + round(($counter * 100) / $numAccounts, 2), + $eta[0], $eta[1]) + ); + } } $accountRequest = new AccountPasswordRequest(); @@ -161,9 +174,11 @@ class AccountCryptService extends Service new Event($this, EventMessage::factory()->addDescription(__u('Actualizar Clave Maestra'))) ); - $taskId = $this->request->getTask(); + if ($this->request->useTask()) { + $taskId = $this->request->getTask(); - TaskFactory::update($taskId, TaskFactory::createMessage($taskId, __u('Actualizar Clave Maestra'))); + TaskFactory::update($taskId, TaskFactory::createMessage($taskId, __u('Actualizar Clave Maestra'))); + } $eventMessage = $this->processAccounts($this->accountService->getAccountsPassData(), function ($request) { $this->accountService->updatePasswordMasterPass($request); @@ -204,7 +219,11 @@ class AccountCryptService extends Service $configData = $this->config->getConfigData(); $currentMasterPassHash = $this->request->getCurrentHash(); - $taskId = $this->request->getTask()->getTaskId(); + + if ($this->request->useTask()) { + $taskId = $this->request->getTask()->getTaskId(); + } + $eventMessage = EventMessage::factory(); foreach ($accounts as $account) { @@ -217,14 +236,24 @@ class AccountCryptService extends Service if ($counter % 100 === 0) { $eta = Util::getETA($startTime, $counter, $numAccounts); - $taskMessage = TaskFactory::createMessage($taskId, __('Actualizar Clave Maestra')) - ->setMessage(sprintf(__('Cuentas actualizadas: %d /%d'), $counter, $numAccounts)) - ->setProgress(round(($counter * 100) / $numAccounts, 2)) - ->setTime(sprintf('ETA: %ds (%.2f/s)', $eta[0], $eta[1])); + if (isset($taskId)) { + $taskMessage = TaskFactory::createMessage($taskId, __('Actualizar Clave Maestra')) + ->setMessage(sprintf(__('Cuentas actualizadas: %d / %d'), $counter, $numAccounts)) + ->setProgress(round(($counter * 100) / $numAccounts, 2)) + ->setTime(sprintf('ETA: %ds (%.2f/s)', $eta[0], $eta[1])); - TaskFactory::update($taskId, $taskMessage); + TaskFactory::update($taskId, $taskMessage); - debugLog($taskMessage->composeText()); + debugLog($taskMessage->composeText()); + } else { + debugLog( + sprintf(__('Cuentas actualizadas: %d / %d - %d%% - ETA: %ds (%.2f/s)'), + $counter, + $numAccounts, + round(($counter * 100) / $numAccounts, 2), + $eta[0], $eta[1]) + ); + } } if (isset($account->mPassHash) && $account->mPassHash !== $currentMasterPassHash) { @@ -285,7 +314,9 @@ class AccountCryptService extends Service $taskId = $this->request->getTask(); - TaskFactory::update($taskId, TaskFactory::createMessage($taskId, __u('Actualizar Clave Maestra (H)'))); + if ($this->request->useTask()) { + TaskFactory::update($taskId, TaskFactory::createMessage($taskId, __u('Actualizar Clave Maestra (H)'))); + } $eventMessage = $this->processAccounts($this->accountHistoryService->getAccountsPassData(), function ($request) { /** @var AccountPasswordRequest $request */ diff --git a/lib/SP/Services/Crypt/MasterPassService.php b/lib/SP/Services/Crypt/MasterPassService.php index 757f01b2..1fd1d6df 100644 --- a/lib/SP/Services/Crypt/MasterPassService.php +++ b/lib/SP/Services/Crypt/MasterPassService.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. @@ -25,7 +25,8 @@ namespace SP\Services\Crypt; use SP\Core\Crypt\Hash; -use SP\Core\Exceptions\SPException; +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; @@ -79,32 +80,38 @@ class MasterPassService extends Service /** * @param UpdateMasterPassRequest $request - * @throws SPException - * @throws ServiceException + * @throws \Exception */ public function changeMasterPassword(UpdateMasterPassRequest $request) { $db = $this->dic->get(Database::class); - if (!DbWrapper::beginTransaction($db)) { - throw new ServiceException(__u('No es posible iniciar una transacción'), ServiceException::ERROR); - } - try { + if (!DbWrapper::beginTransaction($db)) { + throw new ServiceException(__u('No es posible iniciar una transacción'), ServiceException::ERROR); + } + $this->accountCryptService->updateMasterPassword($request); $this->accountCryptService->updateHistoryMasterPassword($request); $this->customFieldCryptService->updateMasterPassword($request); - } catch (ServiceException $e) { - DbWrapper::rollbackTransaction($db); + + if (!DbWrapper::endTransaction($db)) { + throw new ServiceException(__u('No es posible finalizar una transacción'), ServiceException::ERROR); + } + } catch (\Exception $e) { + if (DbWrapper::rollbackTransaction($db)) { + $this->eventDispatcher->notifyEvent('update.masterPassword.rollback', + new Event($this, EventMessage::factory() + ->addDescription(__u('Rollback'))) + ); + + debugLog('Rollback'); + } throw $e; } - - if (!DbWrapper::endTransaction($db)) { - throw new ServiceException(__u('No es posible finalizar una transacción'), ServiceException::ERROR); - } } /** diff --git a/lib/SP/Services/Crypt/UpdateMasterPassRequest.php b/lib/SP/Services/Crypt/UpdateMasterPassRequest.php index 643627cb..d38708ba 100644 --- a/lib/SP/Services/Crypt/UpdateMasterPassRequest.php +++ b/lib/SP/Services/Crypt/UpdateMasterPassRequest.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. @@ -64,7 +64,7 @@ class UpdateMasterPassRequest * @param string $currentHash * @param Task $task */ - public function __construct($currentMasterPass, $newMasterPass, $currentHash, Task $task) + public function __construct($currentMasterPass, $newMasterPass, $currentHash, Task $task = null) { $this->currentMasterPass = $currentMasterPass; $this->newMasterPass = $newMasterPass; @@ -97,6 +97,14 @@ class UpdateMasterPassRequest return $this->task; } + /** + * @return bool + */ + public function useTask() + { + return $this->task !== null; + } + /** * @return string */ diff --git a/lib/SP/Services/CustomField/CustomFieldCryptService.php b/lib/SP/Services/CustomField/CustomFieldCryptService.php index 8796b489..2989539e 100644 --- a/lib/SP/Services/CustomField/CustomFieldCryptService.php +++ b/lib/SP/Services/CustomField/CustomFieldCryptService.php @@ -82,23 +82,33 @@ class CustomFieldCryptService extends Service /** * @param callable $decryptor - * @throws ServiceException */ protected function processUpdateMasterPassword(callable $decryptor) { $customFields = $this->customFieldService->getAll(); if (count($customFields) === 0) { - throw new ServiceException(__u('No hay datos de campos personalizados'), ServiceException::INFO); + $this->eventDispatcher->notifyEvent('update.masterPassword.customFields', + new Event($this, EventMessage::factory() + ->addDescription(__u('Actualizar Clave Maestra')) + ->addDescription(__u('No hay datos de campos personalizados'))) + ); + return; } $this->eventDispatcher->notifyEvent('update.masterPassword.customFields.start', - new Event($this, EventMessage::factory()->addDescription(__u('Actualizar Clave Maestra'))) + new Event($this, EventMessage::factory() + ->addDescription(__u('Actualizar Clave Maestra')) + ->addDescription(__u('Actualizando datos encriptados'))) ); - $taskId = $this->request->getTask()->getTaskId(); + if ($this->request->useTask()) { + $taskId = $this->request->getTask()->getTaskId(); - TaskFactory::update($taskId, TaskFactory::createMessage($taskId, __('Actualizar Clave Maestra'))->setMessage(__u('Actualizando datos encriptados'))); + TaskFactory::update($taskId, + TaskFactory::createMessage($taskId, __('Actualizar Clave Maestra')) + ->setMessage(__('Actualizando datos encriptados'))); + } $errors = []; $success = []; @@ -144,8 +154,6 @@ class CustomFieldCryptService extends Service Crypt::unlockSecuredKey($customFieldData->getKey(), $this->request->getCurrentMasterPass()), $this->request->getCurrentMasterPass()); }); - } catch (ServiceException $e) { - throw $e; } catch (\Exception $e) { $this->eventDispatcher->notifyEvent('exception', new Event($e)); diff --git a/lib/SP/Services/Task/TaskService.php b/lib/SP/Services/Task/TaskService.php new file mode 100644 index 00000000..d50e896f --- /dev/null +++ b/lib/SP/Services/Task/TaskService.php @@ -0,0 +1,217 @@ +. + */ + +namespace SP\Services\Task; + +use SP\Core\Task; +use SP\Core\TaskFactory; +use SP\Services\Service; +use SP\Services\ServiceException; +use SP\Util\Util; + +/** + * Class TaskService + * + * @package SP\Services + */ +class TaskService extends Service +{ + /** + * Tiempo de espera en cada intento de inicialización + */ + const STARTUP_WAIT_TIME = 5; + /** + * Intentos de inicialización + */ + const STARTUP_WAIT_COUNT = 30; + + /** + * @var Task Instancia de la tarea + */ + protected $task; + /** + * @var string Archivo de bloqueo + */ + protected $lockFile; + /** + * @var string Directorio de las tareas + */ + protected $dir; + /** + * @var string ID de la tarea + */ + protected $taskId; + /** + * @var string Archivo de la tarea + */ + protected $taskFile; + + /** + * Realizar acción + * + * @param string $taskId + * @throws ServiceException + */ + public function run($taskId) + { + $this->taskId = $taskId; + $this->dir = Util::getTempDir(); + + if ($this->dir === false || !$this->getLock()) { + throw new ServiceException(__('No es posible crear archivo de bloqueo')); + } + + $this->taskFile = $this->dir . DIRECTORY_SEPARATOR . $this->taskId . '.task'; + + $count = 0; + + while (!$this->checkTaskRegistered() || !$this->checkTaskFile()) { + if ($count >= self::STARTUP_WAIT_COUNT || !file_exists($this->lockFile)) { + debugLog('Aborting ...'); + + die(1); + } else { + debugLog(sprintf('Waiting for task "%s" (%ds) ...', $taskId, (self::STARTUP_WAIT_COUNT - $count) * self::STARTUP_WAIT_TIME)); + + $count++; + sleep(self::STARTUP_WAIT_TIME); + } + } + + $this->readTaskStatus(); + + die(0); + } + + /** + * Obtener un bloqueo para la ejecución de la tarea + * + * @return bool + */ + private function getLock() + { + $this->lockFile = $this->dir . DIRECTORY_SEPARATOR . $this->taskId . '.lock'; + + if (file_exists($this->lockFile)) { + $timeout = self::STARTUP_WAIT_COUNT * self::STARTUP_WAIT_TIME; + + if (filemtime($this->lockFile) + $timeout < time()) { + unlink($this->lockFile); + + return $this->updateLock(); + } + + return false; + } + + return $this->updateLock(); + } + + /** + * Actualizar el tiempo del archivo de bloqueo + */ + protected function updateLock() + { + return file_put_contents($this->lockFile, time()) !== false; + } + + /** + * Comprueba si una tarea ha sido registrada en la sesión + * + * @return bool + */ + protected function checkTaskRegistered() + { + if (is_object($this->task)) { + debugLog('Task detected: ' . $this->task->getTaskId()); + + return true; + } + + if (file_exists($this->taskFile)) { + $task = file_get_contents($this->taskFile); + + if ($task !== false) { + $this->task = unserialize($task); + } + + return is_object($this->task); + } + + return false; + } + + /** + * Comprobar si el archivo de salida de la tarea existe + */ + protected function checkTaskFile() + { + return file_exists($this->task->getFileOut()); + } + + /** + * Leer el estado de una tarea y enviarlo + */ + protected function readTaskStatus() + { + debugLog('Tracking task: ' . $this->task->getTaskId()); + + $id = 0; + $failCount = 0; + $file = $this->task->getFileOut(); + $interval = $this->task->getInterval(); + + $taskMessage = TaskFactory::createMessage($this->task->getTaskId(), __('Esperando actualización de progreso ...')); + + while ($failCount <= self::STARTUP_WAIT_COUNT && file_exists($this->taskFile)) { + $content = file_get_contents($file); + + if (!empty($content)) { + $this->sendMessage($id, $content); + $id++; + } else { + debugLog($taskMessage->composeJson()); + + $this->sendMessage($id, $taskMessage->composeJson()); + $failCount++; + } + + sleep($interval); + } + } + + /** + * Enviar un mensaje + * + * @param $id + * @param $message + */ + protected function sendMessage($id, $message) + { + echo 'id: ', $id, PHP_EOL, 'data: ', $message, PHP_EOL, PHP_EOL; + + ob_flush(); + flush(); + } +} \ No newline at end of file diff --git a/lib/SP/Util/Util.php b/lib/SP/Util/Util.php index 56e5c8e8..2ef0853b 100644 --- a/lib/SP/Util/Util.php +++ b/lib/SP/Util/Util.php @@ -327,7 +327,7 @@ class Util public static function getTempDir() { $sysTmp = sys_get_temp_dir(); - $appTmp = Init::$SERVERROOT . DIRECTORY_SEPARATOR . 'tmp'; + $appTmp = APP_PATH . DIRECTORY_SEPARATOR . 'temp'; $file = 'syspass.test'; $checkDir = function ($dir) use ($file) { diff --git a/public/js/app-actions.js b/public/js/app-actions.js index 84d635f5..1ed26111 100644 --- a/public/js/app-actions.js +++ b/public/js/app-actions.js @@ -657,31 +657,17 @@ sysPass.Actions = function (Common) { positive: { title: Common.config().LANG[43], onClick: function (e) { - const $useTask = $obj.find("input[name='useTask']"); - const $taskStatus = $("#taskStatus"); + let taskRunner; + const taskId = $obj.find("input[name='taskId']").val(); - $taskStatus.empty().html(Common.config().LANG[62]); - - if ($useTask.length > 0 && $useTask.val() == 1) { - const optsTask = Common.appRequests().getRequestOpts(); - optsTask.url = ajaxUrl.entrypoint; - optsTask.data = { - source: $obj.find("input[name='lock']").val(), - taskId: $obj.find("input[name='taskId']").val() - }; - - const task = Common.appRequests().getActionEvent(optsTask, function (result) { - let text = result.task + " - " + result.message + " - " + result.time + " - " + result.progress + "%"; - text += "
" + Common.config().LANG[62]; - - $taskStatus.empty().html(text); - }); + if (taskId) { + taskRunner = task(taskId); } const opts = Common.appRequests().getRequestOpts(); opts.url = ajaxUrl.entrypoint; opts.method = "get"; - opts.useFullLoading = true; + opts.useFullLoading = !!taskId; opts.data = $obj.serialize(); Common.appRequests().getActionCall(opts, function (json) { @@ -690,8 +676,8 @@ sysPass.Actions = function (Common) { if (json.status !== 0) { $obj.find(":input[name=h]").val(""); } else { - if (task !== undefined) { - task.close(); + if (taskRunner !== undefined) { + taskRunner.close(); } setTimeout(function () { @@ -781,30 +767,16 @@ sysPass.Actions = function (Common) { positive: { title: Common.config().LANG[43], onClick: function (e) { - const $useTask = $obj.find("input[name='useTask']"); - const $taskStatus = $("#taskStatus"); + let taskRunner; + const taskId = $obj.find("input[name='taskId']").val(); - $taskStatus.empty().html(Common.config().LANG[62]); - - if ($useTask.length > 0 && $useTask.val() == 1) { - const optsTask = Common.appRequests().getRequestOpts(); - optsTask.url = ajaxUrl.entrypoint; - optsTask.data = { - source: $obj.find("input[name='lock']").val(), - taskId: $obj.find("input[name='taskId']").val() - }; - - const task = Common.appRequests().getActionEvent(optsTask, function (result) { - let text = result.task + " - " + result.message + " - " + result.time + " - " + result.progress + "%"; - text += "
" + Common.config().LANG[62]; - - $taskStatus.empty().html(text); - }); + if (taskId) { + taskRunner = task(taskId); } const opts = Common.appRequests().getRequestOpts(); opts.url = ajaxUrl.entrypoint; - opts.useFullLoading = true; + opts.useFullLoading = !!taskId; opts.data = $obj.serialize(); Common.appRequests().getActionCall(opts, function (json) { @@ -812,8 +784,8 @@ sysPass.Actions = function (Common) { $obj.find(":input[type=password]").val(""); - if (task !== undefined) { - task.close(); + if (taskRunner !== undefined) { + taskRunner.close(); } }); } @@ -956,14 +928,13 @@ sysPass.Actions = function (Common) { const itemId = $obj.data("item-id"); const opts = Common.appRequests().getRequestOpts(); - opts.url = ajaxUrl.entrypoint; - opts.data = { - r: $obj.data("action-route"), - accountId: itemId, - notify: notify, - sk: Common.sk.get(), - isAjax: 1 - }; + + if (itemId) { + opts.url = ajaxUrl.entrypoint + "?r=" + $obj.data("action-route") + "/" + itemId + "/" + notify; + } else { + opts.url = ajaxUrl.entrypoint + "?r=" + $obj.data("action-route"); + opts.data = $obj.serialize(); + } Common.appRequests().getActionCall(opts, function (json) { Common.msg.out(json); @@ -1544,6 +1515,23 @@ sysPass.Actions = function (Common) { } }; + const task = function (taskId) { + const $taskStatus = $("#taskStatus"); + + $taskStatus.empty().html(Common.config().LANG[62]); + + const opts = Common.appRequests().getRequestOpts(); + opts.method = "get"; + opts.url = ajaxUrl.entrypoint + "?r=task/runTask/" + taskId; + + return Common.appRequests().getActionEvent(opts, function (result) { + let text = result.task + " - " + result.message + " - " + result.time + " - " + result.progress + "%"; + text += "
" + Common.config().LANG[62]; + + $taskStatus.empty().html(text); + }); + }; + return { doAction: doAction, appMgmt: appMgmt, diff --git a/public/js/app-actions.min.js b/public/js/app-actions.min.js index abc593b4..94a5281d 100644 --- a/public/js/app-actions.min.js +++ b/public/js/app-actions.min.js @@ -1,8 +1,8 @@ var $jscomp={scope:{},findInternal:function(b,e,l){b instanceof String&&(b=String(b));for(var f=b.length,h=0;h'+c+""),g=d.find("img");if(0===g.length)return m(c);g.hide();$.magnificPopup.open({items:{src:d,type:"inline"},callbacks:{open:function(){var a= +c){$.magnificPopup.open({items:{src:a||"",type:"inline"},callbacks:{open:function(){var a=$("#box-popup");b.appTriggers().views.common(a);a.find(":input:text:visible:first").focus();void 0!==c&&"function"===typeof c.open&&c.open()},close:function(){void 0!==c&&"function"===typeof c.close&&c.close()}},showCloseBtn:!1})},w=function(a,c){var d=$('
'+c+"
"),g=d.find("img");if(0===g.length)return m(c);g.hide();$.magnificPopup.open({items:{src:d,type:"inline"},callbacks:{open:function(){var a= this;g.on("click",function(){a.close()});setTimeout(function(){var a=b.resizeImage(g);d.css({backgroundColor:"#fff",width:a.width,height:"auto"});g.show("slow")},500)}}})},p={view:function(a){e.info("account:show");h(b.appRequests().getRouteForQuery(a.data("action-route"),a.data("item-id")),"account")},viewHistory:function(a){e.info("account:showHistory");h(b.appRequests().getRouteForQuery(a.data("action-route"),a.val()),"account")},edit:function(a){e.info("account:edit");h(b.appRequests().getRouteForQuery(a.data("action-route"), a.data("item-id")),"account")},"delete":function(a){e.info("account:delete");var c='

'+b.config().LANG[3]+"

";mdlDialog().show({text:c,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault();b.msg.error(b.config().LANG[44])}},positive:{title:b.config().LANG[43],onClick:function(d){d=b.appRequests().getRequestOpts();d.url=f.entrypoint;d.data={r:"account/saveDelete/"+a.data("item-id"),sk:b.sk.get()};b.appRequests().getActionCall(d,function(d){b.msg.out(d); p.search(a)})}}})},viewPass:function(a){e.info("account:showpass");var c=a.data("parent-id")||0,c=0===c?a.data("item-id"):c,d=a.data("history")||0,g=b.appRequests().getRequestOpts();g.url=f.entrypoint;g.method="get";g.data={r:a.data("action-route")+"/"+c+"/"+d,sk:b.sk.get(),isAjax:1};b.appRequests().getActionCall(g,function(a){0!==a.status?b.msg.out(a):(a=$(a.data.html),m(a),l=setTimeout(function(){$.magnificPopup.close()},3E4),a.on("mouseleave",function(){clearTimeout(l);l=setTimeout(function(){$.magnificPopup.close()}, @@ -13,32 +13,32 @@ var c=a.data("parent-id"),c=void 0===c?a.data("item-id"):c;h(b.appRequests().get a.data.itemId),"account")})},listFiles:function(a){e.info("account:getfiles");var c=b.appRequests().getRequestOpts();c.method="get";c.type="html";c.url=f.entrypoint;c.data={r:a.data("action-route")+"/"+a.data("item-id"),del:a.data("delete"),sk:b.sk.get()};b.appRequests().getActionCall(c,function(b){a.html(b)})},search:function(a){e.info("account:search");var c=$("#frmSearch");c.find("input[name='sk']").val(b.sk.get());c.find("input[name='skey']").val();c.find("input[name='sorder']").val();void 0!== a&&c.find("input[name='start']").val(0);a=b.appRequests().getRequestOpts();a.url=f.entrypoint+"?r="+c.data("action-route");a.method="get";a.data=c.serialize();b.appRequests().getActionCall(a,function(a){10===a.status&&b.msg.out(a);b.sk.set(a.data.sk);$("#res-content").empty().html(a.data.html)})},save:function(a){e.info("account:save");var c=b.appRequests().getRequestOpts();c.url=f.entrypoint+"?r="+a.data("action-route")+"/"+a.data("item-id");c.data=a.serialize();b.appRequests().getActionCall(c,function(a){b.msg.out(a); void 0!==a.data.itemId&&void 0!==a.data.nextAction&&h(b.appRequests().getRouteForQuery(a.data.nextAction,a.data.itemId),"account")})}},r={get:function(a){e.info("items:get");var c=a[0].selectize;c.clearOptions();c.load(function(d){var g=b.appRequests().getRequestOpts();g.url=f.entrypoint;g.method="get";g.data={r:a.data("action-route")+"/"+a.data("item-id"),sk:a.data("sk")};b.appRequests().getActionCall(g,function(g){d(g.data);c.setValue(a.data("selected-id"),!0);b.appTriggers().updateFormHash()})})}, -update:function(a){e.info("items:update");var c=$("#"+a.data("item-dst"))[0].selectize;c.clearOptions();c.load(function(d){var c=b.appRequests().getRequestOpts();c.url=f.entrypoint;c.method="get";c.data={r:a.data("item-route"),sk:b.sk.get()};b.appRequests().getActionCall(c,function(a){d(a)})})}},t={logout:function(){b.redirect("index.php?r=login/logout")},login:function(a){e.info("main:login");var c=b.appRequests().getRequestOpts();c.url=f.entrypoint+"?r="+a.data("route");c.method="get";c.data=a.serialize(); +update:function(a){e.info("items:update");var c=$("#"+a.data("item-dst"))[0].selectize;c.clearOptions();c.load(function(c){var d=b.appRequests().getRequestOpts();d.url=f.entrypoint;d.method="get";d.data={r:a.data("item-route"),sk:b.sk.get()};b.appRequests().getActionCall(d,function(a){c(a)})})}},u={logout:function(){b.redirect("index.php?r=login/logout")},login:function(a){e.info("main:login");var c=b.appRequests().getRequestOpts();c.url=f.entrypoint+"?r="+a.data("route");c.method="get";c.data=a.serialize(); b.appRequests().getActionCall(c,function(c){var d=$(".extra-hidden");switch(c.status){case 0:b.redirect(c.data.url);break;case 2:b.msg.out(c);a.find("input[type='text'],input[type='password']").val("");a.find("input:first").focus();0";mdlDialog().show({text:c,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault();b.msg.error(b.config().LANG[44])}},positive:{title:b.config().LANG[43],onClick:function(c){c=a.find("input[name='useTask']");var d=$("#taskStatus");d.empty().html(b.config().LANG[62]);0",g=a.data("selection"),e=[];if(g&&($(g).find(".is-selected").each(function(){e.push($(this).data("item-id"))}),0===e.length))return;mdlDialog().show({text:d,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault();b.msg.error(b.config().LANG[44])}},positive:{title:b.config().LANG[43],onClick:function(a){a.preventDefault();"function"===typeof c&&c(e)}}})}};return{doAction:function(a, -c){var d={r:a.r+(void 0!==a.itemId?"/"+a.itemId:""),isAjax:1},e=b.appRequests().getRequestOpts();e.url=f.entrypoint;e.method="get";e.type="html";e.addHistory=!0;e.data=d;b.appRequests().getActionCall(e,function(a){var d=$("#content");d.empty().html(a);a=b.triggers().views;a.common(d);if(void 0!==c&&"function"===typeof a[c])a[c]();d=$(".mdl-layout__content");0";mdlDialog().show({text:c, +"

";mdlDialog().show({text:c,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault();b.msg.error(b.config().LANG[44])}},positive:{title:b.config().LANG[43],onClick:function(c){var d;(c=a.find("input[name='taskId']").val())&&(d=t(c));var e=b.appRequests().getRequestOpts();e.url=f.entrypoint;e.method="get";e.useFullLoading=!!c;e.data=a.serialize();b.appRequests().getActionCall(e,function(c){b.msg.out(c);0!==c.status?a.find(":input[name=h]").val(""):(void 0!==d&&d.close(), +setTimeout(function(){b.redirect("index.php")},5E3))})}}})},getUpdates:function(){e.info("main:getUpdates");var a=b.appRequests().getRequestOpts();a.url=f.entrypoint;a.type="html";a.method="get";a.timeout=1E4;a.useLoading=!1;a.data={isAjax:1};b.appRequests().getActionCall(a,function(a){$("#updates").html(a);void 0!==componentHandler&&componentHandler.upgradeDom()},function(){$("#updates").html("!")})}},k={state:{tab:{index:0,refresh:!0,route:""},itemId:0,update:function(a){var b=$("#content").find("[id^='tabs-'].is-active"); +0",g=a.data("selection"),e=[];if(g&&($(g).find(".is-selected").each(function(){e.push($(this).data("item-id"))}),0===e.length))return;mdlDialog().show({text:d,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault(); +b.msg.error(b.config().LANG[44])}},positive:{title:b.config().LANG[43],onClick:function(a){a.preventDefault();"function"===typeof c&&c(e)}}})}},t=function(a){var c=$("#taskStatus");c.empty().html(b.config().LANG[62]);var d=b.appRequests().getRequestOpts();d.method="get";d.url=f.entrypoint+"?r=task/runTask/"+a;return b.appRequests().getActionEvent(d,function(a){a=a.task+" - "+a.message+" - "+a.time+" - "+a.progress+"%";a+="
"+b.config().LANG[62];c.empty().html(a)})};return{doAction:function(a,c){var d= +{r:a.r+(void 0!==a.itemId?"/"+a.itemId:""),isAjax:1},e=b.appRequests().getRequestOpts();e.url=f.entrypoint;e.method="get";e.type="html";e.addHistory=!0;e.data=d;b.appRequests().getActionCall(e,function(a){var d=$("#content");d.empty().html(a);a=b.triggers().views;a.common(d);if(void 0!==c&&"function"===typeof a[c])a[c]();d=$(".mdl-layout__content");0";mdlDialog().show({text:c, negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault();b.msg.error(b.config().LANG[44])}},positive:{title:b.config().LANG[43],onClick:function(c){c=b.appRequests().getRequestOpts();c.url=f.entrypoint;c.method="get";c.data={r:a.data("action-route")+"/"+a.data("item-id"),sk:b.sk.get()};b.appRequests().getActionCall(c,function(a){b.msg.out(a);0===a.status&&p.listFiles($("#list-account-files"))})}}})}},checks:{wiki:function(a){e.info("checks:wiki");a=$(a.data("src"));a.find("[name='sk']").val(b.sk.get()); var c=b.appRequests().getRequestOpts();c.url=f.entrypoint;c.data=a.serialize();b.appRequests().getActionCall(c,function(a){b.msg.out(a);0===a.status&&$("#dokuWikiResCheck").html(a.data)})}},config:{save:function(a){e.info("config:save");k.save(a)},masterpass:function(a){var c='

'+b.config().LANG[59]+"

";mdlDialog().show({text:c,negative:{title:b.config().LANG[44],onClick:function(c){c.preventDefault();b.msg.error(b.config().LANG[44]);a.find(":input[type=password]").val("")}}, -positive:{title:b.config().LANG[43],onClick:function(c){c=a.find("input[name='useTask']");var d=$("#taskStatus");d.empty().html(b.config().LANG[62]);0

'+b.config().LANG[48]+"

";mdlDialog().show({text:d,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault();c(0)}},positive:{title:b.config().LANG[43],onClick:function(a){a.preventDefault();c(1)}}})},refresh:function(a){e.info("link:refresh");k.state.update(a);var c=a.data("item-id"),d=b.appRequests().getRequestOpts();d.url=f.entrypoint;d.method="get";d.data={r:a.data("action-route")+ -"/"+c,sk:b.sk.get(),isAjax:1};b.appRequests().getActionCall(d,function(d){b.msg.out(d);0===d.status&&((d=a.data("action-next"))?h({r:d+"/"+c}):h({r:k.state.tab.route,tabIndex:k.state.tab.index}))})}},eventlog:{search:function(a){e.info("eventlog:search");n.search(a)},nav:function(a){e.info("eventlog:nav");n.nav(a)},clear:function(a){var c='

'+b.config().LANG[20]+"

";mdlDialog().show({text:c,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault(); -b.msg.error(b.config().LANG[44])}},positive:{title:b.config().LANG[43],onClick:function(c){c.preventDefault();c=b.appRequests().getRequestOpts();c.url=f.entrypoint+"?r="+a.data("action-route");c.method="get";c.data={sk:b.sk.get(),isAjax:1};b.appRequests().getActionCall(c,function(c){b.msg.out(c);0===c.status&&h({r:a.data("nextaction")});b.sk.set(c.csrf)})}}})}},ajaxUrl:f,plugin:{toggle:function(a){e.info("plugin:enable");k.save(a,function(){setTimeout(function(){b.redirect("index.php")},2E3)})},reset:function(a){e.info("plugin:reset"); -var c='

'+b.config().LANG[58]+"

";mdlDialog().show({text:c,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault();b.msg.error(b.config().LANG[44])}},positive:{title:b.config().LANG[43],onClick:function(b){b.preventDefault();k.save(a)}}})}},notification:{check:function(a){e.info("notification:check");var c=b.appRequests().getRequestOpts();c.url=f.entrypoint;c.method="get";c.data={r:a.data("action-route")+"/"+a.data("item-id"),sk:b.sk.get(), -isAjax:1};b.appRequests().getActionCall(c,function(c){b.msg.out(c);0===c.status&&h({r:a.data("nextaction")});b.sk.set(c.csrf)})},search:function(a){e.info("notification:search");n.search(a)},show:function(a){e.info("notification:show");u.show(a)},save:function(a){e.info("notification:save");var c=b.appRequests().getRequestOpts();c.url=f.entrypoint+"?r="+a.data("route");c.data=a.serialize();b.appRequests().getActionCall(c,function(c){b.msg.out(c);0===c.status&&(h({r:a.data("nextaction")}),$.magnificPopup.close())})}, -"delete":function(a){e.info("notification:delete");n["delete"](a,function(c){var d=a.data("item-id"),e=b.appRequests().getRequestOpts();e.url=f.entrypoint;e.method="get";e.data={r:a.data("action-route")+(d?"/"+d:""),items:c,sk:b.sk.get(),isAjax:1};b.appRequests().getActionCall(e,function(c){b.msg.out(c);h({r:a.data("nextaction")})})})},getActive:function(){e.info("notification:getActive");var a=b.appRequests().getRequestOpts();a.url=f.entrypoint;a.method="get";a.data={r:"items/notifications",sk:b.sk.get(), -isAjax:1};b.appRequests().getActionCall(a,function(a){return a})},nav:function(a){e.info("eventlog:nav");n.nav(a)}},wiki:{show:function(a){e.info("wiki:show");var c=b.appRequests().getRequestOpts();c.url=f.entrypoint;c.method="get";c.data={pageName:a.data("pagename"),actionId:a.data("action-id"),sk:b.sk.get(),isAjax:1};b.appRequests().getActionCall(c,function(a){0!==a.status?b.msg.out(a):m(a.data.html)})}},items:r,ldap:{check:function(a){e.info("ldap:check");var c=$(a.data("src"));c.find("[name='sk']").val(b.sk.get()); -var d=b.appRequests().getRequestOpts();d.url=f.entrypoint+"?r="+a.data("action-route");d.data=c.serialize();b.appRequests().getActionCall(d,function(a){b.msg.out(a);0===a.status&&void 0!==a.data.template&&void 0!==a.data.items&&m(a.data.template,{open:function(){var c=$("#ldap-results").find(".list-wrap").empty();a.data.items.forEach(function(a){c.append(b.appTheme().html.getList(a.items,a.icon))})}})})},"import":function(a){e.info("ldap:import");var c='

'+b.config().LANG[57]+ -"

";mdlDialog().show({text:c,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault();b.msg.error(b.config().LANG[44])}},positive:{title:b.config().LANG[43],onClick:function(c){c=$(a.data("src"));c.find("[name='sk']").val(b.sk.get());var d=b.appRequests().getRequestOpts();d.url=f.entrypoint+"?r="+a.data("action-route");d.data=c.serialize();b.appRequests().getActionCall(d,function(a){b.msg.out(a)})}}})}}}}; +positive:{title:b.config().LANG[43],onClick:function(c){var d;(c=a.find("input[name='taskId']").val())&&(d=t(c));var e=b.appRequests().getRequestOpts();e.url=f.entrypoint;e.useFullLoading=!!c;e.data=a.serialize();b.appRequests().getActionCall(e,function(c){b.msg.out(c);a.find(":input[type=password]").val("");void 0!==d&&d.close()})}}})},backup:function(a){e.info("config:backup");k.state.update(a);var c=b.appRequests().getRequestOpts();c.url=f.entrypoint+"?r="+a.data("action-route");c.useFullLoading= +!0;c.data=a.serialize();b.appRequests().getActionCall(c,function(a){b.msg.out(a);0===a.status&&h({r:k.state.tab.route,tabIndex:k.state.tab.index})})},"export":function(a){e.info("config:export");k.save(a)},"import":function(a){e.info("config:import");var c=b.appRequests().getRequestOpts();c.url=f.entrypoint+"?r="+a.data("action-route");c.data=a.serialize();b.appRequests().getActionCall(c,function(a){b.msg.out(a)})},refreshMpass:function(a){e.info("config:import");var c=b.appRequests().getRequestOpts(); +c.url=f.entrypoint+"?r="+a.data("action-route");c.data={sk:a.data("sk"),isAjax:1};b.appRequests().getActionCall(c,function(a){b.msg.out(a)})}},main:u,user:{showSettings:function(a){e.info("user:showSettings");h({r:a.data("action-route")},"userSettings")},saveSettings:function(a){e.info("user:saveSettings");k.save(a)},password:function(a){e.info("user:password");var c=b.appRequests().getRequestOpts();c.type="html";c.method="get";c.url=f.entrypoint;c.data={r:a.data("action-route")+"/"+a.data("item-id"), +sk:b.sk.get(),isAjax:1};b.appRequests().getActionCall(c,function(a){0===a.length?u.logout():m(a)})},passreset:function(a){e.info("user:passreset");var c=b.appRequests().getRequestOpts();c.url=f.entrypoint+"/?r="+a.data("action-route");c.data=a.serialize();b.appRequests().getActionCall(c,function(a){b.msg.out(a);0===a.status&&setTimeout(function(){b.redirect("index.php")},2E3)})}},link:{save:function(a){e.info("link:save");var c=function(c){var d=a.data("item-id"),e=b.appRequests().getRequestOpts(); +d?e.url=f.entrypoint+"?r="+a.data("action-route")+"/"+d+"/"+c:(e.url=f.entrypoint+"?r="+a.data("action-route"),e.data=a.serialize());b.appRequests().getActionCall(e,function(c){b.msg.out(c);0===c.status&&h({r:a.data("action-next")+"/"+d})})},d='

'+b.config().LANG[48]+"

";mdlDialog().show({text:d,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault();c(0)}},positive:{title:b.config().LANG[43],onClick:function(a){a.preventDefault();c(1)}}})}, +refresh:function(a){e.info("link:refresh");k.state.update(a);var c=a.data("item-id"),d=b.appRequests().getRequestOpts();d.url=f.entrypoint;d.method="get";d.data={r:a.data("action-route")+"/"+c,sk:b.sk.get(),isAjax:1};b.appRequests().getActionCall(d,function(d){b.msg.out(d);0===d.status&&((d=a.data("action-next"))?h({r:d+"/"+c}):h({r:k.state.tab.route,tabIndex:k.state.tab.index}))})}},eventlog:{search:function(a){e.info("eventlog:search");n.search(a)},nav:function(a){e.info("eventlog:nav");n.nav(a)}, +clear:function(a){var c='

'+b.config().LANG[20]+"

";mdlDialog().show({text:c,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault();b.msg.error(b.config().LANG[44])}},positive:{title:b.config().LANG[43],onClick:function(c){c.preventDefault();c=b.appRequests().getRequestOpts();c.url=f.entrypoint+"?r="+a.data("action-route");c.method="get";c.data={sk:b.sk.get(),isAjax:1};b.appRequests().getActionCall(c,function(c){b.msg.out(c);0===c.status&& +h({r:a.data("nextaction")});b.sk.set(c.csrf)})}}})}},ajaxUrl:f,plugin:{toggle:function(a){e.info("plugin:enable");k.save(a,function(){setTimeout(function(){b.redirect("index.php")},2E3)})},reset:function(a){e.info("plugin:reset");var c='

'+b.config().LANG[58]+"

";mdlDialog().show({text:c,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault();b.msg.error(b.config().LANG[44])}},positive:{title:b.config().LANG[43],onClick:function(b){b.preventDefault(); +k.save(a)}}})}},notification:{check:function(a){e.info("notification:check");var c=b.appRequests().getRequestOpts();c.url=f.entrypoint;c.method="get";c.data={r:a.data("action-route")+"/"+a.data("item-id"),sk:b.sk.get(),isAjax:1};b.appRequests().getActionCall(c,function(c){b.msg.out(c);0===c.status&&h({r:a.data("nextaction")});b.sk.set(c.csrf)})},search:function(a){e.info("notification:search");n.search(a)},show:function(a){e.info("notification:show");v.show(a)},save:function(a){e.info("notification:save"); +var c=b.appRequests().getRequestOpts();c.url=f.entrypoint+"?r="+a.data("route");c.data=a.serialize();b.appRequests().getActionCall(c,function(c){b.msg.out(c);0===c.status&&(h({r:a.data("nextaction")}),$.magnificPopup.close())})},"delete":function(a){e.info("notification:delete");n["delete"](a,function(c){var d=a.data("item-id"),e=b.appRequests().getRequestOpts();e.url=f.entrypoint;e.method="get";e.data={r:a.data("action-route")+(d?"/"+d:""),items:c,sk:b.sk.get(),isAjax:1};b.appRequests().getActionCall(e, +function(c){b.msg.out(c);h({r:a.data("nextaction")})})})},getActive:function(){e.info("notification:getActive");var a=b.appRequests().getRequestOpts();a.url=f.entrypoint;a.method="get";a.data={r:"items/notifications",sk:b.sk.get(),isAjax:1};b.appRequests().getActionCall(a,function(a){return a})},nav:function(a){e.info("eventlog:nav");n.nav(a)}},wiki:{show:function(a){e.info("wiki:show");var c=b.appRequests().getRequestOpts();c.url=f.entrypoint;c.method="get";c.data={pageName:a.data("pagename"),actionId:a.data("action-id"), +sk:b.sk.get(),isAjax:1};b.appRequests().getActionCall(c,function(a){0!==a.status?b.msg.out(a):m(a.data.html)})}},items:r,ldap:{check:function(a){e.info("ldap:check");var c=$(a.data("src"));c.find("[name='sk']").val(b.sk.get());var d=b.appRequests().getRequestOpts();d.url=f.entrypoint+"?r="+a.data("action-route");d.data=c.serialize();b.appRequests().getActionCall(d,function(a){b.msg.out(a);0===a.status&&void 0!==a.data.template&&void 0!==a.data.items&&m(a.data.template,{open:function(){var c=$("#ldap-results").find(".list-wrap").empty(); +a.data.items.forEach(function(a){c.append(b.appTheme().html.getList(a.items,a.icon))})}})})},"import":function(a){e.info("ldap:import");var c='

'+b.config().LANG[57]+"

";mdlDialog().show({text:c,negative:{title:b.config().LANG[44],onClick:function(a){a.preventDefault();b.msg.error(b.config().LANG[44])}},positive:{title:b.config().LANG[43],onClick:function(c){c=$(a.data("src"));c.find("[name='sk']").val(b.sk.get());var d=b.appRequests().getRequestOpts();d.url= +f.entrypoint+"?r="+a.data("action-route");d.data=c.serialize();b.appRequests().getActionCall(d,function(a){b.msg.out(a)})}}})}}}};