diff --git a/README.md b/README.md index e231d24008f930eb0fead31fabb74006b27a0c24..41013293c930aa0f63efdac72ea53c86665fa497 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ easy to setup and use. The best part is, it's completely free. Requirements ------------ * HTTP server running Microsoft® IIS or Apache - * PHP version 5.4 or greater, 5.6 is recommended + * PHP version 5.6 to 7.2, 7.2 is recommended * mysqli extension for PHP * MySQL database version 5.0 or greater diff --git a/include/class.config.php b/include/class.config.php index 32f5ca702feb2855e52d437ea8d4bbb625354ded..116c5253e63d67282463600c7bec0808980ba676 100644 --- a/include/class.config.php +++ b/include/class.config.php @@ -429,6 +429,10 @@ class OsticketConfig extends Config { return $this->get('enable_richtext'); } + function getAllowIframes() { + return str_replace(array(', ', ','), array(' ', ' '), $this->get('allow_iframes')) ?: "'self'"; + } + function isAvatarsEnabled() { return $this->get('enable_avatars'); } @@ -1121,6 +1125,7 @@ class OsticketConfig extends Config { $f['helpdesk_title']=array('type'=>'string', 'required'=>1, 'error'=>__('Helpdesk title is required')); $f['default_dept_id']=array('type'=>'int', 'required'=>1, 'error'=>__('Default Department is required')); $f['autolock_minutes']=array('type'=>'int', 'required'=>1, 'error'=>__('Enter lock time in minutes')); + $f['allow_iframes']=array('type'=>'cs-domain', 'required'=>0, 'error'=>__('Enter comma separated list of domains')); //Date & Time Options $f['time_format']=array('type'=>'string', 'required'=>1, 'error'=>__('Time format is required')); $f['date_format']=array('type'=>'string', 'required'=>1, 'error'=>__('Date format is required')); @@ -1179,6 +1184,7 @@ class OsticketConfig extends Config { 'enable_avatars' => isset($vars['enable_avatars']) ? 1 : 0, 'enable_richtext' => isset($vars['enable_richtext']) ? 1 : 0, 'files_req_auth' => isset($vars['files_req_auth']) ? 1 : 0, + 'allow_iframes' => Format::sanitize($vars['allow_iframes']), )); } diff --git a/include/class.format.php b/include/class.format.php index fead2044d9abe9c018d6eb66482c84dde14b6356..c584b09d2e4bc00f76ddcccf837e0ef1809e14d3 100644 --- a/include/class.format.php +++ b/include/class.format.php @@ -422,6 +422,33 @@ class Format { return strip_tags($decode?Format::htmldecode($var):$var); } + // Strip all Emoticon/Emoji characters until we support them + function strip_emoticons($text) { + return preg_replace(array( + '/[\x{1F601}-\x{1F64F}]/u', # Emoticons + '/[\x{1F680}-\x{1F6C0}]/u', # Transport/Map + '/[\x{1F600}-\x{1F636}]/u', # Add. Emoticons + '/[\x{1F681}-\x{1F6C5}]/u', # Add. Transport/Map + '/[\x{1F30D}-\x{1F567}]/u', # Other + '/[\x{1F910}-\x{1F999}]/u', # Hands + '/[\x{1F9D0}-\x{1F9DF}]/u', # Fantasy + '/[\x{1F9E0}-\x{1F9EF}]/u', # Clothes + '/[\x{1F6F0}-\x{1F6FF}]/u', # Misc. Transport + '/[\x{1F6E0}-\x{1F6EF}]/u', # Planes/Boats + '/[\x{1F6C0}-\x{1F6CF}]/u', # Bed/Bath + '/[\x{1F9C0}-\x{1F9C2}]/u', # Misc. Food + '/[\x{1F6D0}-\x{1F6D2}]/u', # Sign/P.O.W./Cart + '/[\x{1F500}-\x{1F5FF}]/u', # Uncategorized + '/[\x{1F300}-\x{1F3FF}]/u', # Cyclone/Amphora + '/[\x{2702}-\x{27B0}]/u', # Dingbats + '/[\x{00A9}-\x{00AE}]/u', # Copyright/Registered + '/[\x{23F0}-\x{23FF}]/u', # Clock/Buttons + '/[\x{23E0}-\x{23EF}]/u', # More Buttons + '/[\x{2310}-\x{231F}]/u', # Hourglass/Watch + '/[\x{2322}-\x{232F}]/u' # Keyboard + ), '', $text); + } + //make urls clickable. Mainly for display function clickableurls($text, $target='_blank') { global $ost; diff --git a/include/class.forms.php b/include/class.forms.php index 4252be233d1a6ac056ed10992c3ed6f67888f766..02d59862cc8170d2e2b02ba6aa7219cd304965e7 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -3965,7 +3965,7 @@ class FileUploadWidget extends Widget { allowedfiletypes: <?php echo JsonDataEncoder::encode( $mimetypes); ?>, maxfiles: <?php echo $config['max'] ?: 20; ?>, - maxfilesize: <?php echo $maxfilesize; ?>, + maxfilesize: <?php echo str_replace(',', '.', $maxfilesize); ?>, name: '<?php echo $name; ?>[]', files: <?php echo JsonDataEncoder::encode($files); ?> });}); diff --git a/include/class.thread.php b/include/class.thread.php index d6f21619a31c129fc2d971686553e79a0737fb06..bd47a83785b96906decb4631fb8e4119eb755af3 100644 --- a/include/class.thread.php +++ b/include/class.thread.php @@ -1306,7 +1306,7 @@ implements TemplateVariable { $vars['body'] = new TextThreadEntryBody($vars['body']); } - if (!($body = $vars['body']->getClean())) + if (!($body = Format::strip_emoticons($vars['body']->getClean()))) $body = '-'; //Special tag used to signify empty message as stored. $poster = $vars['poster']; diff --git a/include/class.ticket.php b/include/class.ticket.php index 7cc661f9595c6a68e4dc8ee8d47b04b7fd13ddda..47b1713c56729266597b7fd5fd94a8e6c3ef789b 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -1385,7 +1385,7 @@ implements RestrictedAccess, Threadable { } // Account manager - if ($cfg->alertAcctManagerONNewMessage() + if ($cfg->alertAcctManagerONNewTicket() && ($org = $this->getOwner()->getOrganization()) && ($acct_manager = $org->getAccountManager()) ) { @@ -2884,7 +2884,10 @@ implements RestrictedAccess, Threadable { ->filter(array('number' => $number)); if ($email) - $query->filter(array('user__emails__address' => $email)); + $query->filter(Q::any(array( + 'user__emails__address' => $email, + 'thread__collaborators__user__emails__address' => $email + ))); if (!$ticket) { diff --git a/include/class.validator.php b/include/class.validator.php index 14be7ccaf005423bf34c395aa375c04227e9671e..388d00ac929ccdc45a78325cae549329db761280 100644 --- a/include/class.validator.php +++ b/include/class.validator.php @@ -123,6 +123,14 @@ class Validator { if(!is_numeric($this->input[$k]) || (strlen($this->input[$k])!=5)) $this->errors[$k]=$field['error']; break; + case 'cs-domain': // Comma separated list of domains + if($values=explode(',', $this->input[$k])) + foreach($values as $v) + if(!preg_match_all( + '/^(https?:\/\/)?((\*\.|\w+\.)?[\w-]+(\.[a-zA-Z]+)?(:([0-9]+|\*))?)+$/', + ltrim($v))) + $this->errors[$k]=$field['error']; + break; default://If param type is not set...or handle..error out... $this->errors[$k]=$field['error'].' '.__('(type not set)'); endswitch; diff --git a/include/client/header.inc.php b/include/client/header.inc.php index 0d66f67537f3b8ac5c7e8cd2336281ad5bcdf82e..e26d4b503c3cefeba400226a6319b4c9e81a3fe6 100644 --- a/include/client/header.inc.php +++ b/include/client/header.inc.php @@ -6,7 +6,7 @@ $signin_url = ROOT_PATH . "login.php" $signout_url = ROOT_PATH . "logout.php?auth=".$ost->getLinkToken(); header("Content-Type: text/html; charset=UTF-8"); -header("X-Frame-Options: SAMEORIGIN"); +header("Content-Security-Policy: frame-ancestors ".$cfg->getAllowIframes().";"); if (($lang = Internationalization::getCurrentLanguage())) { $langs = array_unique(array($lang, $cfg->getPrimaryLanguage())); $langs = Internationalization::rfc1766($langs); diff --git a/include/i18n/en_US/help/tips/settings.system.yaml b/include/i18n/en_US/help/tips/settings.system.yaml index 28b069775ba6e2a8b8eafc4c93ae94fc96a002e6..56e39e2bf7481257be419dd20ef45b4bf246ef6b 100644 --- a/include/i18n/en_US/help/tips/settings.system.yaml +++ b/include/i18n/en_US/help/tips/settings.system.yaml @@ -93,6 +93,20 @@ collision_avoidance: <br><br> Enter <span class="doc-desc-opt">0</span> to disable the lockout feature. +allow_iframes: + title: Allow iFrames + content: > + Enter comma separated list of domains for the system to be framed + in. If left empty, the system will default to 'self'. This accepts + domain wildcards, HTTP/HTTPS URL scheme, and port numbers. + <br><br> + <b>Example:</b> + <br> + https://domain.tld, sub.domain.tld:443, http://*.domain.tld + links: + - title: Syntax Information (host-source) + href: "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors#Sources" + # Date and time options date_time_options: title: Date & Time Options diff --git a/include/staff/header.inc.php b/include/staff/header.inc.php index ebd31bfb05bb1fa216cdd4a60d12cee1fd8c6247..a5be849941b5240e85df268e96577138a57026f6 100644 --- a/include/staff/header.inc.php +++ b/include/staff/header.inc.php @@ -1,6 +1,6 @@ <?php header("Content-Type: text/html; charset=UTF-8"); -header("X-Frame-Options: SAMEORIGIN"); +header("Content-Security-Policy: frame-ancestors ".$cfg->getAllowIframes().";"); $title = ($ost && ($title=$ost->getPageTitle())) ? $title : ('osTicket :: '.__('Staff Control Panel')); diff --git a/include/staff/login.header.php b/include/staff/login.header.php index 2a4fcdbb6d234d0ffa434b838afcc065ec808e38..2f24f3a17a8ab4f4eb1c3249922d815295cebb8b 100644 --- a/include/staff/login.header.php +++ b/include/staff/login.header.php @@ -1,6 +1,6 @@ <?php defined('OSTSCPINC') or die('Invalid path'); -header("X-Frame-Options: SAMEORIGIN"); +header("Content-Security-Policy: frame-ancestors ".$cfg->getAllowIframes().";"); ?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> diff --git a/include/staff/orgs.inc.php b/include/staff/orgs.inc.php index feb53acb399b5e934cd49bf9c1eedb5420f3e856..b8236d545e6b1d6bc29f1b4855f43e84b2129508 100644 --- a/include/staff/orgs.inc.php +++ b/include/staff/orgs.inc.php @@ -18,7 +18,7 @@ if ($_REQUEST['query']) { $sortOptions = array( 'name' => 'name', - 'users' => 'users', + 'users' => 'user_count', 'create' => 'created', 'update' => 'updated' ); diff --git a/include/staff/settings-system.inc.php b/include/staff/settings-system.inc.php index 22502ed5e54dde3ae77d17c0c8aa15f4c7204b4b..37370df97eb22f4c450c41815ce13e2e08baef69 100644 --- a/include/staff/settings-system.inc.php +++ b/include/staff/settings-system.inc.php @@ -131,6 +131,13 @@ $gmtime = Misc::gmtime(); <i class="help-tip icon-question-sign" href="#enable_richtext"></i> </td> </tr> + <tr> + <td><?php echo __('Allow iFrames'); ?>:</td> + <td><input type="text" size="40" name="allow_iframes" value="<?php echo $config['allow_iframes']; ?>"> + <font class="error"> <?php echo $errors['allow_iframes']; ?></font> + <i class="help-tip icon-question-sign" href="#allow_iframes"></i> + </td> + </tr> <tr> <th colspan="2"> <em><b><?php echo __('Date and Time Options'); ?></b> diff --git a/setup/inc/header.inc.php b/setup/inc/header.inc.php index 57ceade2e12bad159d811881d8f8eea2022c22f7..fcb69d3ffa5ea9b21d14323c10d11953cb1b36d2 100644 --- a/setup/inc/header.inc.php +++ b/setup/inc/header.inc.php @@ -1,4 +1,7 @@ -<?php header("X-Frame-Options: SAMEORIGIN"); ?> +<?php +if ($cfg) + header("Content-Security-Policy: frame-ancestors ".$cfg->getAllowIframes().";"); +?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html <?php