Invert fonction from clean_cross_side_scripting_deep to display HTML striping XSS code
static public unclean_html_cross_side_scripting_deep ( $value ) : unclean | ||
$value | array or string: item to unclean from clean_cross_side_scripting_deep | |
return | unclean | item |
<script type='text/javascript'> window.onload = function() { var input = document.getElementById("login_name").focus(); } </script> </head> <body> <div id="body2"></div> <div class="login-container"> <div class="middle-login"> <div id='text-login'> <?php echo nl2br(Toolbox::unclean_html_cross_side_scripting_deep($CFG_GLPI['text_login'])); ?> </div> <div class="block-web row-fluid"> <div class="head"> <h3 class="text-center"><img class="logo-img" src="pics/logo.png" alt="" style="left:50%;"></h3> </div> <div id="logo_big" style="border-right: 1px solid #ccc; width:220px;" > <img src="pics/logo_big.png" alt="GLPI" class="logo2" /> </div> <div id="auth" style="background:#fff;"> <form class="form-horizontal" style="margin-bottom: 0px !important;" action='front/login.php' method='post'>
/** * Show list for central view * * @param $personal boolean display rssfeeds created by me ? (true by default) * * @return Nothing (display function) **/ static function showListForCentral($personal = true) { global $DB, $CFG_GLPI; $users_id = Session::getLoginUserID(); $today = date('Y-m-d'); $now = date('Y-m-d H:i:s'); if ($personal) { /// Personal notes only for central view if ($_SESSION['glpiactiveprofile']['interface'] == 'helpdesk') { return false; } $query = "SELECT `glpi_rssfeeds`.*\n FROM `glpi_rssfeeds`\n WHERE `glpi_rssfeeds`.`users_id` = '{$users_id}'\n AND `glpi_rssfeeds`.`is_active` = '1'\n ORDER BY `glpi_rssfeeds`.`name`"; $titre = "<a href='" . $CFG_GLPI["root_doc"] . "/front/rssfeed.php'>" . _n('Personal RSS feed', 'Personal RSS feeds', Session::getPluralNumber()) . "</a>"; } else { // Show public rssfeeds / not mines : need to have access to public rssfeeds if (!self::canView()) { return false; } $restrict_user = '******'; // Only personal on central so do not keep it if ($_SESSION['glpiactiveprofile']['interface'] == 'central') { $restrict_user = "******"; } $query = "SELECT `glpi_rssfeeds`.*\n FROM `glpi_rssfeeds` " . self::addVisibilityJoins() . "\n WHERE {$restrict_user}\n AND " . self::addVisibilityRestrict() . "\n ORDER BY `glpi_rssfeeds`.`name`"; if ($_SESSION['glpiactiveprofile']['interface'] != 'helpdesk') { $titre = "<a href=\"" . $CFG_GLPI["root_doc"] . "/front/rssfeed.php\">" . _n('Public RSS feed', 'Public RSS feeds', Session::getPluralNumber()) . "</a>"; } else { $titre = _n('Public RSS feed', 'Public RSS feeds', Session::getPluralNumber()); } } $result = $DB->query($query); $items = array(); $rssfeed = new self(); if ($nb = $DB->numrows($result)) { while ($data = $DB->fetch_assoc($result)) { if ($rssfeed->getFromDB($data['id'])) { // Force fetching feeds if ($feed = self::getRSSFeed($data['url'], $data['refresh_rate'])) { // Store feeds in array of feeds $items = array_merge($items, $feed->get_items(0, $data['max_items'])); $rssfeed->setError(false); } else { $rssfeed->setError(true); } } } } echo "<br><table class='tab_cadrehov'>"; echo "<tr class='noHover'><th colspan='2'><div class='relative'><span>{$titre}</span>"; if ($personal && self::canCreate() || !$personal && Session::haveRight('rssfeed_public', CREATE)) { echo "<span class='floatright'>"; echo "<a href='" . $CFG_GLPI["root_doc"] . "/front/rssfeed.form.php'>"; echo "<img src='" . $CFG_GLPI["root_doc"] . "/pics/plus.png' alt='" . __s('Add') . "' title=\"" . __s('Add') . "\"></a></span>"; } echo "</div></th></tr>\n"; if ($nb) { usort($items, array('SimplePie', 'sort_items')); foreach ($items as $item) { echo "<tr class='tab_bg_1'><td>"; echo HTML::convDateTime($item->get_date('Y-m-d H:i:s')); echo "</td><td>"; $link = $item->feed->get_permalink(); if (empty($link)) { echo $item->feed->get_title(); } else { echo "<a target='_blank' href='{$link}'>" . $item->feed->get_title() . '</a>'; } $link = $item->get_permalink(); // echo "<br>"; // echo $item->get_title(); // echo "</td><td>"; $rand = mt_rand(); echo "<div id='rssitem{$rand}' class='pointer rss'>"; if (!is_null($link)) { echo "<a target='_blank' href='{$link}'>"; } echo $item->get_title(); // echo Html::resume_text(Html::clean(Toolbox::unclean_cross_side_scripting_deep($item->get_content())), 300); if (!is_null($link)) { echo "</a>"; } echo "</div>"; Html::showToolTip(Toolbox::unclean_html_cross_side_scripting_deep($item->get_content()), array('applyto' => "rssitem{$rand}", 'display' => true)); echo "</td></tr>"; } } echo "</table>\n"; }
/** * Show list for central view * * @param $personal boolean : display reminders created by me ? (true by default) * * @return Nothing (display function) **/ static function showListForCentral($personal = true) { global $DB, $CFG_GLPI; $users_id = Session::getLoginUserID(); $today = date('Y-m-d'); $now = date('Y-m-d H:i:s'); $restrict_visibility = " AND (`glpi_reminders`.`begin_view_date` IS NULL\n OR `glpi_reminders`.`begin_view_date` < '{$now}')\n AND (`glpi_reminders`.`end_view_date` IS NULL\n OR `glpi_reminders`.`end_view_date` > '{$now}') "; if ($personal) { /// Personal notes only for central view if ($_SESSION['glpiactiveprofile']['interface'] == 'helpdesk') { return false; } $query = "SELECT `glpi_reminders`.*\n FROM `glpi_reminders`\n WHERE `glpi_reminders`.`users_id` = '{$users_id}'\n AND (`glpi_reminders`.`end` >= '{$today}'\n OR `glpi_reminders`.`is_planned` = '0')\n {$restrict_visibility}\n ORDER BY `glpi_reminders`.`name`"; $titre = "<a href='" . $CFG_GLPI["root_doc"] . "/front/reminder.php'>" . _n('Personal reminder', 'Personal reminders', 2) . "</a>"; } else { // Show public reminders / not mines : need to have access to public reminders if (!Session::haveRight('reminder_public', 'r')) { return false; } $restrict_user = '******'; // Only personal on central so do not keep it if ($_SESSION['glpiactiveprofile']['interface'] == 'central') { $restrict_user = "******"; } $query = "SELECT `glpi_reminders`.*\n FROM `glpi_reminders` " . self::addVisibilityJoins() . "\n WHERE {$restrict_user}\n {$restrict_visibility}\n AND " . self::addVisibilityRestrict() . "\n ORDER BY `glpi_reminders`.`name`"; if ($_SESSION['glpiactiveprofile']['interface'] != 'helpdesk') { $titre = "<a href=\"" . $CFG_GLPI["root_doc"] . "/front/reminder.php\">" . _n('Public reminder', 'Public reminders', 2) . "</a>"; } else { $titre = _n('Public reminder', 'Public reminders', 2); } } $result = $DB->query($query); $nb = $DB->numrows($result); echo "<br><table class='tab_cadrehov'>"; echo "<tr><th><div class='relative'><span>{$titre}</span>"; if (self::canCreate()) { echo "<span class='reminder_right'>"; echo "<a href='" . $CFG_GLPI["root_doc"] . "/front/reminder.form.php'>"; echo "<img src='" . $CFG_GLPI["root_doc"] . "/pics/plus.png' alt='" . __s('Add') . "'\n title=\"" . __s('Add') . "\"></a></span>"; } echo "</div></th></tr>\n"; if ($nb) { $rand = mt_rand(); while ($data = $DB->fetch_assoc($result)) { echo "<tr class='tab_bg_2'><td><div class='relative reminder_list'>"; $link = "<a id='content_reminder_" . $data["id"] . $rand . "'\n href='" . $CFG_GLPI["root_doc"] . "/front/reminder.form.php?id=" . $data["id"] . "'>" . $data["name"] . "</a>"; $tooltip = Html::showToolTip(Toolbox::unclean_html_cross_side_scripting_deep($data["text"]), array('applyto' => "content_reminder_" . $data["id"] . $rand, 'display' => false)); printf(__('%1$s %2$s'), $link, $tooltip); if ($data["is_planned"]) { $tab = explode(" ", $data["begin"]); $date_url = $tab[0]; echo "<span class='reminder_right'>"; echo "<a href='" . $CFG_GLPI["root_doc"] . "/front/planning.php?date=" . $date_url . "&type=day'>"; echo "<img src='" . $CFG_GLPI["root_doc"] . "/pics/rdv.png' alt=\"" . __s('Planning') . "\" title=\"" . sprintf(__s('From %1$s to %2$s'), Html::convDateTime($data["begin"]), Html::convDateTime($data["end"])) . "\">"; echo "</a></span>"; } echo "</div></td></tr>\n"; } } echo "</table>\n"; }
/** * Print out (html) show item : question and answer * * @param $options array of options * * @return nothing (display item : question and answer) **/ function showFull($options = array()) { global $DB, $CFG_GLPI; if (!$this->can($this->fields['id'], READ)) { return false; } $linkusers_id = true; // show item : question and answer if (Session::getLoginUserID() === false && $CFG_GLPI["use_public_faq"] || $_SESSION["glpiactiveprofile"]["interface"] == "helpdesk" || !User::canView()) { $linkusers_id = false; } $this->updateCounter(); $knowbaseitemcategories_id = $this->fields["knowbaseitemcategories_id"]; $fullcategoryname = getTreeValueCompleteName("glpi_knowbaseitemcategories", $knowbaseitemcategories_id); $tmp = "<a href='" . $this->getSearchURL() . "?knowbaseitemcategories_id={$knowbaseitemcategories_id}'>" . $fullcategoryname . "</a>"; echo "<table class='tab_cadre_fixe'>"; echo "<tr><th colspan='4'>" . sprintf(__('%1$s: %2$s'), __('Category'), $tmp); echo "</th></tr>"; echo "<tr><td class='left' colspan='4'><h2>" . __('Subject') . "</h2>"; if (KnowbaseItemTranslation::canBeTranslated($this)) { echo KnowbaseItemTranslation::getTranslatedValue($this, 'name'); } else { echo $this->fields["name"]; } echo "</td></tr>"; echo "<tr><td class='left' colspan='4'><h2>" . __('Content') . "</h2>\n"; echo "<div id='kbanswer'>"; if (KnowbaseItemTranslation::canBeTranslated($this)) { $answer = KnowbaseItemTranslation::getTranslatedValue($this, 'answer'); } else { $answer = $this->fields["answer"]; } echo Toolbox::unclean_html_cross_side_scripting_deep($answer); echo "</div>"; echo "</td></tr>"; echo "<tr><th class='tdkb' colspan='2'>"; if ($this->fields["users_id"]) { // Integer because true may be 2 and getUserName return array if ($linkusers_id) { $linkusers_id = 1; } else { $linkusers_id = 0; } printf(__('%1$s: %2$s'), __('Writer'), getUserName($this->fields["users_id"], $linkusers_id)); echo "<br>"; } if ($this->fields["date"]) { //TRANS: %s is the datetime of update printf(__('Created on %s'), Html::convDateTime($this->fields["date"])); echo "<br>"; } if ($this->fields["date_mod"]) { //TRANS: %s is the datetime of update printf(__('Last update on %s'), Html::convDateTime($this->fields["date_mod"])); } echo "</th>"; echo "<th class='tdkb' colspan='2'>"; if ($this->countVisibilities() == 0) { echo "<span class='red'>" . __('Unpublished') . "</span><br>"; } printf(_n('%d view', '%d views', $this->fields["view"]), $this->fields["view"]); echo "<br>"; if ($this->fields["is_faq"]) { _e('This item is part of the FAQ'); } else { _e('This item is not part of the FAQ'); } echo "</th></tr>"; echo "</table>"; return true; }
/** * Update from 0.84 to 0.84.1 * * @return bool for success (will die for most error) **/ function update084to0841() { global $DB, $migration; $updateresult = true; $ADDTODISPLAYPREF = array(); //TRANS: %s is the number of new version $migration->displayTitle(sprintf(__('Update to %s'), '0.84.1')); $migration->setVersion('0.84.1'); $backup_tables = false; $newtables = array(); foreach ($newtables as $new_table) { // rename new tables if exists ? if (TableExists($new_table)) { $migration->dropTable("backup_{$new_table}"); $migration->displayWarning("{$new_table} table already exists. " . "A backup have been done to backup_{$new_table}."); $backup_tables = true; $query = $migration->renameTable("{$new_table}", "backup_{$new_table}"); } } if ($backup_tables) { $migration->displayWarning("You can delete backup tables if you have no need of them.", true); } // Convert html fields from numeric encoding to raw encoding $fields_to_clean = array('glpi_knowbaseitems' => 'answer', 'glpi_tickets' => 'solution', 'glpi_problems' => 'solution', 'glpi_reminders' => 'text', 'glpi_solutiontemplates' => 'content', 'glpi_notificationtemplatetranslations' => 'content_text'); foreach ($fields_to_clean as $table => $field) { foreach ($DB->request($table) as $data) { $text = Toolbox::unclean_html_cross_side_scripting_deep($data[$field]); $text = html_entity_decode($text, ENT_NOQUOTES, 'UTF-8'); $text = addslashes($text); $text = Toolbox::clean_cross_side_scripting_deep($text); $query = "UPDATE `{$table}`\n SET `{$field}` = '{$text}'\n WHERE `id` = '" . $data['id'] . "';"; $DB->queryOrDie($query, "0.84.1 fix encoding of html field : {$table}.{$field}"); } } // Add date_mod to document_item $migration->addField('glpi_documents_items', 'date_mod', 'datetime'); $migration->migrationOneTable('glpi_documents_items'); $query_doc_i = "UPDATE `glpi_documents_items` as `doc_i`\n INNER JOIN `glpi_documents` as `doc`\n ON `doc`.`id` = `doc_i`.`documents_id`\n SET `doc_i`.`date_mod` = `doc`.`date_mod`"; $DB->queryOrDie($query_doc_i, "0.84.1 update date_mod in glpi_documents_items"); // correct entities_id in documents_items $query_doc_i = "UPDATE `glpi_documents_items` as `doc_i`\n INNER JOIN `glpi_documents` as `doc`\n ON `doc`.`id` = `doc_i`.`documents_id`\n SET `doc_i`.`entities_id` = `doc`.`entities_id`,\n `doc_i`.`is_recursive` = `doc`.`is_recursive`"; $DB->queryOrDie($query_doc_i, "0.84.1 change entities_id in documents_items"); // add delete_problem $migration->addField('glpi_profiles', 'delete_problem', 'char', array('after' => 'edit_all_problem', 'update' => 'edit_all_problem')); // ************ Keep it at the end ************** //TRANS: %s is the table or item to migrate $migration->displayMessage(sprintf(__('Data migration - %s'), 'glpi_displaypreferences')); foreach ($ADDTODISPLAYPREF as $type => $tab) { $query = "SELECT DISTINCT `users_id`\n FROM `glpi_displaypreferences`\n WHERE `itemtype` = '{$type}'"; if ($result = $DB->query($query)) { if ($DB->numrows($result) > 0) { while ($data = $DB->fetch_assoc($result)) { $query = "SELECT MAX(`rank`)\n FROM `glpi_displaypreferences`\n WHERE `users_id` = '" . $data['users_id'] . "'\n AND `itemtype` = '{$type}'"; $result = $DB->query($query); $rank = $DB->result($result, 0, 0); $rank++; foreach ($tab as $newval) { $query = "SELECT *\n FROM `glpi_displaypreferences`\n WHERE `users_id` = '" . $data['users_id'] . "'\n AND `num` = '{$newval}'\n AND `itemtype` = '{$type}'"; if ($result2 = $DB->query($query)) { if ($DB->numrows($result2) == 0) { $query = "INSERT INTO `glpi_displaypreferences`\n (`itemtype` ,`num` ,`rank` ,`users_id`)\n VALUES ('{$type}', '{$newval}', '" . $rank++ . "',\n '" . $data['users_id'] . "')"; $DB->query($query); } } } } } else { // Add for default user $rank = 1; foreach ($tab as $newval) { $query = "INSERT INTO `glpi_displaypreferences`\n (`itemtype` ,`num` ,`rank` ,`users_id`)\n VALUES ('{$type}', '{$newval}', '" . $rank++ . "', '0')"; $DB->query($query); } } } } // must always be at the end $migration->executeMigration(); return $updateresult; }
/** * Print out (html) show item : question and answer * * @param $linkusers_id display users_id link (true by default) * @param $options array of options * * @return nothing (display item : question and answer) **/ function showFull($linkusers_id = true, $options = array()) { global $DB, $CFG_GLPI; if (!$this->can($this->fields['id'], 'r')) { return false; } // show item : question and answer if (!Session::haveRight("user", "r")) { $linkusers_id = false; } $inpopup = strpos($_SERVER['PHP_SELF'], "popup.php"); $this->updateCounter(); $knowbaseitemcategories_id = $this->fields["knowbaseitemcategories_id"]; $fullcategoryname = getTreeValueCompleteName("glpi_knowbaseitemcategories", $knowbaseitemcategories_id); if (!$inpopup) { $this->showTabs($options); } $options['colspan'] = 2; $options['canedit'] = 0; // Hide the buttons $this->showFormHeader($options); $tmp = "<a href='" . $this->getSearchURL() . "?knowbaseitemcategories_id={$knowbaseitemcategories_id}'>" . $fullcategoryname . "</a>"; echo "<tr class='tab_bg_3'><th colspan='4'>" . sprintf(__('%1$s: %2$s'), __('Category'), $tmp); echo "</th></tr>"; echo "<tr class='tab_bg_3'><td class='left' colspan='4'><h2>" . __('Subject') . "</h2>"; echo $this->fields["name"]; echo "</td></tr>"; echo "<tr class='tab_bg_3'><td class='left' colspan='4'><h2>" . __('Content') . "</h2>\n"; echo "<div id='kbanswer'>"; echo Toolbox::unclean_html_cross_side_scripting_deep($this->fields["answer"]); echo "</div>"; echo "</td></tr>"; echo "<tr><th class='tdkb' colspan='2'>"; if ($this->fields["users_id"]) { // Integer because true may be 2 and getUserName return array if ($linkusers_id) { $linkusers_id = 1; } else { $linkusers_id = 0; } printf(__('%1$s: %2$s'), __('Writer'), getUserName($this->fields["users_id"], $linkusers_id)); echo "<br>"; } if ($this->fields["date"]) { //TRANS: %s is the datetime of update printf(__('Created on %s'), Html::convDateTime($this->fields["date"])); } if ($this->countVisibilities() == 0) { echo "<br><span class='red'>" . __('Unpublished') . "</span>"; } echo "</th>"; echo "<th class='tdkb' colspan='2'>"; if ($this->fields["date_mod"]) { //TRANS: %s is the datetime of update printf(__('Last update on %s'), Html::convDateTime($this->fields["date_mod"])); echo "<br>"; } echo sprintf(_n('%d view', '%d views', $this->fields["view"]), $this->fields["view"]) . "</th></tr>"; $this->showFormButtons($options); if (!$inpopup) { $this->addDivForTabs(); } return true; }
/** * Display all translated field for an KnowbaseItem * * @param $item a KnowbaseItem item * * @return true; **/ static function showTranslations(KnowbaseItem $item) { global $DB, $CFG_GLPI; $canedit = $item->can($item->getID(), UPDATE); $rand = mt_rand(); if ($canedit) { echo "<div id='viewtranslation" . $item->getID() . "{$rand}'></div>\n"; echo "<script type='text/javascript' >\n"; echo "function addTranslation" . $item->getID() . "{$rand}() {\n"; $params = array('type' => __CLASS__, 'parenttype' => get_class($item), 'knowbaseitems_id' => $item->fields['id'], 'id' => -1); Ajax::updateItemJsCode("viewtranslation" . $item->getID() . "{$rand}", $CFG_GLPI["root_doc"] . "/ajax/viewsubitem.php", $params); echo "};"; echo "</script>\n"; echo "<div class='center'>" . "<a class='vsubmit' href='javascript:addTranslation" . $item->getID() . "{$rand}();'>" . __('Add a new translation') . "</a></div><br>"; } $obj = new self(); $found = $obj->find("`knowbaseitems_id`='" . $item->getID() . "'", "`language` ASC"); if (count($found) > 0) { if ($canedit) { Html::openMassiveActionsForm('mass' . __CLASS__ . $rand); $massiveactionparams = array('container' => 'mass' . __CLASS__ . $rand); Html::showMassiveActions($massiveactionparams); } echo "<div class='center'>"; echo "<table class='tab_cadre_fixehov'><tr class='tab_bg_2'>"; echo "<th colspan='4'>" . __("List of translations") . "</th></tr>"; if ($canedit) { echo "<th width='10'>"; Html::checkAllAsCheckbox('mass' . __CLASS__ . $rand); echo "</th>"; } echo "<th>" . __("Language") . "</th>"; echo "<th>" . __("Subject") . "</th>"; foreach ($found as $data) { echo "<tr class='tab_bg_1' " . ($canedit ? "style='cursor:pointer'\n onClick=\"viewEditTranslation" . $data['id'] . "{$rand}();\"" : '') . ">"; if ($canedit) { echo "<td class='center'>"; Html::showMassiveActionCheckBox(__CLASS__, $data["id"]); echo "</td>"; } echo "<td>"; if ($canedit) { echo "\n<script type='text/javascript' >\n"; echo "function viewEditTranslation" . $data["id"] . "{$rand}() {\n"; $params = array('type' => __CLASS__, 'parenttype' => get_class($item), 'knowbaseitems_id' => $item->getID(), 'id' => $data["id"]); Ajax::updateItemJsCode("viewtranslation" . $item->getID() . "{$rand}", $CFG_GLPI["root_doc"] . "/ajax/viewsubitem.php", $params); echo "};"; echo "</script>\n"; } echo Dropdown::getLanguageName($data['language']); echo "</td><td>"; echo $data["name"]; if (isset($data['answer']) && !empty($data['answer'])) { echo " "; Html::showToolTip(Toolbox::unclean_html_cross_side_scripting_deep($data['answer'])); } echo "</td></tr>"; } echo "</table>"; if ($canedit) { $massiveactionparams['ontop'] = false; Html::showMassiveActions($massiveactionparams); Html::closeForm(); } } else { echo "<table class='tab_cadre_fixe'><tr class='tab_bg_2'>"; echo "<th class='b'>" . __("No translation found") . "</th></tr></table>"; } return true; }
/** * Get KB answer, with id on titles to set anchors * * @return string */ public function getAnswer() { if (KnowbaseItemTranslation::canBeTranslated($this)) { $answer = KnowbaseItemTranslation::getTranslatedValue($this, 'answer'); } else { $answer = $this->fields["answer"]; } $answer = Toolbox::unclean_html_cross_side_scripting_deep($answer); $callback = function ($matches) { //1 => tag name, 2 => existing attributes, 3 => title contents $tpl = '<%tag%attrs id="%slug"><a href="#%slug">%icon</a>%title</%tag>'; $title = str_replace(['%tag', '%attrs', '%slug', '%title', '%icon'], [$matches[1], $matches[2], Toolbox::slugify($matches[3]), $matches[3], '<svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"/></svg>'], $tpl); return $title; }; $pattern = '|<(h[1-6]{1})(.?[^>])?>(.+)</h[1-6]{1}>|'; $answer = preg_replace_callback($pattern, $callback, $answer); return $answer; }