diff --git a/classes/linkAction/request/AjaxAction.inc.php b/classes/linkAction/request/AjaxAction.inc.php index a412bf0da11..a0ae762224d 100644 --- a/classes/linkAction/request/AjaxAction.inc.php +++ b/classes/linkAction/request/AjaxAction.inc.php @@ -14,6 +14,8 @@ namespace PKP\linkAction\request; +use APP\core\Application; + class AjaxAction extends LinkActionRequest { public const AJAX_REQUEST_TYPE_GET = 'get'; @@ -25,18 +27,24 @@ class AjaxAction extends LinkActionRequest /** @var string */ public $_requestType; + /** @var array */ + public $_requestData; /** * Constructor * * @param $remoteAction string The target URL. * @param $requestType string One of the AJAX_REQUEST_TYPE_* constants. + * @param $requestData array Any request data (e.g. POST params) to be sent. */ - public function __construct($remoteAction, $requestType = self::AJAX_REQUEST_TYPE_POST) + public function __construct($remoteAction, $requestType = self::AJAX_REQUEST_TYPE_POST, $requestData = []) { parent::__construct(); $this->_remoteAction = $remoteAction; $this->_requestType = $requestType; + $this->_requestData = array_merge($requestData, [ + 'csrfToken' => Application::getRequest()->getSession()->getCSRFToken(), + ]); } @@ -54,15 +62,25 @@ public function getRemoteAction() } /** - * Get the modal object. + * Get the request type. * - * @return Modal + * @return string */ public function getRequestType() { return $this->_requestType; } + /** + * Get the request data. + * + * @return array + */ + public function getRequestData() + { + return $this->_requestData; + } + // // Overridden protected methods from LinkActionRequest @@ -82,7 +100,8 @@ public function getLocalizedOptions() { return [ 'url' => $this->getRemoteAction(), - 'requestType' => $this->getRequestType() + 'requestType' => $this->getRequestType(), + 'data' => $this->getRequestData(), ]; } } diff --git a/classes/plugins/ImportExportPlugin.inc.php b/classes/plugins/ImportExportPlugin.inc.php index 84c124ed79c..e9210a4142b 100644 --- a/classes/plugins/ImportExportPlugin.inc.php +++ b/classes/plugins/ImportExportPlugin.inc.php @@ -400,7 +400,13 @@ public function getBounceTab($request, $title, $bounceUrl, $bounceParameterArray $json = new JSONMessage(true); $json->setEvent('addTab', [ 'title' => $title, - 'url' => $request->url(null, null, null, ['plugin', $this->getName(), $bounceUrl], $bounceParameterArray), + 'url' => $request->url( + null, + null, + null, + ['plugin', $this->getName(), $bounceUrl], + array_merge($bounceParameterArray, ['csrfToken' => $request->getSession()->getCSRFToken()]) + ), ]); header('Content-Type: application/json'); return $json->getString(); diff --git a/controllers/grid/languages/LanguageGridHandler.inc.php b/controllers/grid/languages/LanguageGridHandler.inc.php index d21a0849668..4cda910da10 100644 --- a/controllers/grid/languages/LanguageGridHandler.inc.php +++ b/controllers/grid/languages/LanguageGridHandler.inc.php @@ -83,6 +83,9 @@ protected function getRowInstance() */ public function saveLanguageSetting($args, $request) { + if (!$request->checkCSRF()) { + return new JSONMessage(false); + } $locale = (string) $request->getUserVar('rowId'); $settingName = (string) $request->getUserVar('setting'); $settingValue = (bool) $request->getUserVar('value'); @@ -180,6 +183,9 @@ public function saveLanguageSetting($args, $request) */ public function setContextPrimaryLocale($args, $request) { + if (!$request->checkCSRF()) { + return new JSONMessage(false); + } $locale = (string) $request->getUserVar('rowId'); $context = $request->getContext(); $availableLocales = $this->getGridDataElements($request); diff --git a/controllers/grid/notifications/NotificationsGridHandler.inc.php b/controllers/grid/notifications/NotificationsGridHandler.inc.php index fa43cabea11..add51849989 100644 --- a/controllers/grid/notifications/NotificationsGridHandler.inc.php +++ b/controllers/grid/notifications/NotificationsGridHandler.inc.php @@ -184,6 +184,9 @@ protected function getNotificationsColumnTitle() */ public function markNew($args, $request) { + if (!$request->checkCSRF()) { + return new JSONMessage(false); + } $notificationDao = DAORegistry::getDAO('NotificationDAO'); /** @var NotificationDAO $notificationDao */ $user = $request->getUser(); @@ -209,6 +212,9 @@ public function markNew($args, $request) */ public function markRead($args, $request) { + if (!$request->checkCSRF()) { + return new JSONMessage(false); + } $notificationDao = DAORegistry::getDAO('NotificationDAO'); /** @var NotificationDAO $notificationDao */ $user = $request->getUser(); @@ -242,6 +248,9 @@ public function markRead($args, $request) */ public function deleteNotifications($args, $request) { + if (!$request->checkCSRF()) { + return new JSONMessage(false); + } $notificationDao = DAORegistry::getDAO('NotificationDAO'); /** @var NotificationDAO $notificationDao */ $user = $request->getUser(); diff --git a/controllers/grid/settings/roles/UserGroupGridHandler.inc.php b/controllers/grid/settings/roles/UserGroupGridHandler.inc.php index da0e36f2d36..2341db1ac7c 100644 --- a/controllers/grid/settings/roles/UserGroupGridHandler.inc.php +++ b/controllers/grid/settings/roles/UserGroupGridHandler.inc.php @@ -416,6 +416,9 @@ public function unassignStage($args, $request) */ private function _toggleAssignment($args, $request) { + if (!$request->checkCSRF()) { + return new JSONMessage(false); + } $userGroup = $this->_userGroup; $stageId = $this->getAuthorizedContextObject(ASSOC_TYPE_WORKFLOW_STAGE); $contextId = $this->_getContextId(); diff --git a/js/classes/linkAction/AjaxRequest.js b/js/classes/linkAction/AjaxRequest.js index 19afc650191..efb97a76444 100644 --- a/js/classes/linkAction/AjaxRequest.js +++ b/js/classes/linkAction/AjaxRequest.js @@ -21,7 +21,8 @@ * @param {jQueryObject} $linkActionElement The element the link * action was attached to. * @param {{ - * requestType: string + * requestType: string, + * data: PlainObject * }} options Configuration of the link action * request. */ @@ -51,11 +52,11 @@ this.handleResponse, this); switch (options.requestType) { case 'get': - $.getJSON(options.url, responseHandler); + $.getJSON(options.url, options.data, responseHandler); break; case 'post': - $.post(options.url, responseHandler, 'json'); + $.post(options.url, options.data, responseHandler, 'json'); break; } return returnValue; diff --git a/pages/admin/AdminHandler.inc.php b/pages/admin/AdminHandler.inc.php index aa3e0c6792a..eb5748155e8 100644 --- a/pages/admin/AdminHandler.inc.php +++ b/pages/admin/AdminHandler.inc.php @@ -404,9 +404,13 @@ public function phpinfo() */ public function expireSessions($args, $request) { + if (!$request->checkCSRF()) { + return new JSONMessage(false); + } + $sessionDao = DAORegistry::getDAO('SessionDAO'); /** @var SessionDAO $sessionDao */ $sessionDao->deleteAllSessions(); - $request->redirect(null, 'admin'); + $request->redirect(null, 'login'); } /** @@ -417,6 +421,10 @@ public function expireSessions($args, $request) */ public function clearTemplateCache($args, $request) { + if (!$request->checkCSRF()) { + return new JSONMessage(false); + } + $templateMgr = TemplateManager::getManager($request); $templateMgr->clearTemplateCache(); $templateMgr->clearCssCache(); @@ -431,6 +439,10 @@ public function clearTemplateCache($args, $request) */ public function clearDataCache($args, $request) { + if (!$request->checkCSRF()) { + return new JSONMessage(false); + } + // Clear the CacheManager's caches $cacheManager = CacheManager::getManager(); $cacheManager->flush(); @@ -441,10 +453,8 @@ public function clearDataCache($args, $request) /** * Download scheduled task execution log file. */ - public function downloadScheduledTaskLogFile() + public function downloadScheduledTaskLogFile($args, $request) { - $request = Application::get()->getRequest(); - $file = basename($request->getUserVar('file')); ScheduledTaskHelper::downloadExecutionLog($file); } @@ -454,9 +464,12 @@ public function downloadScheduledTaskLogFile() */ public function clearScheduledTaskLogFiles() { + if (!$request->checkCSRF()) { + return new JSONMessage(false); + } + ScheduledTaskHelper::clearExecutionLogs(); - $request = Application::get()->getRequest(); $request->redirect(null, 'admin'); } } diff --git a/plugins/importexport/native/PKPNativeImportExportPlugin.inc.php b/plugins/importexport/native/PKPNativeImportExportPlugin.inc.php index 7e97db3086d..7fe5d6b148e 100644 --- a/plugins/importexport/native/PKPNativeImportExportPlugin.inc.php +++ b/plugins/importexport/native/PKPNativeImportExportPlugin.inc.php @@ -198,6 +198,9 @@ public function display($args, $request) break; case 'import': + if (!$request->checkCSRF()) { + throw new Exception('CSRF mismatch!'); + } $temporaryFilePath = $this->getImportedFilePath($request->getUserVar('temporaryFileId'), $user); [$filter, $xmlString] = $this->getImportFilter($temporaryFilePath); $result = $this->getImportTemplateResult($filter, $xmlString, $this->getDeployment(), $templateMgr); diff --git a/plugins/importexport/users/PKPUserImportExportPlugin.inc.php b/plugins/importexport/users/PKPUserImportExportPlugin.inc.php index c8384b5cefa..81ff2ede58e 100644 --- a/plugins/importexport/users/PKPUserImportExportPlugin.inc.php +++ b/plugins/importexport/users/PKPUserImportExportPlugin.inc.php @@ -116,11 +116,14 @@ public function display($args, $request) $json = new JSONMessage(true); $json->setEvent('addTab', [ 'title' => __('plugins.importexport.users.results'), - 'url' => $request->url(null, null, null, ['plugin', $this->getName(), 'import'], ['temporaryFileId' => $request->getUserVar('temporaryFileId')]), + 'url' => $request->url(null, null, null, ['plugin', $this->getName(), 'import'], ['temporaryFileId' => $request->getUserVar('temporaryFileId'), 'csrfToken' => $request->getSession()->getCSRFToken()]), ]); header('Content-Type: application/json'); return $json->getString(); case 'import': + if (!$request->checkCSRF()) { + throw new Exception('CSRF mismatch!'); + } $temporaryFileId = $request->getUserVar('temporaryFileId'); $temporaryFileDao = DAORegistry::getDAO('TemporaryFileDAO'); /** @var TemporaryFileDAO $temporaryFileDao */ $user = $request->getUser(); diff --git a/templates/admin/index.tpl b/templates/admin/index.tpl index 159fb440f69..b0b8a3f3745 100644 --- a/templates/admin/index.tpl +++ b/templates/admin/index.tpl @@ -31,10 +31,30 @@

{translate key="admin.adminFunctions"}