From d5a9d225f219b013cdfc512072f2ab57a2d5a74b Mon Sep 17 00:00:00 2001 From: Skylar Ittner Date: Sun, 30 Jul 2017 01:15:27 +0000 Subject: [PATCH 1/9] Fix bootstrap-theme not disabling on Firefox --- inc/header.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inc/header.inc.php b/inc/header.inc.php index 192e1580..f459df6c 100644 --- a/inc/header.inc.php +++ b/inc/header.inc.php @@ -55,10 +55,10 @@ if (is_dir(HESK_PATH . 'install')) { + > + rel="stylesheet" /> + Date: Sun, 30 Jul 2017 01:21:26 +0000 Subject: [PATCH 2/9] Swap == for != --- inc/header.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/header.inc.php b/inc/header.inc.php index f459df6c..ca27118b 100644 --- a/inc/header.inc.php +++ b/inc/header.inc.php @@ -55,7 +55,7 @@ if (is_dir(HESK_PATH . 'install')) { - + From 4db151de66b88cd523148e7c11614c56133797b9 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Sun, 30 Jul 2017 14:52:03 -0400 Subject: [PATCH 3/9] Disable AutoTLS for PHPMailer --- api/BusinessLogic/Emails/BasicEmailSender.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/api/BusinessLogic/Emails/BasicEmailSender.php b/api/BusinessLogic/Emails/BasicEmailSender.php index 058ef937..fd6cecfe 100644 --- a/api/BusinessLogic/Emails/BasicEmailSender.php +++ b/api/BusinessLogic/Emails/BasicEmailSender.php @@ -15,6 +15,10 @@ class BasicEmailSender implements EmailSender { if ($heskSettings['smtp']) { $mailer->isSMTP(); $mailer->SMTPAuth = true; + + //-- We'll set this explicitly below if the user has it enabled. + $mailer->SMTPAutoTLS = false; + if ($heskSettings['smtp_ssl']) { $mailer->SMTPSecure = "ssl"; } elseif ($heskSettings['smtp_tls']) { From 84f491bd40e9fc2bd04ee1c18578924a6eb91c54 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Sun, 30 Jul 2017 15:05:53 -0400 Subject: [PATCH 4/9] Don't fail resending email when there is no owner --- api/BusinessLogic/Emails/EmailTemplateParser.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/api/BusinessLogic/Emails/EmailTemplateParser.php b/api/BusinessLogic/Emails/EmailTemplateParser.php index 4fbc3e65..e53a03b2 100644 --- a/api/BusinessLogic/Emails/EmailTemplateParser.php +++ b/api/BusinessLogic/Emails/EmailTemplateParser.php @@ -190,7 +190,9 @@ class EmailTemplateParser { $defaultStatus = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::NEW_TICKET, $heskSettings); $statusName = hesk_msgToPlain($defaultStatus->localizedNames[$language]); $category = hesk_msgToPlain($this->categoryGateway->getAllCategories($heskSettings)[$ticket->categoryId]->name); - $owner = hesk_msgToPlain($this->userGateway->getUserById($ticket->ownerId, $heskSettings)->name); + $owner = $this->userGateway->getUserById($ticket->ownerId, $heskSettings); + + $ownerName = $owner === null ? $hesklang['unas'] : hesk_msgToPlain($owner->name); switch ($ticket->priorityId) { case Priority::CRITICAL: @@ -219,7 +221,7 @@ class EmailTemplateParser { $msg = str_replace('%%SITE_URL%%', $heskSettings['site_url'], $msg); $msg = str_replace('%%CATEGORY%%', $category, $msg); $msg = str_replace('%%PRIORITY%%', $priority, $msg); - $msg = str_replace('%%OWNER%%', $owner, $msg); + $msg = str_replace('%%OWNER%%', $ownerName, $msg); $msg = str_replace('%%STATUS%%', $statusName, $msg); $msg = str_replace('%%EMAIL%%', implode(';',$ticket->email), $msg); $msg = str_replace('%%CREATED%%', $ticket->dateCreated, $msg); From 73b3a01bc0470bf38ef80a552ca13d8f8e202bc6 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Thu, 10 Aug 2017 21:51:59 -0400 Subject: [PATCH 5/9] Version checks are now asynchronous --- admin/admin_settings.php | 299 ++++++------------ .../System/HeskVersionController.php | 56 ++++ api/index.php | 82 +++-- 3 files changed, 218 insertions(+), 219 deletions(-) create mode 100644 api/Controllers/System/HeskVersionController.php diff --git a/admin/admin_settings.php b/admin/admin_settings.php index 6f686d97..fcf24ec4 100644 --- a/admin/admin_settings.php +++ b/admin/admin_settings.php @@ -355,86 +355,121 @@ $modsForHesk_settings = mfh_getSettings(); : - - + - ' . $hesklang['hud'] . ' '; - } elseif ($latest != -1) { - // Is this a beta/dev version? - if (strpos($hesk_settings['hesk_version'], 'beta') || strpos($hesk_settings['hesk_version'], 'dev') || strpos($hesk_settings['hesk_version'], 'RC')) { - echo ' ' . $hesklang['beta'] . ' '; ?> ' . $hesklang['hnw'] . ' '; ?> - - + - + + + + + + + + + - + target="_blank"> + : - - + - ' . $hesklang['beta'] . ' '; ?> ' . $hesklang['mfh_up_to_date'] . ''; - } else { - ?> - - - + - + + + + + + + + - - + + @@ -3935,130 +3970,6 @@ $modsForHesk_settings = mfh_getSettings(); } - function hesk_checkVersion() - { - global $hesk_settings; - - if ($latest = hesk_getLatestVersion()) { - if (strlen($latest) > 12) { - return -1; - } elseif ($latest == $hesk_settings['hesk_version']) { - return true; - } else { - return $latest; - } - } else { - return -1; - } - - } // END hesk_checkVersion() - - - function hesk_getLatestVersion() - { - global $hesk_settings; - - // Do we have a cached version file? - if (file_exists(HESK_PATH . $hesk_settings['cache_dir'] . '/__latest.txt')) { - if (preg_match('/^(\d+)\|([\d.]+)+$/', @file_get_contents(HESK_PATH . $hesk_settings['cache_dir'] . '/__latest.txt'), $matches) && (time() - intval($matches[1])) < 3600) { - return $matches[2]; - } - } - - // No cached file or older than 3600 seconds, try to get an update - $hesk_version_url = 'https://hesk.com/version'; - - // Try using cURL - if (function_exists('curl_init')) { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $hesk_version_url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 6); - $latest = curl_exec($ch); - curl_close($ch); - return hesk_cacheLatestVersion($latest); - } - - // Try using a simple PHP function instead - if ($latest = @file_get_contents($hesk_version_url)) { - return hesk_cacheLatestVersion($latest); - } - - // Can't check automatically, will need a manual check - return false; - - } // END hesk_getLatestVersion() - - function hesk_cacheLatestVersion($latest) - { - global $hesk_settings; - - @file_put_contents(HESK_PATH . $hesk_settings['cache_dir'] . '/__latest.txt', time() . '|' . $latest); - - return $latest; - - } // END hesk_cacheLatestVersion() - - function hesk_checkMfhVersion($currentVersion) - { - if ($latest = hesk_getMfhLatestVersion()) { - if (strlen($latest) > 12) { - return -1; - } elseif ($latest == $currentVersion) { - return true; - } else { - return $latest; - } - } else { - return -1; - } - } - - function hesk_getMfhLatestVersion() - { - global $hesk_settings; - - // Do we have a cached version file? - if (file_exists(HESK_PATH . $hesk_settings['cache_dir'] . '/__latest-mfh.txt')) { - if (preg_match('/^(\d+)\|([\d.]+)+$/', @file_get_contents(HESK_PATH . $hesk_settings['cache_dir'] . '/__latest-mfh.txt'), $matches) && (time() - intval($matches[1])) < 3600) { - return $matches[2]; - } - } - - // No cached file or older than 3600 seconds, try to get an update - $hesk_version_url = 'http://mods-for-hesk.mkochcs.com/latestversion.php'; - - // Try using cURL - if (function_exists('curl_init')) { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $hesk_version_url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 6); - $latest = curl_exec($ch); - curl_close($ch); - return hesk_cacheMfhLatestVersion($latest); - } - - // Try using a simple PHP function instead - if ($latest = file_get_contents($hesk_version_url)) { - return hesk_cacheMfhLatestVersion($latest); - } - - // Can't check automatically, will need a manual check - return false; - } - - function hesk_cacheMfhLatestVersion($latest) - { - global $hesk_settings; - - @file_put_contents(HESK_PATH . $hesk_settings['cache_dir'] . '/__latest-mfh.txt', time() . '|' . $latest); - - return $latest; - - } - - function hesk_testLanguage($return_options = 0) { global $hesk_settings, $hesklang, $modsForHesk_settings; diff --git a/api/Controllers/System/HeskVersionController.php b/api/Controllers/System/HeskVersionController.php new file mode 100644 index 00000000..c07122ed --- /dev/null +++ b/api/Controllers/System/HeskVersionController.php @@ -0,0 +1,56 @@ + $matches[2])); + } + + // Try using cURL + if (function_exists('curl_init')) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 6); + $latest = curl_exec($ch); + curl_close($ch); + + self::cacheLatestVersion($latest, $fileName, $hesk_settings); + + return output(array('version' => $latest)); + } + + // Try using a simple PHP function instead + if ($latest = @file_get_contents($url)) { + self::cacheLatestVersion($latest, $fileName, $hesk_settings); + + return output(array('version' => $latest)); + } + + // Can't check automatically, will need a manual check + return http_response_code(408); + } + + private static function cacheLatestVersion($latest, $fileName, $hesk_settings) { + @file_put_contents(__DIR__ . '/../../../' . $hesk_settings['cache_dir'] . '/' . $fileName, + time() . '|' . $latest); + } +} \ No newline at end of file diff --git a/api/index.php b/api/index.php index 672bbf8b..63879505 100644 --- a/api/index.php +++ b/api/index.php @@ -15,26 +15,37 @@ function handle404() { ), 404); } -function before() { - if (defined('HESK_DEMO') && $_SERVER['REQUEST_METHOD'] !== 'GET') { +function globalBefore() { + if (defined('HESK_DEMO') && $_SERVER['REQUEST_METHOD'] === 'GET') { print_error('Demo Mode', 'Only read-only commands are available in demo mode!', null, 401); die(); } +} + +function internalHandler() { + buildUserContextFromSession(); +} +function authTokenHandler() { + assertApiIsEnabled(); + $token = \BusinessLogic\Helpers::getHeader('X-AUTH-TOKEN'); + buildUserContext($token); +} + +function internalOrAuthHandler() { $internalUse = \BusinessLogic\Helpers::getHeader('X-INTERNAL-CALL'); if ($internalUse === 'true') { - buildUserContextFromSession(); - } elseif (preg_match('/\/v1\/tickets\/.+\/attachments\/\d+/', $_SERVER['PATH_INFO'])) { - //-- TODO Clean this up - return; + internalHandler(); } else { - assertApiIsEnabled(); - $token = \BusinessLogic\Helpers::getHeader('X-AUTH-TOKEN'); - buildUserContext($token); + authTokenHandler(); } } +function publicHandler() { + //-- No-op +} + function assertApiIsEnabled() { global $applicationContext, $hesk_settings; @@ -172,34 +183,55 @@ function fatalErrorShutdownHandler() { } } -Link::before('before'); +Link::before('globalBefore'); Link::all(array( // Categories - '/v1/categories' => [\Controllers\Categories\CategoryController::class . '::printAllCategories'], - '/v1/categories/{i}' => \Controllers\Categories\CategoryController::class, + '/v1/categories' => action(\Controllers\Categories\CategoryController::class . '::printAllCategories'), + '/v1/categories/{i}' => action(\Controllers\Categories\CategoryController::class), // Tickets - '/v1/tickets' => \Controllers\Tickets\CustomerTicketController::class, + '/v1/tickets' => action(\Controllers\Tickets\CustomerTicketController::class), // Tickets - Staff - '/v1/staff/tickets/{i}' => \Controllers\Tickets\StaffTicketController::class, + '/v1/staff/tickets/{i}' => action(\Controllers\Tickets\StaffTicketController::class), // Attachments - '/v1/tickets/{a}/attachments/{i}' => \Controllers\Attachments\PublicAttachmentController::class . '::getRaw', - '/v1/staff/tickets/{i}/attachments' => \Controllers\Attachments\StaffTicketAttachmentsController::class, - '/v1/staff/tickets/{i}/attachments/{i}' => \Controllers\Attachments\StaffTicketAttachmentsController::class, + '/v1/tickets/{a}/attachments/{i}' => action(\Controllers\Attachments\PublicAttachmentController::class . '::getRaw'), + '/v1/staff/tickets/{i}/attachments' => action(\Controllers\Attachments\StaffTicketAttachmentsController::class), + '/v1/staff/tickets/{i}/attachments/{i}' => action(\Controllers\Attachments\StaffTicketAttachmentsController::class), // Statuses - '/v1/statuses' => \Controllers\Statuses\StatusController::class, + '/v1/statuses' => action(\Controllers\Statuses\StatusController::class), // Settings - '/v1/settings' => \Controllers\Settings\SettingsController::class, + '/v1/settings' => action(\Controllers\Settings\SettingsController::class), /* Internal use only routes */ // Resend email response - '/v1-internal/staff/tickets/{i}/resend-email' => \Controllers\Tickets\ResendTicketEmailToCustomerController::class, + '/v1-internal/staff/tickets/{i}/resend-email' => + action(\Controllers\Tickets\ResendTicketEmailToCustomerController::class, SecurityHandler::INTERNAL), // Custom Navigation - '/v1-internal/custom-navigation/all' => \Controllers\Navigation\CustomNavElementController::class . '::getAll', - '/v1-internal/custom-navigation' => \Controllers\Navigation\CustomNavElementController::class, - '/v1-internal/custom-navigation/{i}' => \Controllers\Navigation\CustomNavElementController::class, - '/v1-internal/custom-navigation/{i}/sort/{s}' => \Controllers\Navigation\CustomNavElementController::class . '::sort', + '/v1-internal/custom-navigation/all' => + action(\Controllers\Navigation\CustomNavElementController::class . '::getAll', SecurityHandler::INTERNAL), + '/v1-internal/custom-navigation' => + action(\Controllers\Navigation\CustomNavElementController::class, SecurityHandler::INTERNAL), + '/v1-internal/custom-navigation/{i}' => + action(\Controllers\Navigation\CustomNavElementController::class, SecurityHandler::INTERNAL), + '/v1-internal/custom-navigation/{i}/sort/{s}' => + action(\Controllers\Navigation\CustomNavElementController::class . '::sort', SecurityHandler::INTERNAL), + + '/v1-public/hesk-version' => + action(\Controllers\System\HeskVersionController::class . '::getHeskVersion', SecurityHandler::OPEN), + '/v1-public/mods-for-hesk-version' => + action(\Controllers\System\HeskVersionController::class . '::getModsForHeskVersion', SecurityHandler::OPEN), // Any URL that doesn't match goes to the 404 handler '404' => 'handle404' -)); \ No newline at end of file +)); + +function action($class, $securityHandler = SecurityHandler::AUTH_TOKEN) { + return [$class, $class, $securityHandler]; +} + +class SecurityHandler { + const OPEN = 'publicHandler'; + const INTERNAL = 'internalHandler'; + const AUTH_TOKEN = 'authTokenHandler'; + const INTERNAL_OR_AUTH_TOKEN = 'internalOrAuthHandler'; +} \ No newline at end of file From 65576d5c4333464102d272c70798f850a8846b50 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Sat, 12 Aug 2017 21:41:41 -0400 Subject: [PATCH 6/9] Fix document type on IE intranet pages --- inc/header.inc.php | 1 + inc/headerAdmin.inc.php | 2 ++ 2 files changed, 3 insertions(+) diff --git a/inc/header.inc.php b/inc/header.inc.php index ca27118b..f35f50fa 100644 --- a/inc/header.inc.php +++ b/inc/header.inc.php @@ -43,6 +43,7 @@ if (is_dir(HESK_PATH . 'install')) { $modsForHesk_settings = mfh_getSettings(); } +header('X-UA-Compatible: IE=edge'); ?> diff --git a/inc/headerAdmin.inc.php b/inc/headerAdmin.inc.php index ce2f0f1d..20501baa 100644 --- a/inc/headerAdmin.inc.php +++ b/inc/headerAdmin.inc.php @@ -21,6 +21,8 @@ if (!defined('IN_SCRIPT')) { define('ADMIN_PAGE', true); $modsForHesk_settings = mfh_getSettings(); + +header('X-UA-Compatible: IE=edge'); ?> From c60d2ed8662b9224fd6ee77935afafc7dc3ed289 Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Sat, 12 Aug 2017 21:57:41 -0400 Subject: [PATCH 7/9] Update installer --- install/install_functions.inc.php | 2 +- install/mods-for-hesk/ajax/install-database-ajax.php | 2 ++ install/mods-for-hesk/installModsForHesk.php | 1 + install/mods-for-hesk/js/version-scripts.js | 3 +++ install/mods-for-hesk/modsForHesk.php | 1 + install/mods-for-hesk/sql/installSql.php | 7 +++++++ 6 files changed, 15 insertions(+), 1 deletion(-) diff --git a/install/install_functions.inc.php b/install/install_functions.inc.php index 864e6dc8..a498ab67 100644 --- a/install/install_functions.inc.php +++ b/install/install_functions.inc.php @@ -16,7 +16,7 @@ if (!defined('IN_SCRIPT')) {die('Invalid attempt');} // We will be installing this HESK version: define('HESK_NEW_VERSION','2.7.3'); -define('MODS_FOR_HESK_NEW_VERSION','3.1.0'); +define('MODS_FOR_HESK_NEW_VERSION','3.1.1'); define('REQUIRE_PHP_VERSION','5.3.0'); define('REQUIRE_MYSQL_VERSION','5.0.7'); diff --git a/install/mods-for-hesk/ajax/install-database-ajax.php b/install/mods-for-hesk/ajax/install-database-ajax.php index e28169ec..77aed493 100644 --- a/install/mods-for-hesk/ajax/install-database-ajax.php +++ b/install/mods-for-hesk/ajax/install-database-ajax.php @@ -90,6 +90,8 @@ if ($version == 2) { execute307Scripts(); } elseif ($version == 42) { execute310Scripts(); +} elseif ($version == 43) { + execute311Scripts(); } else { $response = 'The version "' . $version . '" was not recognized. Check the value submitted and try again.'; print $response; diff --git a/install/mods-for-hesk/installModsForHesk.php b/install/mods-for-hesk/installModsForHesk.php index cc89aaf4..cae36a82 100644 --- a/install/mods-for-hesk/installModsForHesk.php +++ b/install/mods-for-hesk/installModsForHesk.php @@ -51,6 +51,7 @@ $buildToVersionMap = array( 40 => '3.0.6', 41 => '3.0.7', 42 => '3.1.0', + 43 => '3.1.1', ); function echoInitialVersionRows($version, $build_to_version_map) diff --git a/install/mods-for-hesk/js/version-scripts.js b/install/mods-for-hesk/js/version-scripts.js index 68a83e12..a7a9d1fc 100644 --- a/install/mods-for-hesk/js/version-scripts.js +++ b/install/mods-for-hesk/js/version-scripts.js @@ -122,6 +122,9 @@ function processUpdates(startingVersion) { } else if (startingVersion < 42) { startVersionUpgrade('310'); executeUpdate(42, '310', '3.1.0'); + } else if (startingVersion < 43) { + startVersionUpgrade('311'); + executeUpdate(43, '311', '3.1.1'); } else { installationFinished(); } diff --git a/install/mods-for-hesk/modsForHesk.php b/install/mods-for-hesk/modsForHesk.php index 386a53ff..4496bc49 100644 --- a/install/mods-for-hesk/modsForHesk.php +++ b/install/mods-for-hesk/modsForHesk.php @@ -118,6 +118,7 @@ hesk_dbConnect();