From ed956eec543c5eda2f11f484ebd22723148921b1 Mon Sep 17 00:00:00 2001 From: nuxsmin Date: Sat, 10 Nov 2018 21:41:07 +0100 Subject: [PATCH] * [ADD] Added mime type file checking instead of extension. Thanks to @vmario89 for the feedback. Related #825 * [MOD] Improved exception handling in controllers Signed-off-by: nuxsmin --- .gitignore | 1 + app/config/mime.xml | 209 ++++++++++++++++++ app/config/strings.js.inc | 2 +- .../web/Controllers/AccountController.php | 36 +++ .../Controllers/AccountFavoriteController.php | 5 + .../web/Controllers/AccountFileController.php | 108 +++++---- .../AccountHistoryManagerController.php | 4 + .../web/Controllers/AuthTokenController.php | 12 + .../web/Controllers/BootstrapController.php | 4 +- .../web/Controllers/CategoryController.php | 12 + .../web/Controllers/ClientController.php | 12 + .../Controllers/ConfigAccountController.php | 3 +- .../Controllers/ConfigImportController.php | 5 +- .../web/Controllers/ConfigLdapController.php | 12 +- .../Controllers/ConfigManagerController.php | 31 ++- .../web/Controllers/CustomFieldController.php | 12 + .../web/Controllers/ItemPresetController.php | 12 + .../web/Controllers/LoginController.php | 1 - .../Controllers/NotificationController.php | 14 ++ .../web/Controllers/PluginController.php | 10 + .../web/Controllers/PublicLinkController.php | 14 ++ app/modules/web/Controllers/TagController.php | 12 + .../web/Controllers/TrackController.php | 4 + .../web/Controllers/UserController.php | 16 ++ .../web/Controllers/UserGroupController.php | 12 + .../Controllers/UserPassResetController.php | 4 + .../web/Controllers/UserProfileController.php | 12 + .../UserSettingsGeneralController.php | 6 + .../UserSettingsManagerController.php | 7 + .../material-blue/views/config/accounts.inc | 23 +- lib/Base.php | 1 + lib/Definitions.php | 4 + lib/SP/Config/ConfigData.php | 34 +-- lib/SP/Core/MimeTypes.php | 171 ++++++++++++++ .../Mvc/View/Components/SelectItemAdapter.php | 6 +- lib/SP/Providers/Log/DatabaseLogHandler.php | 11 +- lib/SP/Services/Export/XmlVerifyService.php | 10 +- lib/SP/Services/Import/FileImport.php | 52 ++--- lib/SP/Services/Import/ImportService.php | 2 +- lib/SP/Services/Install/Installer.php | 2 +- .../Services/Upgrade/UpgradeConfigService.php | 89 +++++++- lib/SP/Util/FileUtil.php | 4 +- public/js/app-actions.js | 3 +- public/js/app-actions.min.js | 4 +- public/js/app-config.js | 12 +- public/js/app-config.min.js | 4 +- public/js/app-main.js | 4 +- public/js/app-main.min.js | 2 +- public/js/app-triggers.js | 15 +- public/js/app-triggers.min.js | 14 +- public/js/app-util.js | 17 +- .../Account/AccountFileServiceTest.php | 18 +- tests/res/config/config.xml | 9 +- 53 files changed, 924 insertions(+), 179 deletions(-) create mode 100644 app/config/mime.xml create mode 100644 lib/SP/Core/MimeTypes.php diff --git a/.gitignore b/.gitignore index 124173aa..0a7a3772 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ app/temp/* app/plugins/* app/modules/**/plugins/* !app/config/actions.xml +!app/config/mime.xml !app/config/*.inc res/* tools/ diff --git a/app/config/mime.xml b/app/config/mime.xml new file mode 100644 index 00000000..93484ee4 --- /dev/null +++ b/app/config/mime.xml @@ -0,0 +1,209 @@ + + + + + application/x-abiword + AbiWord document + abw + + + application/octet-stream + Archive document (multiple files embedded) + arc + + + application/vnd.amazon.ebook + Amazon Kindle eBook format + azw + + + application/octet-stream + Any kind of binary data + bin + + + image/bmp + Windows OS/2 Bitmap Graphics + bmp + + + application/x-bzip + BZip archive + bz + + + application/x-bzip2 + BZip2 archive + bz2 + + + application/x-csh + C-Shell script + csh + + + text/csv + Comma-separated values (CSV) + csv + + + application/msword + Microsoft Word + doc + + + application/vnd.openxmlformats-officedocument.wordprocessingml.document + Microsoft Word (OpenXML) + docx + + + application/vnd.ms-fontobject + MS Embedded OpenType fonts + eot + + + application/epub+zip + Electronic publication (EPUB) + epub + + + image/gif + Graphics Interchange Format (GIF) + gif + + + text/html + HyperText Markup Language (HTML) + html + + + text/calendar + iCalendar format + ics + + + application/java-archive + Java Archive (JAR) + jar + + + image/jpeg + JPEG images + jpg + + + application/json + JSON format + json + + + application/vnd.apple.installer+xml + Apple Installer Package + mpkg + + + application/vnd.oasis.opendocument.presentation + OpenDocument presentation document + odp + + + application/vnd.oasis.opendocument.spreadsheet + OpenDocument spreadsheet document + ods + + + application/vnd.oasis.opendocument.text + OpenDocument text document + odt + + + image/png + Portable Network Graphics + png + + + application/pdf + Adobe Portable Document Format (PDF) + pdf + + + application/vnd.ms-powerpoint + Microsoft PowerPoint + ppt + + + application/vnd.openxmlformats-officedocument.presentationml.presentation + Microsoft PowerPoint (OpenXML) + pptx + + + application/x-rar-compressed + RAR archive + rar + + + application/rtf + Rich Text Format (RTF) + rtf + + + application/x-sh + Bourne shell script + sh + + + image/svg+xml + Scalable Vector Graphics (SVG) + svg + + + application/x-tar + Tape Archive (TAR) + tar + + + text/plain + Text, (generally ASCII or ISO 8859-n) + txt + + + application/vnd.visio + Microsoft Visio + vsd + + + application/xhtml+xml + XHTML + xhtml + + + application/vnd.ms-excel + Microsoft Excel + xls + + + application/vnd.openxmlformats-officedocument.spreadsheetml.sheet + Microsoft Excel (OpenXML) + xlsx + + + application/xml + XML + xml + + + application/vnd.mozilla.xul+xml + XUL + xul + + + application/zip + ZIP archive + zip + + + application/x-7z-compressed + 7-zip archive + 7z + + diff --git a/app/config/strings.js.inc b/app/config/strings.js.inc index c8475afe..e7eb04dc 100644 --- a/app/config/strings.js.inc +++ b/app/config/strings.js.inc @@ -42,7 +42,7 @@ return [ 16 => __('Your browser does not support HTML5 file uploads'), 17 => __('Too many files'), 18 => __('File size not allowed'), - 19 => __('Extension not allowed'), + 19 => __('MIME type not allowed'), 20 => __('Clear the event log out?'), 21 => __('Select Group'), 22 => __('Select User'), diff --git a/app/modules/web/Controllers/AccountController.php b/app/modules/web/Controllers/AccountController.php index 4b600490..34152a5b 100644 --- a/app/modules/web/Controllers/AccountController.php +++ b/app/modules/web/Controllers/AccountController.php @@ -92,6 +92,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + ErrorUtil::showExceptionInView($this->view, $e); } } @@ -115,6 +117,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -163,6 +167,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + ErrorUtil::showExceptionInView($this->view, $e, 'account'); } } @@ -239,6 +245,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + ErrorUtil::showExceptionInView($this->view, $e, 'account-link'); } } @@ -320,6 +328,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + ErrorUtil::showExceptionInView($this->view, $e, 'account'); } } @@ -368,6 +378,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + ErrorUtil::showExceptionInView($this->view, $e, 'account'); } } @@ -413,6 +425,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + ErrorUtil::showExceptionInView($this->view, $e, 'account'); } } @@ -458,6 +472,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + ErrorUtil::showExceptionInView($this->view, $e, 'account-editpass'); } } @@ -503,6 +519,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + ErrorUtil::showExceptionInView($this->view, $e, 'account-history'); } } @@ -537,6 +555,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + ErrorUtil::showExceptionInView($this->view, $e, 'account-request'); } } @@ -578,6 +598,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -636,6 +658,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -762,6 +786,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -809,6 +835,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -852,6 +880,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -891,6 +921,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -936,6 +968,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -986,6 +1020,8 @@ final class AccountController extends ControllerBase implements CrudControllerIn } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/AccountFavoriteController.php b/app/modules/web/Controllers/AccountFavoriteController.php index b93996d2..0f2c3f7f 100644 --- a/app/modules/web/Controllers/AccountFavoriteController.php +++ b/app/modules/web/Controllers/AccountFavoriteController.php @@ -24,6 +24,7 @@ namespace SP\Modules\Web\Controllers; +use SP\Core\Events\Event; use SP\Http\JsonResponse; use SP\Modules\Web\Controllers\Traits\JsonTrait; use SP\Services\Account\AccountToFavoriteService; @@ -56,6 +57,8 @@ final class AccountFavoriteController extends SimpleControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -74,6 +77,8 @@ final class AccountFavoriteController extends SimpleControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/AccountFileController.php b/app/modules/web/Controllers/AccountFileController.php index 2372f3cd..bcc8e227 100644 --- a/app/modules/web/Controllers/AccountFileController.php +++ b/app/modules/web/Controllers/AccountFileController.php @@ -37,10 +37,10 @@ use SP\Modules\Web\Controllers\Traits\JsonTrait; use SP\Mvc\Controller\CrudControllerInterface; use SP\Services\Account\AccountFileService; use SP\Services\Account\AccountService; +use SP\Storage\File\FileException; use SP\Storage\File\FileHandler; use SP\Util\ErrorUtil; use SP\Util\FileUtil; -use SP\Util\Util; /** * Class AccountFileController @@ -49,7 +49,7 @@ use SP\Util\Util; */ final class AccountFileController extends ControllerBase implements CrudControllerInterface { - const EXTENSIONS_VIEW = ['TXT']; + const MIME_VIEW = ['text/plain']; use JsonTrait, ItemTrait; @@ -91,10 +91,10 @@ final class AccountFileController extends ControllerBase implements CrudControll return $this->returnJsonResponseData(['html' => $this->render()]); } - $extension = mb_strtoupper($fileData->getExtension()); + $type = strtolower($fileData->getType()); - if (in_array($extension, self::EXTENSIONS_VIEW)) { - $this->view->assign('extension', $extension); + if (in_array($type, self::MIME_VIEW)) { + $this->view->assign('mime', $type); $this->view->assign('data', htmlentities($fileData->getContent())); $this->eventDispatcher->notifyEvent('show.accountFile', @@ -109,6 +109,8 @@ final class AccountFileController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } @@ -148,9 +150,9 @@ final class AccountFileController extends ControllerBase implements CrudControll $response->header('Content-Description', ' sysPass file'); $response->header('Content-transfer-encoding', 'binary'); - $extension = mb_strtoupper($fileData->getExtension()); + $type = strtolower($fileData->getType()); - if ($extension === 'PDF') { + if ($type === 'application/pdf') { $response->header('Content-Disposition', 'inline; filename="' . $fileData->getName() . '"'); } else { $response->header('Set-Cookie', 'fileDownload=true; path=/'); @@ -186,61 +188,46 @@ final class AccountFileController extends ControllerBase implements CrudControll throw new SPException(__u('INVALID QUERY'), SPException::ERROR); } - $allowedExts = $this->configData->getFilesAllowedExts(); + $filesAllowedMime = $this->configData->getFilesAllowedMime(); - if (empty($allowedExts)) { - throw new SPException(__u('There aren\'t any allowed extensions'), SPException::ERROR); + if (empty($filesAllowedMime)) { + throw new SPException(__u('There aren\'t any allowed mime types')); } - $fileHandler = new FileHandler($file['tmp_name']); + try { + $fileHandler = new FileHandler($file['tmp_name']); - $fileData = new FileData(); - $fileData->setAccountId($accountId); - $fileData->setName(Html::sanitize($file['name'])); - $fileData->setSize($file['size']); - $fileData->setType($file['type']); - - if ($fileData->getName() !== '') { - // Comprobamos la extensión del archivo + $fileData = new FileData(); + $fileData->setAccountId($accountId); + $fileData->setName(Html::sanitize($file['name'])); + $fileData->setSize($file['size']); + $fileData->setType($file['type']); $fileData->setExtension(mb_strtoupper(pathinfo($fileData->getName(), PATHINFO_EXTENSION))); - if (!in_array($fileData->getExtension(), $allowedExts, true)) { + if ($fileData->getName() === '') { throw new SPException( - __u('File type not allowed'), + __u('Invalid file'), SPException::ERROR, - sprintf(__('Extension: %s'), $fileData->getExtension()) + sprintf(__u('File: %s'), $fileData->getName()) ); } - } else { - throw new SPException( - __u('Invalid file'), - SPException::ERROR, - sprintf(__u('File: %s'), $fileData->getName()) - ); - } - if (!file_exists($file['tmp_name'])) { - throw new SPException( - __u('Internal error while reading the file'), - SPException::ERROR, - sprintf(__u('Maximum size: %s'), Util::getMaxUpload()) - ); - } + $fileHandler->checkFileExists(); - $allowedSize = $this->configData->getFilesAllowedSize(); + $this->checkAllowedMimeType($fileData, $fileHandler); - if ($fileData->getSize() > ($allowedSize * 1000)) { - throw new SPException( - __u('File size exceeded'), - SPException::ERROR, - sprintf(__u('Maximum size: %d KB'), - $fileData->getRoundSize()) - ); - } + $allowedSize = $this->configData->getFilesAllowedSize(); - $fileData->setContent($fileHandler->readToString()); + if ($fileData->getSize() > ($allowedSize * 1000)) { + throw new SPException( + __u('File size exceeded'), + SPException::ERROR, + sprintf(__u('Maximum size: %d KB'), $fileData->getRoundSize()) + ); + } - if ($fileData->getContent() === false) { + $fileData->setContent($fileHandler->readToString()); + } catch (FileException $e) { throw new SPException(__u('Internal error while reading the file')); } @@ -266,14 +253,39 @@ final class AccountFileController extends ControllerBase implements CrudControll } catch (SPException $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponse(1, $e->getMessage(), [$e->getHint()]); } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } + /** + * @param FileData $fileData + * + * @param FileHandler $fileHandler + * + * @throws SPException + * @throws \SP\Storage\File\FileException + */ + private function checkAllowedMimeType(FileData $fileData, FileHandler $fileHandler) + { + if (!in_array($fileData->getType(), $this->configData->getFilesAllowedMime()) + && !in_array($fileHandler->getFileType(), $this->configData->getFilesAllowedMime()) + ) { + throw new SPException( + __u('File type not allowed'), + SPException::ERROR, + sprintf(__('MIME type: %s'), $fileData->getType()) + ); + } + } + /** * Search action * @@ -370,6 +382,8 @@ final class AccountFileController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/AccountHistoryManagerController.php b/app/modules/web/Controllers/AccountHistoryManagerController.php index 7b2bbc7d..0d0cc363 100644 --- a/app/modules/web/Controllers/AccountHistoryManagerController.php +++ b/app/modules/web/Controllers/AccountHistoryManagerController.php @@ -125,6 +125,8 @@ final class AccountHistoryManagerController extends ControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -162,6 +164,8 @@ final class AccountHistoryManagerController extends ControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/AuthTokenController.php b/app/modules/web/Controllers/AuthTokenController.php index 58a9a139..a3b7efea 100644 --- a/app/modules/web/Controllers/AuthTokenController.php +++ b/app/modules/web/Controllers/AuthTokenController.php @@ -123,6 +123,8 @@ final class AuthTokenController extends ControllerBase implements CrudController } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -189,6 +191,8 @@ final class AuthTokenController extends ControllerBase implements CrudController } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -238,6 +242,8 @@ final class AuthTokenController extends ControllerBase implements CrudController } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -272,6 +278,8 @@ final class AuthTokenController extends ControllerBase implements CrudController } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -324,6 +332,8 @@ final class AuthTokenController extends ControllerBase implements CrudController } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -360,6 +370,8 @@ final class AuthTokenController extends ControllerBase implements CrudController } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/BootstrapController.php b/app/modules/web/Controllers/BootstrapController.php index 74deb497..874b8a67 100644 --- a/app/modules/web/Controllers/BootstrapController.php +++ b/app/modules/web/Controllers/BootstrapController.php @@ -69,8 +69,8 @@ final class BootstrapController extends SimpleControllerBase 'authbasic_autologin' => $this->getAuthBasicAutologinEnabled(), 'pki_key' => $this->getPublicKey(), 'pki_max_size' => CryptPKI::getMaxDataSize(), - 'import_allowed_exts' => ImportService::ALLOWED_EXTS, - 'files_allowed_exts' => $this->configData->getFilesAllowedExts(), + 'import_allowed_mime' => ImportService::ALLOWED_MIME, + 'files_allowed_mime' => $this->configData->getFilesAllowedMime(), 'session_timeout' => $this->configData->getSessionTimeout() ]; diff --git a/app/modules/web/Controllers/CategoryController.php b/app/modules/web/Controllers/CategoryController.php index 1ead5405..d03af2e5 100644 --- a/app/modules/web/Controllers/CategoryController.php +++ b/app/modules/web/Controllers/CategoryController.php @@ -118,6 +118,8 @@ final class CategoryController extends ControllerBase implements CrudControllerI } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -183,6 +185,8 @@ final class CategoryController extends ControllerBase implements CrudControllerI } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -232,6 +236,8 @@ final class CategoryController extends ControllerBase implements CrudControllerI } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -270,6 +276,8 @@ final class CategoryController extends ControllerBase implements CrudControllerI } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -312,6 +320,8 @@ final class CategoryController extends ControllerBase implements CrudControllerI } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -343,6 +353,8 @@ final class CategoryController extends ControllerBase implements CrudControllerI } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/ClientController.php b/app/modules/web/Controllers/ClientController.php index 8d287fef..8fafe724 100644 --- a/app/modules/web/Controllers/ClientController.php +++ b/app/modules/web/Controllers/ClientController.php @@ -119,6 +119,8 @@ final class ClientController extends ControllerBase implements CrudControllerInt } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -183,6 +185,8 @@ final class ClientController extends ControllerBase implements CrudControllerInt } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -229,6 +233,8 @@ final class ClientController extends ControllerBase implements CrudControllerInt } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -265,6 +271,8 @@ final class ClientController extends ControllerBase implements CrudControllerInt } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -303,6 +311,8 @@ final class ClientController extends ControllerBase implements CrudControllerInt } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -334,6 +344,8 @@ final class ClientController extends ControllerBase implements CrudControllerInt } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/ConfigAccountController.php b/app/modules/web/Controllers/ConfigAccountController.php index c9c601ed..471469b5 100644 --- a/app/modules/web/Controllers/ConfigAccountController.php +++ b/app/modules/web/Controllers/ConfigAccountController.php @@ -24,7 +24,6 @@ namespace SP\Modules\Web\Controllers; -use SP\Config\ConfigUtil; use SP\Core\Acl\ActionsInterface; use SP\Core\Acl\UnauthorizedPageException; use SP\Core\Events\Event; @@ -75,7 +74,7 @@ final class ConfigAccountController extends SimpleControllerBase } $configData->setFilesEnabled(true); - $configData->setFilesAllowedExts(ConfigUtil::filesExtsAdapter($this->request->analyzeString('files_allowed_exts'))); + $configData->setFilesAllowedMime($this->request->analyzeArray('files_allowed_mimetypes')); $configData->setFilesAllowedSize($filesAllowedSize); if ($configData->isFilesEnabled() === false) { diff --git a/app/modules/web/Controllers/ConfigImportController.php b/app/modules/web/Controllers/ConfigImportController.php index 1a1c2b28..274ff2e7 100644 --- a/app/modules/web/Controllers/ConfigImportController.php +++ b/app/modules/web/Controllers/ConfigImportController.php @@ -86,10 +86,7 @@ final class ConfigImportController extends SimpleControllerBase } catch (\Exception $e) { processException($e); - $this->eventDispatcher->notifyEvent('exception', - new Event($e, EventMessage::factory() - ->addDescription($e->getMessage())) - ); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); return $this->returnJsonResponseException($e); } diff --git a/app/modules/web/Controllers/ConfigLdapController.php b/app/modules/web/Controllers/ConfigLdapController.php index e6eb42c9..2885f313 100644 --- a/app/modules/web/Controllers/ConfigLdapController.php +++ b/app/modules/web/Controllers/ConfigLdapController.php @@ -101,6 +101,10 @@ final class ConfigLdapController extends SimpleControllerBase $this->eventDispatcher->notifyEvent('save.config.ldap', new Event($this, $eventMessage)); }); } catch (\Exception $e) { + processException($e); + + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -161,8 +165,9 @@ final class ConfigLdapController extends SimpleControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); -// $this->JsonResponse->addMessage(__('Revise el registro de eventos para más detalles', false)); } } @@ -206,8 +211,9 @@ final class ConfigLdapController extends SimpleControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); -// $this->JsonResponse->addMessage(__('Revise el registro de eventos para más detalles', false)); } } @@ -284,6 +290,8 @@ final class ConfigLdapController extends SimpleControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/ConfigManagerController.php b/app/modules/web/Controllers/ConfigManagerController.php index 651fda9b..8483c806 100644 --- a/app/modules/web/Controllers/ConfigManagerController.php +++ b/app/modules/web/Controllers/ConfigManagerController.php @@ -29,6 +29,7 @@ use SP\Core\AppInfoInterface; use SP\Core\Crypt\CryptSessionHandler; use SP\Core\Events\Event; use SP\Core\Language; +use SP\Core\MimeTypes; use SP\Modules\Web\Controllers\Helpers\TabsHelper; use SP\Mvc\View\Components\DataTab; use SP\Mvc\View\Components\SelectItemAdapter; @@ -162,7 +163,10 @@ final class ConfigManagerController extends ControllerBase /** * @return DataTab + * @throws \DI\DependencyException + * @throws \DI\NotFoundException * @throws \SP\Core\Exceptions\CheckException + * @throws \SP\Core\Exceptions\SPException */ protected function getAccountConfig() { @@ -171,6 +175,19 @@ final class ConfigManagerController extends ControllerBase $template->addTemplate('accounts'); $template->assign('gdIsAvailable', $this->extensionChecker->checkGdAvailable()); + $mimeTypesAvailable = array_map(function ($value) { + return $value['type']; + }, $this->dic->get(MimeTypes::class)->getMimeTypes()); + + $mimeTypes = SelectItemAdapter::factory( + array_merge($mimeTypesAvailable, $this->configData->getFilesAllowedMime()) + ); + + $template->assign('mimeTypes', $mimeTypes->getItemsFromArraySelected( + $this->configData->getFilesAllowedMime(), + true) + ); + return new DataTab(__('Accounts'), $template); } @@ -263,7 +280,9 @@ final class ConfigManagerController extends ControllerBase $template->assign('tempMasterPassTime', $configService->getByParam(TemporaryMasterPassService::PARAM_TIME, 0)); $template->assign('tempMasterMaxTime', $configService->getByParam(TemporaryMasterPassService::PARAM_MAX_TIME, 0)); - $tempMasterAttempts = sprintf('%d/%d', $configService->getByParam(TemporaryMasterPassService::PARAM_ATTEMPTS, 0), TemporaryMasterPassService::MAX_ATTEMPTS); + $tempMasterAttempts = sprintf('%d/%d', + $configService->getByParam(TemporaryMasterPassService::PARAM_ATTEMPTS, 0), + TemporaryMasterPassService::MAX_ATTEMPTS); $template->assign('tempMasterAttempts', $tempMasterAttempts); $template->assign('tempMasterPass', $this->session->getTemporaryMasterPass()); @@ -325,8 +344,14 @@ final class ConfigManagerController extends ControllerBase $template->setBase('config'); $template->addTemplate('import'); - $template->assign('userGroups', SelectItemAdapter::factory(UserGroupService::getItemsBasic())->getItemsFromModelSelected([$this->userData->getUserGroupId()])); - $template->assign('users', SelectItemAdapter::factory(UserService::getItemsBasic())->getItemsFromModelSelected([$this->userData->getId()])); + $template->assign('userGroups', SelectItemAdapter::factory( + UserGroupService::getItemsBasic()) + ->getItemsFromModelSelected([$this->userData->getUserGroupId()]) + ); + $template->assign('users', SelectItemAdapter::factory( + UserService::getItemsBasic()) + ->getItemsFromModelSelected([$this->userData->getId()]) + ); return new DataTab(__('Import Accounts'), $template); } diff --git a/app/modules/web/Controllers/CustomFieldController.php b/app/modules/web/Controllers/CustomFieldController.php index 49926100..da43788b 100644 --- a/app/modules/web/Controllers/CustomFieldController.php +++ b/app/modules/web/Controllers/CustomFieldController.php @@ -120,6 +120,8 @@ final class CustomFieldController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -182,6 +184,8 @@ final class CustomFieldController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -220,6 +224,8 @@ final class CustomFieldController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -255,6 +261,8 @@ final class CustomFieldController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -294,6 +302,8 @@ final class CustomFieldController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -323,6 +333,8 @@ final class CustomFieldController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponse(JsonResponse::JSON_ERROR, $e->getMessage()); } diff --git a/app/modules/web/Controllers/ItemPresetController.php b/app/modules/web/Controllers/ItemPresetController.php index 785a01da..ef72ff92 100644 --- a/app/modules/web/Controllers/ItemPresetController.php +++ b/app/modules/web/Controllers/ItemPresetController.php @@ -81,6 +81,8 @@ final class ItemPresetController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -216,6 +218,8 @@ final class ItemPresetController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -248,6 +252,8 @@ final class ItemPresetController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -293,6 +299,8 @@ final class ItemPresetController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -330,6 +338,8 @@ final class ItemPresetController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -371,6 +381,8 @@ final class ItemPresetController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/LoginController.php b/app/modules/web/Controllers/LoginController.php index dd9b6a3f..59c6ed57 100644 --- a/app/modules/web/Controllers/LoginController.php +++ b/app/modules/web/Controllers/LoginController.php @@ -149,7 +149,6 @@ final class LoginController extends ControllerBase ->getCustomLayout('index', 'login'); $this->view->assign('mailEnabled', $this->configData->isMailEnabled()); -// $this->view->assign('updated', SessionFactory::getAppUpdated()); $this->prepareSignedUriOnView(); diff --git a/app/modules/web/Controllers/NotificationController.php b/app/modules/web/Controllers/NotificationController.php index d19b7e80..3b0b5361 100644 --- a/app/modules/web/Controllers/NotificationController.php +++ b/app/modules/web/Controllers/NotificationController.php @@ -121,6 +121,8 @@ final class NotificationController extends ControllerBase implements CrudControl } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -203,6 +205,8 @@ final class NotificationController extends ControllerBase implements CrudControl } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -235,6 +239,8 @@ final class NotificationController extends ControllerBase implements CrudControl } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -288,6 +294,8 @@ final class NotificationController extends ControllerBase implements CrudControl } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -321,6 +329,8 @@ final class NotificationController extends ControllerBase implements CrudControl } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -352,6 +362,8 @@ final class NotificationController extends ControllerBase implements CrudControl } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -387,6 +399,8 @@ final class NotificationController extends ControllerBase implements CrudControl } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/PluginController.php b/app/modules/web/Controllers/PluginController.php index cdabfa6f..44d3c1e0 100644 --- a/app/modules/web/Controllers/PluginController.php +++ b/app/modules/web/Controllers/PluginController.php @@ -144,6 +144,8 @@ final class PluginController extends ControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -203,6 +205,8 @@ final class PluginController extends ControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -230,6 +234,8 @@ final class PluginController extends ControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -257,6 +263,8 @@ final class PluginController extends ControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -293,6 +301,8 @@ final class PluginController extends ControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/PublicLinkController.php b/app/modules/web/Controllers/PublicLinkController.php index 8daf966c..aac032a8 100644 --- a/app/modules/web/Controllers/PublicLinkController.php +++ b/app/modules/web/Controllers/PublicLinkController.php @@ -123,6 +123,8 @@ final class PublicLinkController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -181,6 +183,8 @@ final class PublicLinkController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -213,6 +217,8 @@ final class PublicLinkController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -260,6 +266,8 @@ final class PublicLinkController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -289,6 +297,8 @@ final class PublicLinkController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -324,6 +334,8 @@ final class PublicLinkController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -365,6 +377,8 @@ final class PublicLinkController extends ControllerBase implements CrudControlle } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/TagController.php b/app/modules/web/Controllers/TagController.php index 4e363ac6..e8da64ac 100644 --- a/app/modules/web/Controllers/TagController.php +++ b/app/modules/web/Controllers/TagController.php @@ -117,6 +117,8 @@ final class TagController extends ControllerBase implements CrudControllerInterf } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -177,6 +179,8 @@ final class TagController extends ControllerBase implements CrudControllerInterf } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -217,6 +221,8 @@ final class TagController extends ControllerBase implements CrudControllerInterf } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -246,6 +252,8 @@ final class TagController extends ControllerBase implements CrudControllerInterf } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -279,6 +287,8 @@ final class TagController extends ControllerBase implements CrudControllerInterf } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -310,6 +320,8 @@ final class TagController extends ControllerBase implements CrudControllerInterf } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/TrackController.php b/app/modules/web/Controllers/TrackController.php index 9eaa64f5..a34e547c 100644 --- a/app/modules/web/Controllers/TrackController.php +++ b/app/modules/web/Controllers/TrackController.php @@ -115,6 +115,8 @@ final class TrackController extends ControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -141,6 +143,8 @@ final class TrackController extends ControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/UserController.php b/app/modules/web/Controllers/UserController.php index 5632de52..e67fbfe6 100644 --- a/app/modules/web/Controllers/UserController.php +++ b/app/modules/web/Controllers/UserController.php @@ -124,6 +124,8 @@ final class UserController extends ControllerBase implements CrudControllerInter } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -209,6 +211,8 @@ final class UserController extends ControllerBase implements CrudControllerInter } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -246,6 +250,8 @@ final class UserController extends ControllerBase implements CrudControllerInter } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -292,6 +298,8 @@ final class UserController extends ControllerBase implements CrudControllerInter } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -331,6 +339,8 @@ final class UserController extends ControllerBase implements CrudControllerInter } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -396,6 +406,8 @@ final class UserController extends ControllerBase implements CrudControllerInter } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -435,6 +447,8 @@ final class UserController extends ControllerBase implements CrudControllerInter } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -466,6 +480,8 @@ final class UserController extends ControllerBase implements CrudControllerInter } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/UserGroupController.php b/app/modules/web/Controllers/UserGroupController.php index 47b9d22f..7656c74b 100644 --- a/app/modules/web/Controllers/UserGroupController.php +++ b/app/modules/web/Controllers/UserGroupController.php @@ -126,6 +126,8 @@ final class UserGroupController extends ControllerBase implements CrudController } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -197,6 +199,8 @@ final class UserGroupController extends ControllerBase implements CrudController } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -243,6 +247,8 @@ final class UserGroupController extends ControllerBase implements CrudController } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -280,6 +286,8 @@ final class UserGroupController extends ControllerBase implements CrudController } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -321,6 +329,8 @@ final class UserGroupController extends ControllerBase implements CrudController } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -352,6 +362,8 @@ final class UserGroupController extends ControllerBase implements CrudController } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/UserPassResetController.php b/app/modules/web/Controllers/UserPassResetController.php index 13106a0f..c05a647a 100644 --- a/app/modules/web/Controllers/UserPassResetController.php +++ b/app/modules/web/Controllers/UserPassResetController.php @@ -112,6 +112,8 @@ final class UserPassResetController extends ControllerBase $this->addTracking(); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -203,6 +205,8 @@ final class UserPassResetController extends ControllerBase $this->addTracking(); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/UserProfileController.php b/app/modules/web/Controllers/UserProfileController.php index 8567cc56..3f99151b 100644 --- a/app/modules/web/Controllers/UserProfileController.php +++ b/app/modules/web/Controllers/UserProfileController.php @@ -119,6 +119,8 @@ final class UserProfileController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -186,6 +188,8 @@ final class UserProfileController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -232,6 +236,8 @@ final class UserProfileController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -265,6 +271,8 @@ final class UserProfileController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -303,6 +311,8 @@ final class UserProfileController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } @@ -334,6 +344,8 @@ final class UserProfileController extends ControllerBase implements CrudControll } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } diff --git a/app/modules/web/Controllers/UserSettingsGeneralController.php b/app/modules/web/Controllers/UserSettingsGeneralController.php index 00783d8c..47372d90 100644 --- a/app/modules/web/Controllers/UserSettingsGeneralController.php +++ b/app/modules/web/Controllers/UserSettingsGeneralController.php @@ -24,6 +24,7 @@ namespace SP\Modules\Web\Controllers; +use SP\Core\Events\Event; use SP\Http\JsonResponse; use SP\Modules\Web\Controllers\Traits\JsonTrait; use SP\Services\User\UserService; @@ -75,12 +76,17 @@ final class UserSettingsGeneralController extends SimpleControllerBase } catch (\Exception $e) { processException($e); + $this->eventDispatcher->notifyEvent('exception', new Event($e)); + return $this->returnJsonResponseException($e); } } /** * initialize + * + * @throws \DI\DependencyException + * @throws \DI\NotFoundException */ protected function initialize() { diff --git a/app/modules/web/Controllers/UserSettingsManagerController.php b/app/modules/web/Controllers/UserSettingsManagerController.php index 8d74cb0b..568b68fa 100644 --- a/app/modules/web/Controllers/UserSettingsManagerController.php +++ b/app/modules/web/Controllers/UserSettingsManagerController.php @@ -46,6 +46,10 @@ final class UserSettingsManagerController extends ControllerBase implements Exte */ protected $tabsHelper; + /** + * @throws \DI\DependencyException + * @throws \DI\NotFoundException + */ public function indexAction() { $this->getTabs(); @@ -53,6 +57,9 @@ final class UserSettingsManagerController extends ControllerBase implements Exte /** * Returns a tabbed grid with items + * + * @throws \DI\DependencyException + * @throws \DI\NotFoundException */ protected function getTabs() { diff --git a/app/modules/web/themes/material-blue/views/config/accounts.inc b/app/modules/web/themes/material-blue/views/config/accounts.inc index c460abdc..726adcf0 100644 --- a/app/modules/web/themes/material-blue/views/config/accounts.inc +++ b/app/modules/web/themes/material-blue/views/config/accounts.inc @@ -304,23 +304,30 @@ - -
+
getIconHelp()->getIcon(); ?>
-
+

- +

- +

-
+
- + diff --git a/lib/Base.php b/lib/Base.php index 1e686791..8e2343c0 100644 --- a/lib/Base.php +++ b/lib/Base.php @@ -39,6 +39,7 @@ define('CONFIG_PATH', APP_PATH . DIRECTORY_SEPARATOR . 'config'); // Setup config files define('CONFIG_FILE', CONFIG_PATH . DIRECTORY_SEPARATOR . 'config.xml'); define('ACTIONS_FILE', CONFIG_PATH . DIRECTORY_SEPARATOR . 'actions.xml'); +define('MIMETYPES_FILE', CONFIG_PATH . DIRECTORY_SEPARATOR . 'mime.xml'); define('OLD_CONFIG_FILE', CONFIG_PATH . DIRECTORY_SEPARATOR . 'config.php'); define('LOG_FILE', CONFIG_PATH . DIRECTORY_SEPARATOR . 'syspass.log'); define('LOCK_FILE', CONFIG_PATH . DIRECTORY_SEPARATOR . '.lock'); diff --git a/lib/Definitions.php b/lib/Definitions.php index 908d0950..8c37052a 100644 --- a/lib/Definitions.php +++ b/lib/Definitions.php @@ -30,6 +30,7 @@ use SP\Config\ConfigData; use SP\Core\Acl\Acl; use SP\Core\Acl\Actions; use SP\Core\Context\ContextInterface; +use SP\Core\MimeTypes; use SP\Core\UI\Theme; use SP\Core\UI\ThemeInterface; use SP\Http\Request; @@ -64,6 +65,9 @@ return [ Actions::class => function (ContainerInterface $c) { return new Actions($c->get(FileCache::class), new XmlHandler(new FileHandler(ACTIONS_FILE))); }, + MimeTypes::class => function (ContainerInterface $c) { + return new MimeTypes($c->get(FileCache::class), new XmlHandler(new FileHandler(MIMETYPES_FILE))); + }, Acl::class => \DI\autowire(Acl::class) ->constructorParameter('action', get(Actions::class)), ThemeInterface::class => \DI\autowire(Theme::class) diff --git a/lib/SP/Config/ConfigData.php b/lib/SP/Config/ConfigData.php index 90a33d96..994b5afc 100644 --- a/lib/SP/Config/ConfigData.php +++ b/lib/SP/Config/ConfigData.php @@ -156,7 +156,11 @@ final class ConfigData implements JsonSerializable /** * @var array */ - private $filesAllowedExts = ['PDF', 'JPG', 'GIF', 'PNG', 'ODT', 'ODS', 'DOC', 'DOCX', 'XLS', 'XSL', 'VSD', 'TXT', 'CSV', 'BAK']; + private $filesAllowedExts = []; + /** + * @var array + */ + private $filesAllowedMime = []; /** * @var int */ @@ -1073,18 +1077,6 @@ final class ConfigData implements JsonSerializable return (array)$this->filesAllowedExts; } - /** - * @param array $filesAllowedExts - * - * @return $this - */ - public function setFilesAllowedExts(array $filesAllowedExts = []) - { - $this->filesAllowedExts = $filesAllowedExts; - - return $this; - } - /** * @return int */ @@ -2141,4 +2133,20 @@ final class ConfigData implements JsonSerializable { $this->ldapTlsEnabled = (int)$ldapTlsEnabled; } + + /** + * @return array + */ + public function getFilesAllowedMime(): array + { + return $this->filesAllowedMime; + } + + /** + * @param array $filesAllowedMime + */ + public function setFilesAllowedMime(array $filesAllowedMime) + { + $this->filesAllowedMime = $filesAllowedMime; + } } \ No newline at end of file diff --git a/lib/SP/Core/MimeTypes.php b/lib/SP/Core/MimeTypes.php new file mode 100644 index 00000000..dfcdf3e4 --- /dev/null +++ b/lib/SP/Core/MimeTypes.php @@ -0,0 +1,171 @@ +. + */ + +namespace SP\Core; + +use SP\Storage\File\FileException; +use SP\Storage\File\FileStorageInterface; +use SP\Storage\File\XmlFileStorageInterface; + +/** + * Class Mime + * + * @package SP\Core + */ +final class MimeTypes +{ + /** + * Cache file name + */ + const MIME_CACHE_FILE = CACHE_PATH . DIRECTORY_SEPARATOR . 'mime.cache'; + /** + * Cache expire time + */ + const CACHE_EXPIRE = 86400; + /** + * @var int + */ + protected $lastLoadTime; + /** + * @var array + */ + protected $mimeTypes; + /** + * @var XmlFileStorageInterface + */ + protected $xmlFileStorage; + /** + * @var FileStorageInterface + */ + private $fileStorage; + + /** + * Mime constructor. + * + * @param FileStorageInterface $fileStorage + * @param XmlFileStorageInterface $xmlFileStorage + * + * @throws FileException + */ + public function __construct(FileStorageInterface $fileStorage, XmlFileStorageInterface $xmlFileStorage) + { + $this->xmlFileStorage = $xmlFileStorage; + $this->fileStorage = $fileStorage; + + $this->loadCache(); + } + + /** + * Loads MIME types from cache file + * + * @return void + * @throws FileException + */ + protected function loadCache() + { + try { + if ($this->fileStorage->isExpired(self::MIME_CACHE_FILE, self::CACHE_EXPIRE) + || $this->fileStorage->isExpiredDate(self::MIME_CACHE_FILE, $this->xmlFileStorage->getFileHandler()->getFileTime()) + ) { + $this->mapAndSave(); + } else { + $this->mimeTypes = $this->fileStorage->load(self::MIME_CACHE_FILE); + + logger('Loaded MIME types cache', 'INFO'); + } + } catch (FileException $e) { + processException($e); + + $this->mapAndSave(); + } + } + + /** + * @throws FileException + */ + protected function mapAndSave() + { + logger('MIME TYPES CACHE MISS', 'INFO'); + + $this->map(); + $this->saveCache(); + } + + /** + * Sets an array of mime types + * + * @throws FileException + */ + protected function map() + { + $this->mimeTypes = []; + + foreach ($this->load() as $item) { + $this->mimeTypes[] = $item; + } + } + + /** + * Loads MIME types from XML + * + * @return array + * @throws FileException + */ + protected function load() + { + return $this->xmlFileStorage->load('mimetypes')->getItems(); + } + + /** + * Saves MIME types into cache file + */ + protected function saveCache() + { + try { + $this->fileStorage->save(self::MIME_CACHE_FILE, $this->mimeTypes); + + logger('Saved MIME types cache', 'INFO'); + } catch (FileException $e) { + processException($e); + } + } + + /** + * @throws FileException + */ + public function reset() + { + @unlink(self::MIME_CACHE_FILE); + + $this->loadCache(); + } + + /** + * @return array + */ + public function getMimeTypes(): array + { + return $this->mimeTypes; + } +} \ No newline at end of file diff --git a/lib/SP/Mvc/View/Components/SelectItemAdapter.php b/lib/SP/Mvc/View/Components/SelectItemAdapter.php index c802508f..4dc41a60 100644 --- a/lib/SP/Mvc/View/Components/SelectItemAdapter.php +++ b/lib/SP/Mvc/View/Components/SelectItemAdapter.php @@ -176,9 +176,9 @@ final class SelectItemAdapter implements ItemAdapterInterface $items = $this->getItemsFromArray(); foreach ($items as $item) { - if (($useValueAsKey === false && in_array($item->getId(), $selected, false)) - || ($useValueAsKey === true && in_array($item->getName(), $selected, false)) - ) { + $value = $useValueAsKey ? $item->getName() : $item->getId(); + + if (in_array($value, $selected, false)) { $item->setSelected(true); } } diff --git a/lib/SP/Providers/Log/DatabaseLogHandler.php b/lib/SP/Providers/Log/DatabaseLogHandler.php index 2faebe03..6fd69b76 100644 --- a/lib/SP/Providers/Log/DatabaseLogHandler.php +++ b/lib/SP/Providers/Log/DatabaseLogHandler.php @@ -27,6 +27,7 @@ namespace SP\Providers\Log; use DI\Container; use SP\Core\Events\Event; use SP\Core\Events\EventReceiver; +use SP\Core\Exceptions\SPException; use SP\Core\Language; use SP\DataModel\EventlogData; use SP\Providers\EventsTrait; @@ -90,10 +91,14 @@ final class DatabaseLogHandler extends Provider implements EventReceiver $eventlogData->setAction($eventType); $eventlogData->setLevel('INFO'); - if (($e = $event->getSource()) instanceof \Exception) { - /** @var \Exception $e */ + $source = $event->getSource(); + + if ($source instanceof SPException) { $eventlogData->setLevel('ERROR'); - $eventlogData->setDescription(__($e->getMessage())); + $eventlogData->setDescription(__($source->getMessage()) . PHP_EOL . __($source->getHint())); + } elseif ($source instanceof \Exception) { + $eventlogData->setLevel('ERROR'); + $eventlogData->setDescription(__($source->getMessage())); } elseif (($eventMessage = $event->getEventMessage()) !== null) { $eventlogData->setDescription($eventMessage->composeText()); } diff --git a/lib/SP/Services/Export/XmlVerifyService.php b/lib/SP/Services/Export/XmlVerifyService.php index db95de16..6374e9df 100644 --- a/lib/SP/Services/Export/XmlVerifyService.php +++ b/lib/SP/Services/Export/XmlVerifyService.php @@ -123,10 +123,14 @@ final class XmlVerifyService extends Service public static function checkXmlHash(DOMDocument $document, string $key) { $DOMXPath = new DOMXPath($document); - $hash = $DOMXPath->query('/Root/Meta/Hash')->item(0)->nodeValue; - $hmac = $DOMXPath->query('/Root/Meta/Hash/@sign')->item(0)->nodeValue; + $hash = $DOMXPath->query('/Root/Meta/Hash'); + $sign = $DOMXPath->query('/Root/Meta/Hash/@sign'); - return Hash::checkMessage($hash, $key, $hmac) || $hash === XmlExportService::generateHashFromNodes($document); + if ($hash->length === 1 && $sign->length === 1) { + return Hash::checkMessage($hash->item(0)->nodeValue, $key, $sign->item(0)->nodeValue); + } + + return $hash === XmlExportService::generateHashFromNodes($document); } /** diff --git a/lib/SP/Services/Import/FileImport.php b/lib/SP/Services/Import/FileImport.php index 6f8c1e2c..265eb0d3 100644 --- a/lib/SP/Services/Import/FileImport.php +++ b/lib/SP/Services/Import/FileImport.php @@ -24,6 +24,7 @@ namespace SP\Services\Import; +use SP\Core\Exceptions\SPException; use SP\Http\Request; use SP\Storage\File\FileException; use SP\Storage\File\FileHandler; @@ -59,31 +60,25 @@ final class FileImport * * @return FileImport * @throws FileException + * @throws SPException */ public static function fromRequest(string $filename, Request $request) { - if (($file = $request->getFile($filename)) === null) { - throw new FileException( - __u('File successfully uploaded'), - FileException::ERROR, - __u('Please check the web server user permissions') - ); - } - - return new self(new FileHandler(self::checkFile($file))); + return new self(self::checkFile($request->getFile($filename))); } /** * Leer los datos del archivo. * - * @param array $fileData con los datos del archivo + * @param array $file con los datos del archivo * - * @return string - * @throws \SP\Storage\File\FileException + * @return FileHandler + * @throws FileException + * @throws SPException */ - private static function checkFile($fileData): string + private static function checkFile($file): FileHandler { - if (!is_array($fileData)) { + if (!is_array($file)) { throw new FileException( __u('File successfully uploaded'), FileException::ERROR, @@ -91,35 +86,30 @@ final class FileImport ); } - if ($fileData['name']) { - // Comprobamos la extensión del archivo - $fileExtension = mb_strtoupper(pathinfo($fileData['name'], PATHINFO_EXTENSION)); + try { + $fileHandler = new FileHandler($file['tmp_name']); + $fileHandler->checkFileExists(); - if ($fileExtension !== 'CSV' && $fileExtension !== 'XML') { - throw new FileException( + if (!in_array($fileHandler->getFileType(), ImportService::ALLOWED_MIME)) { + throw new ImportException( __u('File type not allowed'), - FileException::ERROR, - __u('Please, check the file extension') + ImportException::ERROR, + sprintf(__('MIME type: %s'), $fileHandler->getFileType()) ); } - } - // Variables con información del archivo -// $this->tmpFile = $fileData['tmp_name']; -// $this->fileType = strtolower($fileData['type']); - - if (!file_exists($fileData['tmp_name']) || !is_readable($fileData['tmp_name'])) { - // Registramos el máximo tamaño permitido por PHP + return $fileHandler; + } catch (FileException $e) { logger('Max. upload size: ' . Util::getMaxUpload()); throw new FileException( __u('Internal error while reading the file'), FileException::ERROR, - __u('Please, check PHP configuration for upload files') + __u('Please, check PHP configuration for upload files'), + $e->getCode(), + $e ); } - - return $fileData['tmp_name']; } /** diff --git a/lib/SP/Services/Import/ImportService.php b/lib/SP/Services/Import/ImportService.php index 4efd2cd3..1a517eec 100644 --- a/lib/SP/Services/Import/ImportService.php +++ b/lib/SP/Services/Import/ImportService.php @@ -34,7 +34,7 @@ defined('APP_ROOT') || die(); */ final class ImportService extends Service { - const ALLOWED_EXTS = ['CSV', 'XML']; + const ALLOWED_MIME = ['text/csv', 'application/xml', 'text/xml']; /** * @var ImportParams diff --git a/lib/SP/Services/Install/Installer.php b/lib/SP/Services/Install/Installer.php index c0ac0e7a..d57573d7 100644 --- a/lib/SP/Services/Install/Installer.php +++ b/lib/SP/Services/Install/Installer.php @@ -57,7 +57,7 @@ final class Installer extends Service */ const VERSION = [3, 0, 0]; const VERSION_TEXT = '3.0-beta'; - const BUILD = 18110601; + const BUILD = 18111001; /** * @var DatabaseSetupInterface diff --git a/lib/SP/Services/Upgrade/UpgradeConfigService.php b/lib/SP/Services/Upgrade/UpgradeConfigService.php index 97f0d6cf..c2925841 100644 --- a/lib/SP/Services/Upgrade/UpgradeConfigService.php +++ b/lib/SP/Services/Upgrade/UpgradeConfigService.php @@ -27,6 +27,7 @@ namespace SP\Services\Upgrade; use SP\Config\ConfigData; use SP\Core\Events\Event; use SP\Core\Events\EventMessage; +use SP\Core\MimeTypes; use SP\Services\Service; use SP\Util\VersionUtil; @@ -40,7 +41,7 @@ final class UpgradeConfigService extends Service implements UpgradeInterface /** * @var array Versiones actualizables */ - const UPGRADES = ['112.4', '130.16020501', '200.17011202']; + const UPGRADES = ['112.4', '130.16020501', '200.17011202', '300.18111001']; /** * @var ConfigData */ @@ -226,17 +227,83 @@ final class UpgradeConfigService extends Service implements UpgradeInterface { switch ($version) { case '200.17011202': - $this->configData->setSiteTheme('material-blue'); - $this->configData->setConfigVersion($version); - - $this->config->saveConfig($this->configData, false); - - $this->eventDispatcher->notifyEvent('upgrade.config.process', - new Event($this, EventMessage::factory() - ->addDescription(__u('Update Configuration')) - ->addDetail(__u('Version'), $version)) - ); + $this->upgrade_200_17011202($version); + break; + case '300.18111001': + $this->upgrade_300_18111001($version); break; } } + + /** + * @param $version + * + * @throws \DI\DependencyException + * @throws \DI\NotFoundException + * @throws \SP\Storage\File\FileException + */ + private function upgrade_200_17011202($version) + { + $this->configData->setSiteTheme('material-blue'); + $this->configData->setConfigVersion($version); + + $this->config->saveConfig($this->configData, false); + + $this->eventDispatcher->notifyEvent('upgrade.config.process', + new Event($this, EventMessage::factory() + ->addDescription(__u('Update Configuration')) + ->addDetail(__u('Version'), $version)) + ); + } + + /** + * @param $version + * + * @throws \DI\DependencyException + * @throws \DI\NotFoundException + * @throws \SP\Storage\File\FileException + */ + private function upgrade_300_18111001($version) + { + $extensions = array_map('strtolower', $this->configData->getFilesAllowedExts()); + $mimeTypes = $this->dic->get(MimeTypes::class)->getMimeTypes(); + $configMimeTypes = []; + + foreach ($extensions as $extension) { + $exists = false; + + foreach ($mimeTypes as $mimeType) { + if (strtolower($mimeType['extension']) === $extension) { + $configMimeTypes[] = $mimeType['type']; + $exists = true; + + $this->eventDispatcher->notifyEvent('upgrade.config.process', + new Event($this, EventMessage::factory() + ->addDescription(__u('MIME type set for this extension')) + ->addDetail(__u('MIME type'), $mimeType['type']) + ->addDetail(__u('Extension'), $extension)) + ); + } + } + + if (!$exists) { + $this->eventDispatcher->notifyEvent('upgrade.config.process', + new Event($this, EventMessage::factory() + ->addDescription(__u('MIME type not found for this extension')) + ->addDetail(__u('Extension'), $extension)) + ); + } + } + + $this->configData->setFilesAllowedMime($configMimeTypes); + $this->configData->setConfigVersion($version); + + $this->config->saveConfig($this->configData, false); + + $this->eventDispatcher->notifyEvent('upgrade.config.process', + new Event($this, EventMessage::factory() + ->addDescription(__u('Update Configuration')) + ->addDetail(__u('Version'), $version)) + ); + } } \ No newline at end of file diff --git a/lib/SP/Util/FileUtil.php b/lib/SP/Util/FileUtil.php index 7e767d27..70d14c4f 100644 --- a/lib/SP/Util/FileUtil.php +++ b/lib/SP/Util/FileUtil.php @@ -37,7 +37,7 @@ use SP\DataModel\FileData; */ final class FileUtil { - const IMAGE_EXTENSIONS = ['JPG', 'PNG', 'GIF']; + const IMAGE_MIME = ['image/jpeg', 'image/png', 'image/bmp', 'image/gif']; /** * Removes a directory in a recursive way @@ -71,6 +71,6 @@ final class FileUtil */ public static function isImage(FileData $fileData) { - return in_array(mb_strtoupper($fileData->getExtension()), self::IMAGE_EXTENSIONS, true); + return in_array(strtolower($fileData->getType()), self::IMAGE_MIME, true); } } \ No newline at end of file diff --git a/public/js/app-actions.js b/public/js/app-actions.js index b9f9ccb5..7dfd3c41 100644 --- a/public/js/app-actions.js +++ b/public/js/app-actions.js @@ -929,7 +929,7 @@ sysPass.Actions = function (log) { sk: sysPassApp.sk.get() }); - if (fileType === 'PDF' || fileType === 'application/pdf') { + if (fileType === 'application/pdf') { window.open(url, '_blank'); return; } @@ -1551,6 +1551,7 @@ sysPass.Actions = function (log) { const opts = sysPassApp.requests.getRequestOpts(); opts.method = "get"; + opts.useLoading = false; opts.url = sysPassApp.util.getUrl(ajaxUrl.entrypoint, { r: "items/notifications", diff --git a/public/js/app-actions.min.js b/public/js/app-actions.min.js index 8d8fb3b9..9074bc58 100644 --- a/public/js/app-actions.min.js +++ b/public/js/app-actions.min.js @@ -28,13 +28,13 @@ b.data={items:d},sysPassApp.requests.getActionCall(b,function(b){if(0!==b.status sk:sysPassApp.sk.get(),isAjax:1});d.data={items:b};sysPassApp.requests.getActionCall(d,function(a){sysPassApp.msg.out(a);f({r:g.state.tab.route,tabIndex:g.state.tab.index})})})},save:function(a){c.info("appMgmt:save");g.save(a,function(){q()})},search:function(a){c.info("appMgmt:search");l.search(a)},nav:function(a){c.info("appMgmt:nav");l.nav(a)}},r={check:function(a){c.info("notification:check");var b=sysPassApp.requests.getRequestOpts();b.method="get";b.url=sysPassApp.util.getUrl(e.entrypoint, {r:[a.data("action-route"),a.data("item-id")],sk:sysPassApp.sk.get(),isAjax:1});sysPassApp.requests.getActionCall(b,function(b){0===b.status&&f({r:a.data("action-next")});r.getActive()})},search:function(a){c.info("notification:search");l.search(a)},show:function(a){c.info("notification:show");u.show(a)},save:function(a){c.info("notification:save");var b=sysPassApp.requests.getRequestOpts();b.url=e.entrypoint+"?r="+a.data("route");b.data=a.serialize()+"&sk="+sysPassApp.sk.get();sysPassApp.requests.getActionCall(b, function(b){sysPassApp.msg.out(b);0===b.status&&($.magnificPopup.close(),f({r:a.data("action-next")}).then(function(){r.getActive()}))})},delete:function(a){c.info("notification:delete");l.delete(a,function(b){var d=sysPassApp.requests.getRequestOpts();d.method="get";d.url=sysPassApp.util.getUrl(e.entrypoint,{r:[a.data("action-route"),0===b.length?a.data("item-id"):null],sk:sysPassApp.sk.get(),isAjax:1});d.data={items:b};sysPassApp.requests.getActionCall(d,function(b){sysPassApp.msg.out(b);f({r:a.data("action-next")}).then(function(){r.getActive()})})})}, -getActive:function(){c.info("notification:getActive");var a=sysPassApp.requests.getRequestOpts();a.method="get";a.url=sysPassApp.util.getUrl(e.entrypoint,{r:"items/notifications",sk:sysPassApp.sk.get(),isAjax:1});sysPassApp.requests.getActionCall(a,function(a){var b=$(".notifications-badge"),c=$(".notifications-tooltip");b.each(function(){var b=$(this);b.attr("data-badge",a.data.count);0===a.data.count?(b.removeClass(b.data("color-class")),c.empty().html(a.data.message)):(b.addClass(b.data("color-class")), +getActive:function(){c.info("notification:getActive");var a=sysPassApp.requests.getRequestOpts();a.method="get";a.useLoading=!1;a.url=sysPassApp.util.getUrl(e.entrypoint,{r:"items/notifications",sk:sysPassApp.sk.get(),isAjax:1});sysPassApp.requests.getActionCall(a,function(a){var b=$(".notifications-badge"),c=$(".notifications-tooltip");b.each(function(){var b=$(this);b.attr("data-badge",a.data.count);0===a.data.count?(b.removeClass(b.data("color-class")),c.empty().html(a.data.message)):(b.addClass(b.data("color-class")), c.empty().html(a.data.message_has))});0
",c=l.getSelection(a);!1!==c&&mdlDialog().show({text:d,negative:{title:sysPassApp.config.LANG[44],onClick:function(a){a.preventDefault(); sysPassApp.msg.error(sysPassApp.config.LANG[44])}},positive:{title:sysPassApp.config.LANG[43],onClick:function(a){a.preventDefault();"function"===typeof b&&b(c)}}})},getSelection:function(a){a=a.data("selection");var b=[];return a&&($(a).find(".is-selected").each(function(){b.push($(this).data("item-id"))}),0===b.length)?!1:b}},v=function(a){var b=$("#taskStatus");b.css("display","block");b.empty().html(sysPassApp.config.LANG[62]);var d=sysPassApp.requests.getRequestOpts();d.method="get";d.url=sysPassApp.util.getUrl(e.entrypoint, {r:["task/runTask",a]});return sysPassApp.requests.getActionEvent(d,function(a){a=a.task+" - "+a.message+" - "+a.time+" - "+a.progress+"%";a+="
"+sysPassApp.config.LANG[62];b.empty().html(a)})};return{getContent:f,showFloatingBox:h,closeFloatingBox:q,appMgmt:u,account:n,accountManager:{restore:function(a){c.info("accountManager:restore");g.state.update(a);var b=a.data("item-id"),d=sysPassApp.requests.getRequestOpts();d.method="get";d.url=sysPassApp.util.getUrl(e.entrypoint,{r:[a.data("action-route"), a.data("item-id")],sk:sysPassApp.sk.get(),isAjax:1});sysPassApp.requests.getActionCall(d,function(d){sysPassApp.msg.out(d);0===d.status&&((d=a.data("action-next"))?f({r:[d,b]}):f({r:g.state.tab.route,tabIndex:g.state.tab.index}))})}},file:{view:function(a){c.info("file:view");var b=sysPassApp.requests.getRequestOpts();b.method="get";b.url=sysPassApp.util.getUrl(e.entrypoint,{r:[a.data("action-route"),a.data("item-id")],sk:sysPassApp.sk.get()});sysPassApp.requests.getActionCall(b,function(b){if(0!== -b.status)return sysPassApp.msg.out(b);p(a,b.data.html)})},download:function(a){c.info("file:download");var b=a.data("item-type");a=sysPassApp.util.getUrl(e.entrypoint,{r:[a.data("action-route"),a.data("item-id")],sk:sysPassApp.sk.get()});"PDF"===b||"application/pdf"===b?window.open(a,"_blank"):$.fileDownload(a,{httpMethod:"GET",successCallback:function(a){sysPassApp.msg.ok(sysPassApp.config.LANG[72])}})},delete:function(a){c.info("file:delete");var b='

'+sysPassApp.config.LANG[15]+ +b.status)return sysPassApp.msg.out(b);p(a,b.data.html)})},download:function(a){c.info("file:download");var b=a.data("item-type");a=sysPassApp.util.getUrl(e.entrypoint,{r:[a.data("action-route"),a.data("item-id")],sk:sysPassApp.sk.get()});"application/pdf"===b?window.open(a,"_blank"):$.fileDownload(a,{httpMethod:"GET",successCallback:function(a){sysPassApp.msg.ok(sysPassApp.config.LANG[72])}})},delete:function(a){c.info("file:delete");var b='

'+sysPassApp.config.LANG[15]+ "

";mdlDialog().show({text:b,negative:{title:sysPassApp.config.LANG[44],onClick:function(a){a.preventDefault();sysPassApp.msg.error(sysPassApp.config.LANG[44])}},positive:{title:sysPassApp.config.LANG[43],onClick:function(b){b=sysPassApp.requests.getRequestOpts();b.method="get";b.url=sysPassApp.util.getUrl(e.entrypoint,{r:[a.data("action-route"),a.data("item-id")],sk:sysPassApp.sk.get()});sysPassApp.requests.getActionCall(b,function(a){sysPassApp.msg.out(a);0===a.status&&n.listFiles($("#list-account-files"))})}}})}}, checks:{wiki:function(a){c.info("checks:wiki");a=$(a.data("src"));a.find("[name='sk']").val(sysPassApp.sk.get());var b=sysPassApp.requests.getRequestOpts();b.url=e.entrypoint;b.data=a.serialize();sysPassApp.requests.getActionCall(b,function(a){sysPassApp.msg.out(a);0===a.status&&$("#dokuWikiResCheck").html(a.data)})}},config:{save:function(a){c.info("config:save");g.save(a)},masterpass:function(a){var b='

'+sysPassApp.config.LANG[59]+"

";mdlDialog().show({text:b, negative:{title:sysPassApp.config.LANG[44],onClick:function(b){b.preventDefault();sysPassApp.msg.error(sysPassApp.config.LANG[44]);a.find(":input[type=password]").val("")}},positive:{title:sysPassApp.config.LANG[43],onClick:function(b){var d;(b=a.find("input[name='taskId']").val())&&(d=v(b));var c=sysPassApp.requests.getRequestOpts();c.url=e.entrypoint;c.useFullLoading=!!b;c.data=a.serialize();sysPassApp.requests.getActionCall(c,function(b){sysPassApp.msg.out(b);a.find(":input[type=password]").val(""); diff --git a/public/js/app-config.js b/public/js/app-config.js index 845c78cd..70b576cb 100644 --- a/public/js/app-config.js +++ b/public/js/app-config.js @@ -37,8 +37,8 @@ sysPass.Config = function () { }, FILES: { MAX_SIZE: 1024, // Max uploading file fize - ACCOUNT_ALLOWED_EXTS: [], // Allowed extensions for accounts' file uploading - IMPORT_ALLOWED_EXTS: [] // Allowed extensions for importing + ACCOUNT_ALLOWED_MIME: [], // Allowed mime types for accounts' file uploading + IMPORT_ALLOWED_MIME: [] // Allowed extensions for importing }, STATUS: { CHECK_UPDATES: false, // Check for updates @@ -83,11 +83,11 @@ sysPass.Config = function () { setFileMaxSize: function (size) { config.FILES.MAX_SIZE = parseInt(size); }, - setFileAccountAllowedExts: function (extensions) { - config.FILES.ACCOUNT_ALLOWED_EXTS = extensions; + setFileAccountAllowedMime: function (mimetypes) { + config.FILES.ACCOUNT_ALLOWED_MIME = mimetypes; }, - setFileImportAllowedExts: function (extensions) { - config.FILES.IMPORT_ALLOWED_EXTS = extensions; + setFileImportAllowedMime: function (mimetypes) { + config.FILES.IMPORT_ALLOWED_MIME = mimetypes; }, setCheckUpdates: function (bool) { config.STATUS.CHECK_UPDATES = bool; diff --git a/public/js/app-config.min.js b/public/js/app-config.min.js index afa1bba6..fb57dda7 100644 --- a/public/js/app-config.min.js +++ b/public/js/app-config.min.js @@ -1,3 +1,3 @@ -sysPass.Config=function(){var b={APP_ROOT:"",LANG:[],PKI:{AVAILABLE:!1,KEY:"",MAX_SIZE:0,CRYPTO:null},FILES:{MAX_SIZE:1024,ACCOUNT_ALLOWED_EXTS:[],IMPORT_ALLOWED_EXTS:[]},STATUS:{CHECK_UPDATES:!1,CHECK_NOTICES:!1,CHECK_NOTIFICATIONS:!1},BROWSER:{TIMEZONE:"UTC",LOCALE:"en_US",COOKIES_ENABLED:!1},DEBUG:!0,PLUGINS:[],AUTH:{LOGGEDIN:!1,AUTHBASIC_AUTOLOGIN:!1},SESSION_TIMEOUT:0};return{setAppRoot:function(a){b.APP_ROOT=a},setLang:function(a){b.LANG=a},setSessionTimeout:function(a){b.SESSION_TIMEOUT=parseInt(a)}, -setPkiKey:function(a){0"+a.messages.join("
"));switch(c){case 0:this.ok(b);break;case 1:this.error(b);break;case 2:this.warn(b);break;case 10:sysPassApp.actions.main.logout();break; case 100:this.ok(b);this.sticky(b);break;case 101:this.error(b);this.sticky(b);break;case 102:this.warn(b);this.sticky(b);break;default:this.error(b)}}},html:{error:function(a){return'

Oops...
'+b.config.LANG[1]+"
"+a+"

"}}};Object.freeze(e);String.format||(String.format=function(a){var b=Array.prototype.slice.call(arguments,1);return a.replace(/{(\d+)}/g,function(a,c){return"undefined"!==typeof b[c]?b[c]:a})});var r=function(){d.info("getEnvironment");var a=window.location.pathname.split("/"), c=sysPass.Config();c.setAppRoot(window.location.protocol+"//"+window.location.host+function(){for(var b="",c=1;c<=a.length-2;c++)b+="/"+a[c];return b}());var f=b.requests.getRequestOpts();f.url="/index.php?r=bootstrap/getEnvironment";f.method="get";f.useLoading=!1;f.data={isAjax:1};return b.requests.getActionCall(f,function(a){void 0!==a.data&&(c.setLang(a.data.lang),c.setSessionTimeout(a.data.session_timeout),c.setPkiKey(a.data.pki_key),c.setPkiSize(a.data.pki_max_size),c.setCheckUpdates(a.data.check_updates), -c.setCheckNotices(a.data.check_notices),c.setCheckNotifications(a.data.check_notifications),c.setTimezone(a.data.timezone),c.setLocale(a.data.locale),c.setDebugEnabled(a.data.debug),c.setFileMaxSize(a.data.max_file_size),c.setFileAccountAllowedExts(a.data.files_allowed_exts),c.setFileImportAllowedExts(a.data.import_allowed_exts),c.setCookiesEnabled(a.data.cookies_enabled),c.setPlugins(a.data.plugins),c.setLoggedIn(a.data.loggedin),c.setAuthBasicAutologinEnabled(a.data.authbasic_autologin),c.initialize(), +c.setCheckNotices(a.data.check_notices),c.setCheckNotifications(a.data.check_notifications),c.setTimezone(a.data.timezone),c.setLocale(a.data.locale),c.setDebugEnabled(a.data.debug),c.setFileMaxSize(a.data.max_file_size),c.setFileAccountAllowedMime(a.data.files_allowed_mime),c.setFileImportAllowedMime(a.data.import_allowed_mime),c.setCookiesEnabled(a.data.cookies_enabled),c.setPlugins(a.data.plugins),c.setLoggedIn(a.data.loggedin),c.setAuthBasicAutologinEnabled(a.data.authbasic_autologin),c.initialize(), b.config=c.getConfig())}).fail(function(){e.error("Error while getting sysPass config
Please try again or check web server logs")})},b={config:sysPass.Config().getConfig(),actions:sysPass.Actions(d),triggers:sysPass.Triggers(d),util:sysPass.Util(d),theme:{},plugins:{},sk:h,msg:e,log:d,encryptFormValue:g},n=function(a){for(var b=[],d,e=window.location.href.slice(window.location.href.indexOf("?")+1).split("&"),g=0;g 0) { const upload = sysPassApp.util.fileUpload($dropFiles); - upload.url = sysPassApp.actions.ajaxUrl.entrypoint + "?r=" + $dropFiles.data("action-route"); - upload.allowedExts = sysPassApp.config.FILES.IMPORT_ALLOWED_EXTS; + upload.url = sysPassApp.util.getUrl( + sysPassApp.actions.ajaxUrl.entrypoint, + {r: $dropFiles.data("action-route")} + ); + upload.allowedMime = sysPassApp.config.FILES.IMPORT_ALLOWED_MIME; upload.beforeSendAction = function () { upload.setRequestData({ sk: sysPassApp.sk.get(), @@ -425,9 +428,11 @@ sysPass.Triggers = function (log) { if ($dropFiles.length > 0) { const upload = sysPassApp.util.fileUpload($dropFiles); - upload.url = sysPassApp.actions.ajaxUrl.entrypoint + "?r=" + $dropFiles.data("action-route") + "/" + $dropFiles.data("item-id"); - upload.allowedExts = sysPassApp.config.FILES.ACCOUNT_ALLOWED_EXTS; - + upload.url = sysPassApp.util.getUrl( + sysPassApp.actions.ajaxUrl.entrypoint, + {r: [$dropFiles.data("action-route"), $dropFiles.data("item-id")]} + ); + upload.allowedMime = sysPassApp.config.FILES.ACCOUNT_ALLOWED_MIME; upload.requestDoneAction = function () { sysPassApp.actions.account.listFiles($listFiles); }; diff --git a/public/js/app-triggers.min.js b/public/js/app-triggers.min.js index e5913cdf..32052606 100644 --- a/public/js/app-triggers.min.js +++ b/public/js/app-triggers.min.js @@ -7,13 +7,13 @@ plugins:["remove_button"]})},d={main:function(a){b.info("views:main");clipboard. "search");else{a=$("#content");var c=a.data("page");d.common(a);if(""!==c&&"function"===typeof d[c])d[c]()}!0===sysPassApp.config.STATUS.CHECK_UPDATES&&sysPassApp.actions.main.getUpdates();!0===sysPassApp.config.STATUS.CHECK_NOTICES&&sysPassApp.actions.main.getNotices();"function"===typeof sysPassApp.theme.viewsTriggers.main&&sysPassApp.theme.viewsTriggers.main()},search:function(){b.info("views:search");var a=$("#frmSearch");0!==a.length&&(a.find("input[name='search']").on("keyup",function(c){c.preventDefault(); 13!==c.which&&13!==c.keyCode||a.submit()}),a.find("select, #rpp").on("change",function(){a.submit()}),a.find("button.btn-clear").on("click",function(c){c.preventDefault();a.find('input[name="searchfav"]').val(0);a[0].reset()}),$("#globalSearch").click(function(){var c=1==$(this).prop("checked")?1:0;a.find("input[name='gsearch']").val(c);a.submit()}),"function"===typeof sysPassApp.theme.viewsTriggers.search&&sysPassApp.theme.viewsTriggers.search())},login:function(){b.info("views:login");var a=$("#frmLogin"); sysPassApp.config.AUTH.AUTHBASIC_AUTOLOGIN&&"0"===a.find("input[name='loggedOut']").val()&&(b.info("views:login:autologin"),sysPassApp.msg.info(sysPassApp.config.LANG[66]),sysPassApp.actions.main.login(a))},userpassreset:function(){b.info("views:userpassreset");var a=$("#frmUserPassReset");sysPassApp.theme.passwordDetect(a)},footer:function(){b.info("views:footer")},common:function(a){b.info("views:common");e(a);var c=a.find(":input[name='sk']");0form").each(function(){var a=$(this);a.find("button.btn-clear").on("click",function(c){c.preventDefault();a.trigger("reset")})})},config:function(){b.info("views:config");var a=$("#drop-import-files");if(0form").each(function(){var a=$(this);a.find("button.btn-clear").on("click",function(c){c.preventDefault();a.trigger("reset")})})},config:function(){b.info("views:config");var a=$("#drop-import-files");if(0 sysPassApp.config.FILES.MAX_SIZE); }; - const checkFileExtension = function (name) { - for (let ext in options.allowedExts) { - if (name.indexOf(options.allowedExts[ext]) !== -1) { + const checkFileMimeType = function (mimeType) { + if (mimeType === '') { + return true; + } + + for (let mime in options.allowedMime) { + if (mimeType.indexOf(options.allowedMime[mime]) !== -1) { return true; } } @@ -264,10 +268,11 @@ sysPass.Util = function (log) { for (let i = 0; i < filesArray.length; i++) { const file = filesArray[i]; + if (checkFileSize(file.size)) { sysPassApp.msg.error(sysPassApp.config.LANG[18] + "
" + file.name + " (Max: " + sysPassApp.config.FILES.MAX_SIZE + ")"); - } else if (!checkFileExtension(file.name.toUpperCase())) { - sysPassApp.msg.error(sysPassApp.config.LANG[19] + "
" + file.name); + } else if (!checkFileMimeType(file.type)) { + sysPassApp.msg.error(sysPassApp.config.LANG[19] + "
" + file.type); } else { sendFile(filesArray[i]); } diff --git a/tests/SP/Services/Account/AccountFileServiceTest.php b/tests/SP/Services/Account/AccountFileServiceTest.php index 4ecdd208..c486c363 100644 --- a/tests/SP/Services/Account/AccountFileServiceTest.php +++ b/tests/SP/Services/Account/AccountFileServiceTest.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. @@ -98,9 +98,9 @@ class AccountFileServiceTest extends DatabaseTestCase $data = new FileData(); $data->setAccountId(2); - $data->setName('app.png'); - $data->setType('image/png'); - $data->setExtension('SVG'); + $data->setName('aaa.txt'); + $data->setType('text/plain'); + $data->setExtension('txt'); $data->setContent(''); $data->setSize(0); @@ -118,7 +118,15 @@ class AccountFileServiceTest extends DatabaseTestCase $this->assertEquals('no_thumb', $resultData->getThumb()); $this->assertEquals(5, $this->conn->getRowCount('AccountFile')); + } + /** + * @throws \SP\Core\Exceptions\ConstraintException + * @throws \SP\Core\Exceptions\QueryException + * @throws \SP\Core\Exceptions\SPException + */ + public function testCreateInvalid() + { $this->expectException(InvalidImageException::class); $data = new FileData(); diff --git a/tests/res/config/config.xml b/tests/res/config/config.xml index a14c29cb..b6dfa39a 100644 --- a/tests/res/config/config.xml +++ b/tests/res/config/config.xml @@ -9,11 +9,11 @@ 1 1 - 5185a5ba55cadceb1968623709dddb1d7626ed44 + 9ae12959c88b80ce06b7a4637bd0375ea6f9d1da 0 0 - 1541544393 - f292660712a4970a14bb85c93d08c5611d8077a4 + 1541881367 + 481481df4e0c5d89f6cd01bffe151a6c8ba33bd4 @@ -32,7 +32,7 @@ 0 - 9d4a01b3e797c5d98f932e13ef6666d2fe5b52e9 + 54960891f385bc6fe57d75674340e278fa0291fc PDF JPG @@ -49,6 +49,7 @@ CSV BAK + 1024 1 1