From d1ae2a80095582eb0c66ffff6c6f86b344dadabf Mon Sep 17 00:00:00 2001 From: Mike Koch Date: Wed, 11 Jan 2017 21:55:22 -0500 Subject: [PATCH] Getting started on new ticket validator --- api/businesslogic/ValidationModel.php | 15 +++ api/businesslogic/email_validators.php | 119 ++++++++++++++++++ .../ticket/CreateTicketForCustomerModel.php | 42 +++++++ api/businesslogic/ticket/ticket_creator.php | 93 ++++++++++++++ api/loader.php | 3 + api/ticket/index.php | 1 - 6 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 api/businesslogic/ValidationModel.php create mode 100644 api/businesslogic/email_validators.php create mode 100644 api/businesslogic/ticket/CreateTicketForCustomerModel.php create mode 100644 api/businesslogic/ticket/ticket_creator.php create mode 100644 api/loader.php diff --git a/api/businesslogic/ValidationModel.php b/api/businesslogic/ValidationModel.php new file mode 100644 index 00000000..aa2258d2 --- /dev/null +++ b/api/businesslogic/ValidationModel.php @@ -0,0 +1,15 @@ + $v) { + if (!hesk_isValidEmail($v)) { + unset($all[$k]); + } + } + + /* If at least one is found return the value */ + if (count($all)) { + if ($return_emails) { + return implode(',', $all); + } + + return true; + } elseif (!$return_emails) { + return false; + } + } else { + /* Make sure people don't try to enter multiple addresses */ + $address = str_replace(strstr($address, ','), '', $address); + $address = str_replace(strstr($address, ';'), '', $address); + $address = trim($address); + + /* Valid address? */ + if (hesk_isValidEmail($address)) { + if ($return_emails) { + return $address; + } + + return true; + } + } + + if ($return_emails) { + return null; + } + + return true; +} // END hesk_validateEmail() + +/** + * @param $email + * @return bool + */ +function hesk_isValidEmail($email) { + /* Check for header injection attempts */ + if (preg_match("/\r|\n|%0a|%0d/i", $email)) { + return false; + } + + /* Does it contain an @? */ + $atIndex = strrpos($email, "@"); + if ($atIndex === false) { + return false; + } + + /* Get local and domain parts */ + $domain = substr($email, $atIndex + 1); + $local = substr($email, 0, $atIndex); + $localLen = strlen($local); + $domainLen = strlen($domain); + + /* Check local part length */ + if ($localLen < 1 || $localLen > 64) { + return false; + } + + /* Check domain part length */ + if ($domainLen < 1 || $domainLen > 254) { + return false; + } + + /* Local part mustn't start or end with a dot */ + if ($local[0] == '.' || $local[$localLen - 1] == '.') { + return false; + } + + /* Local part mustn't have two consecutive dots*/ + if (strpos($local, '..') !== false) { + return false; + } + + /* Check domain part characters */ + if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain)) { + return false; + } + + /* Domain part mustn't have two consecutive dots */ + if (strpos($domain, '..') !== false) { + return false; + } + + /* Character not valid in local part unless local part is quoted */ + if (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/', str_replace("\\\\", "", $local))) /* " */ { + if (!preg_match('/^"(\\\\"|[^"])+"$/', str_replace("\\\\", "", $local))) /* " */ { + return false; + } + } + + /* All tests passed, email seems to be OK */ + return true; +} // END hesk_isValidEmail() \ No newline at end of file diff --git a/api/businesslogic/ticket/CreateTicketForCustomerModel.php b/api/businesslogic/ticket/CreateTicketForCustomerModel.php new file mode 100644 index 00000000..da4c233c --- /dev/null +++ b/api/businesslogic/ticket/CreateTicketForCustomerModel.php @@ -0,0 +1,42 @@ +name === NULL || $ticket_request->name == '') { + $validationModel->errorKeys[] = 'NO_NAME'; + } + + if (hesk_validateEmail($ticket_request->email, $hesk_settings['multi_eml'], false)) { + $validationModel->errorKeys[] = 'INVALID_OR_MISSING_EMAIL'; + } + + if (intval($ticket_request->category) === 0) { + // TODO add support for invalid category ID + $validationModel->errorKeys[] = 'NO_CATEGORY'; + } + + // Don't allow critical priority tickets + if ($hesk_settings['cust_urgency'] && intval($ticket_request->priority) === $TICKET_PRIORITY_CRITICAL) { + $validationModel->errorKeys[] = 'CRITICAL_PRIORITY_FORBIDDEN'; + } + + if ($hesk_settings['require_subject'] === 1 && + ($ticket_request->subject === NULL || $ticket_request->subject === '')) { + $validationModel->errorKeys[] = 'SUBJECT_REQUIRED'; + } + + if ($hesk_settings['require_message'] === 1 && + ($ticket_request->message === NULL || $ticket_request->message === '')) { + $validationModel->errorKeys[] = 'MESSAGE_REQUIRED'; + } + + foreach ($hesk_settings['custom_fields'] as $key => $value) { + // TODO Only check categories that apply to this custom field + if ($value['use'] == 1 && hesk_is_custom_field_in_category($key, intval($ticket_request->category))) { + $custom_field_value = $ticket_request->customFields[$key]; + if (empty($custom_field_value)) { + $validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $key . '_INVALID::NO_VALUE'; + continue; + } + switch($v['type']) { + case 'date': + if (!preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $custom_field_value)) { + $validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $key . '_INVALID::INVALID_DATE'; + } else { + // Actually validate based on range + $date = strtotime($custom_field_value . ' t00:00:00'); + $dmin = strlen($value['value']['dmin']) ? strtotime($value['value']['dmin'] . ' t00:00:00') : false; + $dmax = strlen($value['value']['dmax']) ? strtotime($value['value']['dmax'] . ' t00:00:00') : false; + + if ($dmin && $dmin > $date) { + $validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $key . '_INVALID::DATE_BEFORE_MIN::MIN-' . $dmin . '::ENTERED-' . $date; + } elseif ($dmax && $dmax < $date) { + $validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $key . '_INVALID::DATE_AFTER_MAX::MAX-' . $dmax . '::ENTERED-' . $date; + } + } + break; + case 'email': + if (!hesk_validateEmail($custom_field_value, $value['value']['multiple'], false)) { + $validationModel->errorKeys[] = 'CUSTOM_FIELD_' . $key . '_INVALID::INVALID_OR_MISSING_EMAIL'; + } + break; + } + } + } + + // TODO Check bans (email only; don't check IP on REST requests as they'll most likely be sent via servers) + // TODO submit_ticket.php:320-322 + + // TODO Check if we're at the max number of tickets + // TODO submit_ticket.php:325-334 + + return $validationModel; +} \ No newline at end of file diff --git a/api/loader.php b/api/loader.php new file mode 100644 index 00000000..34a86085 --- /dev/null +++ b/api/loader.php @@ -0,0 +1,3 @@ +