From 4387fb715b59be1ead2db8b12fa008160cd14ce7 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Wed, 15 Mar 2017 15:53:03 -0700 Subject: ensure z_input_filter is called exactly once, since we now depend on the number of htmlspecialchars operations for markdown content. Also ensure that the content is escaped the correct number of times on imported items. --- include/items.php | 68 ++++++++++++++++++++++++++++++++++++------------------ include/photos.php | 9 ++++++++ 2 files changed, 55 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/items.php b/include/items.php index 382be2497..6e9c1c3d9 100755 --- a/include/items.php +++ b/include/items.php @@ -530,11 +530,6 @@ function get_item_elements($x,$allow_code = false) { $arr = array(); - if($allow_code) - $arr['body'] = $x['body']; - else - $arr['body'] = (($x['body']) ? htmlspecialchars($x['body'],ENT_COMPAT,'UTF-8',false) : ''); - $key = get_config('system','pubkey'); $maxlen = get_max_import_size(); @@ -647,7 +642,17 @@ function get_item_elements($x,$allow_code = false) { return array(); } + // Check signature on the body text received. + // This presents an issue that we aren't verifying the text that is actually displayed + // on this site. We are however verifying the received text was exactly as received. + // We have every right to strip content that poses a security risk. You are welcome to + // create a plugin to verify the content after filtering if this offends you. + if($arr['sig']) { + + // check the supplied signature against the supplied content. + // Note that we will purify the content which could change it. + $r = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1", dbesc($arr['author_xchan']) ); @@ -657,6 +662,14 @@ function get_item_elements($x,$allow_code = false) { logger('get_item_elements: message verification failed.'); } + // if the input is markdown, remove one level of html escaping. + // It will be re-applied in item_store() and/or item_store_update(). + // Do this after signature checking as the original signature + // was generated on the escaped content. + + if($arr['mimetype'] === 'text/markdown') + $arr['body'] = \Zotlabs\Lib\MarkdownSoap::unescape($arr['body']); + if(array_key_exists('revision',$x)) { // extended export encoding @@ -1525,14 +1538,20 @@ function item_store($arr, $allow_exec = false, $deliver = true) { $arr['lang'] = detect_language($arr['body']); // apply the input filter here - $arr['body'] = trim(z_input_filter($arr['body'],$arr['mimetype'],$allow_exec)); - - if(local_channel() && (local_channel() == $arr['uid'])) { - if(! $arr['sig']) { - $channel = App::get_channel(); - if($channel['channel_hash'] === $arr['author_xchan']) { - $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey'])); - $arr['item_verified'] = 1; + + if(array_key_exists('input_filtered_signed',$arr)) { + unset($arr['input_filtered_signed']); + } + else { + $arr['body'] = trim(z_input_filter($arr['body'],$arr['mimetype'],$allow_exec)); + + if(local_channel() && (local_channel() == $arr['uid'])) { + if(! $arr['sig']) { + $channel = App::get_channel(); + if($channel['channel_hash'] === $arr['author_xchan']) { + $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey'])); + $arr['item_verified'] = 1; + } } } } @@ -1946,17 +1965,22 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) { return $ret; } - $arr['lang'] = detect_language($arr['body']); - // apply the input filter here - $arr['body'] = trim($arr['body'],$arr['mimetype'],$allow_exec); - - if(local_channel() && (local_channel() == $arr['uid']) && (! $arr['sig'])) { - $channel = App::get_channel(); - if($channel['channel_hash'] === $arr['author_xchan']) { - $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey'])); - $arr['item_verified'] = 1; + if(array_key_exists('input_filtered_signed',$arr)) { + unset($arr['input_filtered_signed']); + } + else { + $arr['body'] = trim(z_input_filter($arr['body'],$arr['mimetype'],$allow_exec)); + + if(local_channel() && (local_channel() == $arr['uid'])) { + if(! $arr['sig']) { + $channel = App::get_channel(); + if($channel['channel_hash'] === $arr['author_xchan']) { + $arr['sig'] = base64url_encode(rsa_sign($arr['body'],$channel['channel_prvkey'])); + $arr['item_verified'] = 1; + } + } } } diff --git a/include/photos.php b/include/photos.php index 22b3e0c88..dff45a0bc 100644 --- a/include/photos.php +++ b/include/photos.php @@ -337,12 +337,15 @@ function photo_upload($channel, $observer, $args) { if($item['mid'] === $item['parent_mid']) { $item['body'] = $summary; + $item['mimetype'] = 'text/bbcode'; $item['obj_type'] = ACTIVITY_OBJ_PHOTO; $item['obj'] = json_encode($object); $item['tgt_type'] = ACTIVITY_OBJ_ALBUM; $item['target'] = json_encode($target); + $item['body'] = trim(z_input_filter($item['body'],$item['mimetype'],false)); + if($item['author_xchan'] === $channel['channel_hash']) { $item['sig'] = base64url_encode(rsa_sign($item['body'],$channel['channel_prvkey'])); $item['item_verified'] = 1; @@ -350,6 +353,12 @@ function photo_upload($channel, $observer, $args) { else { $item['sig'] = ''; } + + // notify item_store or item_store_update that the input has been filtered and signed already. + // The signing procedure in those functions uses local_channel() which may not apply here. + + $item['input_filtered_signed'] = true; + $force = true; } -- cgit v1.2.3