From 2139287c05e3a0f26e9e6bbdccde33a114b2eefb Mon Sep 17 00:00:00 2001 From: azett Date: Fri, 17 Apr 2020 12:53:32 +0200 Subject: [PATCH] Fix for #62: Comments weren't sanitized properly. Thanks, @Illevyard! --- comments.php | 100 +++++------ fp-includes/core/core.comment.php | 275 ++++++++++++++---------------- 2 files changed, 182 insertions(+), 193 deletions(-) diff --git a/comments.php b/comments.php index 0984843..ae7dcd8 100644 --- a/comments.php +++ b/comments.php @@ -2,9 +2,9 @@ if (!defined('MOD_INDEX')) { include 'defaults.php'; include INCLUDES_DIR . 'includes.php'; - + /* backward compatibility */ - + if (!@$_GET ['entry']) { @utils_redirect(); } else { @@ -17,19 +17,19 @@ $module = comment_main($module); function comment_main($module) { global $fpdb, $fp_params; - + // hackish solution to get title before fullparse starts dunno, I don't like it - + $q = & $fpdb->getQuery(); - + list ($id, $entry) = @$q->peekEntry(); if (!$entry) return $module; - + if (!empty($fp_params ['feed'])) { - + switch ($fp_params ['feed']) { - + case 'atom': header('Content-type: application/atom+xml'); $module = SHARED_TPLS . 'comment-atom.tpl'; @@ -40,10 +40,10 @@ function comment_main($module) { $module = SHARED_TPLS . 'comment-rss.tpl'; } } elseif (!in_array('commslock', $entry ['categories'])) { - + commentform(); } - + return $module; } @@ -68,11 +68,11 @@ add_filter('wp_title', 'comment_pagetitle', 10, 2); function comment_validate() { global $smarty, $lang; - + $lerr = & $lang ['comments'] ['error']; - + $r = true; - + /* * $lang['comments']['error'] = array( * 'name' => 'You must enter a name', @@ -81,13 +81,13 @@ function comment_validate() { * 'comment' => 'You must enter a comment', * ); */ - - $content = isset($_POST ['content']) ? trim(stripslashes($_POST ['content'])) : null; - + + $content = isset($_POST ['content']) ? trim(addslashes($_POST ['content'])) : null; + $errors = array(); - + $loggedin = false; - + if (user_loggedin()) { $user = user_get(); $loggedin = $arr ['loggedin'] = true; @@ -98,54 +98,54 @@ function comment_validate() { $name = trim(htmlspecialchars(@$_POST ['name'])); $email = isset($_POST ['email']) ? trim(htmlspecialchars($_POST ['email'])) : null; $url = isset($_POST ['url']) ? trim(stripslashes(htmlspecialchars($_POST ['url']))) : null; - + /* * check name * */ - + if (!$name) { $errors ['name'] = $lerr ['name']; } - + /* * check email * */ - + if ($email) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $errors ['email'] = $lerr ['email']; } } - + /* * check url * */ - + if ($url) { if (!filter_var($url, FILTER_VALIDATE_URL)) { $errors ['url'] = $lerr ['www']; } } } - + if (!$content) { $errors ['content'] = $lerr ['comment']; } - + if ($errors) { $smarty->assign('error', $errors); return false; } - + $arr ['version'] = system_ver(); $arr ['name'] = $name; - + if (!$loggedin) setcookie('comment_author_' . COOKIEHASH, $arr ['name'], time() + 30000000, COOKIEPATH, COOKIE_DOMAIN); - + if ($email) { ($arr ['email'] = $email); if (!$loggedin) @@ -157,11 +157,11 @@ function comment_validate() { setcookie('comment_author_url_' . COOKIEHASH, $arr ['url'], time() + 30000000, COOKIEPATH, COOKIE_DOMAIN); } $arr ['content'] = $content; - + if ($v = utils_ipget()) { $arr ['ip-address'] = $v; } - + if ($loggedin || apply_filters('comment_validate', true, $arr)) return $arr; else @@ -170,47 +170,47 @@ function comment_validate() { function commentform() { global $smarty, $lang, $fpdb, $fp_params; - + $comment_formid = 'fp-comments'; $smarty->assign('comment_formid', $comment_formid); - + if (!empty($_POST)) { - + // utils_nocache_headers(); - + // add http to url if not given if (!empty($_POST ['url']) && strpos($_POST ['url'], 'http://') === false && strpos($_POST ['url'], 'https://') === false) $_POST ['url'] = 'http://' . $_POST ['url']; - + // custom hook here!! if ($arr = comment_validate()) { - + global $fp_config; - + $id = comment_save($fp_params ['entry'], $arr); - + do_action('comment_post', $fp_params ['entry'], array( $id, $arr )); - + $q = new FPDB_Query(array( 'id' => $fp_params ['entry'], 'fullparse' => false ), null); list ($entryid, $e) = $q->getEntry(); - + if ($fp_config ['general'] ['notify'] && !user_loggedin()) { - + global $post; - + $comm_mail = isset($arr ['email']) ? "<{$arr['email']}>" : ''; $from_mail = $fp_config ['general'] ['email']; - + $post = $e; // plugin such as prettyurls might need this... - + $lang = lang_load('comments'); - + $mail = str_replace(array( '%toname%', '%fromname%', @@ -228,20 +228,20 @@ function commentform() { $arr ['content'], $fp_config ['general'] ['title'] ), $lang ['comments'] ['mail']); - + @utils_mail($from_mail, "New comment on {$fp_config['general']['title']}", $mail); } - + // if comment is valid, this redirect will clean the postdata $location = str_replace('&', '&', get_comments_link($entryid)) . '#' . $id; - + utils_redirect($location, true); exit(); } else { $smarty->assign('values', $_POST); } } - + // Cookies $smarty->assign('cookie', array( 'name' => @$_COOKIE ['comment_author_' . COOKIEHASH], diff --git a/fp-includes/core/core.comment.php b/fp-includes/core/core.comment.php index 33d468d..a4d0f97 100755 --- a/fp-includes/core/core.comment.php +++ b/fp-includes/core/core.comment.php @@ -1,156 +1,145 @@ _directory = $f; - parent::__construct(); - //substr(bdb_idtofile($id), -strlen(EXT)); +class comment_indexer extends fs_filelister { + + function __construct($id) { + $f = bdb_idtofile($id, BDB_COMMENT); // todo change + $this->_directory = $f; + parent::__construct(); + // substr(bdb_idtofile($id), -strlen(EXT)); + } + + function _checkFile($directory, $file) { + $f = "$directory/$file"; + if (fnmatch('comment*' . EXT, $file)) { + array_push($this->_list, basename($file, EXT)); + return 0; } - - function _checkFile($directory, $file) { - $f = "$directory/$file"; - if (fnmatch('comment*'.EXT, $file)) { - array_push($this->_list, basename($file,EXT)); - return 0; - } - } - - // overrides parent method to return sorted results - function getList() { - sort($this->_list); - return parent::getList(); - } - - } - - - /** - * function bdb_get_comments - * - *

On success returns an array containing the comment IDs, associated to - * the entry ID in $id

- *

On failure returns false

- * - * @param string $id string formatted like "prefixYYMMDD-HHMMSS.EXT" - * @return mixed - * - * @see bdb_idtofile() - */ - function comment_getlist($id) { - $obj = new comment_indexer($id); //todo change syntax - return $obj->getList(); - - } - - function comment_parse($entryid, $id) { - - $f = comment_exists($entryid, $id); - - - if (!$f) return false; - - - $fc = io_load_file($f); - $arr = utils_kexplode($fc); - - //$arr['EMAIL'] = apply_filters('comment_email', $arr['EMAIL']); - // hackish: dash to underscore for ip-address :( todo: clean this up here or somewhere else - //$arr['ip_address'] = $arr['ip-address']; - return array_change_key_case($arr, CASE_LOWER); - - } - - function comment_exists($entryid, $id) { - if (!preg_match('|^comment[0-9]{6}-[0-9]{6}$|', $id)) - return false; - $f = entry_exists($entryid); - if (!$f) return false; - - $f2 = substr($f, 0, -strlen(EXT)) . '/comments/' . $id.EXT; - if (!file_exists($f2)) return false; - - return $f2; - } - - function comment_clean(&$arr) { - $arr['name'] = apply_filters('pre_comment_author_name', stripslashes($arr['name'])); - if (isset($arr['email'])) - $arr['email'] = apply_filters('pre_comment_author_email', $arr['email']); - if (isset($arr['url'])) - $arr['url'] = apply_filters('pre_comment_author_url', $arr['url']); - $arr['content'] = apply_filters('pre_comment_content', stripslashes($arr['content'])); - return $arr; + // overrides parent method to return sorted results + function getList() { + sort($this->_list); + return parent::getList(); } +} - /** - * function bdb_save_comment - * - *

Saves the content of the $comment array, associating it to the entry-ID $id.

- *

$comment must be formatted as the one returned by {@link bdb_parse_entry()}.

- *

Returns true on success, or false on failure

- * - * @param string $id string formatted like "prefixYYMMDD-HHMMSS" - * @param array $comment array formatted as the one returned by {@link bdb_parse_entry()} - * @return bool - * - * @see bdb_parse_entry() - */ - function comment_save($id, $comment) { - - comment_clean($comment); - - $comment = array_change_key_case($comment, CASE_UPPER); - - $comment_dir = bdb_idtofile($id,BDB_COMMENT); - - if (!isset($comment['DATE'])) - $comment['DATE'] = date_time(); - $id = bdb_idfromtime(BDB_COMMENT, $comment['DATE']); - $f = $comment_dir . $id . EXT; - $str = utils_kimplode($comment); - if (io_write_file($f, $str)) - return $id; - - +/** + * function bdb_get_comments + * + *

On success returns an array containing the comment IDs, associated to + * the entry ID in $id

+ *

On failure returns false

+ * + * @param string $id + * string formatted like "prefixYYMMDD-HHMMSS.EXT" + * @return mixed + * + * @see bdb_idtofile() + */ +function comment_getlist($id) { + $obj = new comment_indexer($id); // todo change syntax + return $obj->getList(); +} + +function comment_parse($entryid, $id) { + $f = comment_exists($entryid, $id); + + if (!$f) return false; - - - } - + $fc = io_load_file($f); + $arr = utils_kexplode($fc); - - /** - * function comment_delete - * - *

Deletes the $id comment

- *

Returns true on success, or false on failure

- * - * @param string $id string formatted like "entryYYMMDD-HHMMSS" - * @param string $comment_id string representig comment id as in "commentYYMMDD-HHMMSS" - * @return bool - * - * @see entry_delete() - */ - function comment_delete($id, $comment_id) { - do_action('comment_delete', $id, $comment_id); - $comment_dir = bdb_idtofile($id,BDB_COMMENT); - $f = $comment_dir . $comment_id .EXT; - return fs_delete($f); - } - - - function dummy_comment($val) { - return $val; - } - - add_filter('comment_validate', 'dummy_comment'); - + // $arr['EMAIL'] = apply_filters('comment_email', $arr['EMAIL']); + // hackish: dash to underscore for ip-address :( todo: clean this up here or somewhere else + // $arr['ip_address'] = $arr['ip-address']; + return array_change_key_case($arr, CASE_LOWER); +} + +function comment_exists($entryid, $id) { + if (!preg_match('|^comment[0-9]{6}-[0-9]{6}$|', $id)) + return false; + $f = entry_exists($entryid); + if (!$f) + return false; + + $f2 = substr($f, 0, -strlen(EXT)) . '/comments/' . $id . EXT; + if (!file_exists($f2)) + return false; + + return $f2; +} + +function comment_clean(&$arr) { + $arr ['name'] = apply_filters('pre_comment_author_name', stripslashes($arr ['name'])); + if (isset($arr ['email'])) + $arr ['email'] = apply_filters('pre_comment_author_email', $arr ['email']); + if (isset($arr ['url'])) + $arr ['url'] = apply_filters('pre_comment_author_url', $arr ['url']); + $arr ['content'] = apply_filters('pre_comment_content', $arr ['content']); + return $arr; +} + +/** + * function bdb_save_comment + * + *

Saves the content of the $comment array, associating it to the entry-ID $id.

+ *

$comment must be formatted as the one returned by {@link bdb_parse_entry()}.

+ *

Returns true on success, or false on failure

+ * + * @param string $id + * string formatted like "prefixYYMMDD-HHMMSS" + * @param array $comment + * array formatted as the one returned by {@link bdb_parse_entry()} + * @return bool + * + * @see bdb_parse_entry() + */ +function comment_save($id, $comment) { + comment_clean($comment); + + $comment = array_change_key_case($comment, CASE_UPPER); + + $comment_dir = bdb_idtofile($id, BDB_COMMENT); + + if (!isset($comment ['DATE'])) + $comment ['DATE'] = date_time(); + $id = bdb_idfromtime(BDB_COMMENT, $comment ['DATE']); + $f = $comment_dir . $id . EXT; + $str = utils_kimplode($comment); + if (io_write_file($f, $str)) + return $id; + + return false; +} + +/** + * function comment_delete + * + *

Deletes the $id comment

+ *

Returns true on success, or false on failure

+ * + * @param string $id + * string formatted like "entryYYMMDD-HHMMSS" + * @param string $comment_id + * string representig comment id as in "commentYYMMDD-HHMMSS" + * @return bool + * + * @see entry_delete() + */ +function comment_delete($id, $comment_id) { + do_action('comment_delete', $id, $comment_id); + $comment_dir = bdb_idtofile($id, BDB_COMMENT); + $f = $comment_dir . $comment_id . EXT; + return fs_delete($f); +} + +function dummy_comment($val) { + return $val; +} + +add_filter('comment_validate', 'dummy_comment'); - ?>