diff options
author | friendica <info@friendica.com> | 2013-09-02 01:38:17 -0700 |
---|---|---|
committer | friendica <info@friendica.com> | 2013-09-02 01:38:17 -0700 |
commit | 8b7757e033c4483da24700722c186057bb431164 (patch) | |
tree | c331db3262084b08b47970c20f2d8657d6ebef81 | |
parent | a35d440ff1fee806a8aa17a0297e1163db6a3ba5 (diff) | |
download | volse-hubzilla-8b7757e033c4483da24700722c186057bb431164.tar.gz volse-hubzilla-8b7757e033c4483da24700722c186057bb431164.tar.bz2 volse-hubzilla-8b7757e033c4483da24700722c186057bb431164.zip |
webpage content-type -- needs cleaning up and a security check once all the important bits are in place.
-rw-r--r-- | include/conversation.php | 8 | ||||
-rwxr-xr-x | include/items.php | 10 | ||||
-rwxr-xr-x | include/text.php | 60 | ||||
-rw-r--r-- | mod/blocks.php | 2 | ||||
-rw-r--r-- | mod/item.php | 244 | ||||
-rw-r--r-- | mod/webpages.php | 3 | ||||
-rw-r--r-- | version.inc | 2 | ||||
-rwxr-xr-x | view/tpl/jot.tpl | 3 |
8 files changed, 206 insertions, 126 deletions
diff --git a/include/conversation.php b/include/conversation.php index 2157f8291..a357e1480 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -1009,9 +1009,16 @@ function status_editor($a,$x,$popup=false) { $geotag = (($x['allow_location']) ? replace_macros(get_markup_template('jot_geotag.tpl'), array()) : ''); $plaintext = true; + if(feature_enabled(local_user(),'richtext')) $plaintext = false; + if(intval($x['plaintext'])) + $plaintext = true; + + if(intval($x['mimeselect'])) + $mimeselect = mimetype_select($x['profile_uid']); + $tpl = get_markup_template('jot-header.tpl'); $a->page['htmlhead'] .= replace_macros($tpl, array( @@ -1079,6 +1086,7 @@ function status_editor($a,$x,$popup=false) { '$emtitle' => t('Example: bob@example.com, mary@example.com'), '$lockstate' => $x['lockstate'], '$acl' => $x['acl'], + '$mimeselect' => $mimeselect, '$showacl' => ((array_key_exists('showacl',$x)) ? $x['showacl'] : 'yes'), '$bang' => $x['bang'], '$profile_uid' => $x['profile_uid'], diff --git a/include/items.php b/include/items.php index 712c416de..66172ade3 100755 --- a/include/items.php +++ b/include/items.php @@ -1397,14 +1397,10 @@ function item_store($arr,$allow_exec = false) { $arr['item_private'] = ((x($arr,'item_private')) ? intval($arr['item_private']) : 0 ); $arr['item_flags'] = ((x($arr,'item_flags')) ? intval($arr['item_flags']) : 0 ); - // this is a bit messy - we really need an input filter chain that temporarily undoes obscuring - if($arr['mimetype'] != 'text/html' && $arr['mimetype'] != 'application/x-php') { - if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false)) - $arr['body'] = escape_tags($arr['body']); - if((strpos($arr['title'],'<') !== false) || (strpos($arr['title'],'>') !== false)) - $arr['title'] = escape_tags($arr['title']); - } + $arr['body'] = z_input_filter($arr['uid'],$arr['body'],$arr['mimetype']); + $arr['title'] = escape_tags($arr['title']); + // only detect language if we have text content, and if the post is private but not yet // obscured, make it so. diff --git a/include/text.php b/include/text.php index 99d5c9d78..606ef421c 100755 --- a/include/text.php +++ b/include/text.php @@ -81,6 +81,34 @@ function escape_tags($string) { } +function z_input_filter($channel_id,$s,$type = 'text/bbcode') { + + if($type === 'text/bbcode') + return escape_tags($s); + if($type === 'text/markdown') + return escape_tags($s); + if($type == 'text/plain') + return escape_tags($s); + $r = q("select account_id, account_roles from account left join channel on channel_account_id = account_id where channel_id = %d limit 1", + intval($channel_id) + ); + if($r && ($r[0]['account_roles'] & ACCOUNT_ROLE_ALLOWEXEC)) { + if(local_user() && (get_account_id() == $r[0]['account_id'])) { + return $s; + } + } + + if($type === 'text/html') + return purify_html($s); + + return escape_tags($s); + +} + + + + + function purify_html($s) { require_once('library/HTMLPurifier.auto.php'); require_once('include/html2bbcode.php'); @@ -1127,6 +1155,7 @@ function prepare_body(&$item,$attach = false) { function prepare_text($text,$content_type = 'text/bbcode') { + switch($content_type) { case 'text/plain': @@ -1291,6 +1320,37 @@ function unamp($s) { } +function mimetype_select($channel_id, $current = 'text/bbcode') { + + $x = array( + 'text/bbcode', + 'text/html', + 'text/markdown', + 'text/plain' + ); + + $r = q("select account_flags from account left join channel on account_id = channel_account_id where + channel_id = %d limit 1", + intval($channel_id) + ); + + if($r) { + if($r[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) { + $x[] = 'application/x-php'; + } + } + + $o = t('Page content type: '); + $o .= '<select name="mimetype" id="mimetype-select">'; + foreach($x as $y) { + $select = (($y == $current) ? ' selected="selected" ' : ''); + $o .= '<option name="' . $y . '"' . $select . '>' . $y . '</option>'; + } + $o .= '</select>'; + + return $o; + +} diff --git a/mod/blocks.php b/mod/blocks.php index bb1b68e8b..29117eae8 100644 --- a/mod/blocks.php +++ b/mod/blocks.php @@ -1,6 +1,6 @@ <?php -function webpages_content(&$a) { +function blocks_content(&$a) { if(argc() > 1) $which = argv(1); diff --git a/mod/item.php b/mod/item.php index 060f36fdd..50644607d 100644 --- a/mod/item.php +++ b/mod/item.php @@ -44,7 +44,7 @@ function item_post(&$a) { call_hooks('post_local_start', $_REQUEST); -// logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA); + logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA); $api_source = ((x($_REQUEST,'api_source') && $_REQUEST['api_source']) ? true : false); @@ -221,7 +221,7 @@ function item_post(&$a) { $verb = $orig_post['verb']; $app = $orig_post['app']; $title = escape_tags(trim($_REQUEST['title'])); - $body = escape_tags(trim($_REQUEST['body'])); + $body = $_REQUEST['body']; $private = $orig_post['item_private']; } @@ -255,7 +255,7 @@ function item_post(&$a) { $coord = notags(trim($_REQUEST['coord'])); $verb = notags(trim($_REQUEST['verb'])); $title = escape_tags(trim($_REQUEST['title'])); - $body = escape_tags(trim($_REQUEST['body'])); + $body = $_REQUEST['body']; $private = ( ( strlen($str_group_allow) @@ -310,154 +310,164 @@ function item_post(&$a) { $post_type = notags(trim($_REQUEST['type'])); - $content_type = notags(trim($_REQUEST['content_type'])); - if(! $content_type) - $content_type = 'text/bbcode'; + $mimetype = notags(trim($_REQUEST['mimetype'])); + if(! $mimetype) + $mimetype = 'text/bbcode'; + // Verify ability to use html or php!!! -// BBCODE alert: the following functions assume bbcode input -// and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.) -// we may need virtual or template classes to implement the possible alternatives + if($preview) { + $body = z_input_filter($profile_uid,$body,$mimetype); + } - // Work around doubled linefeeds in Tinymce 3.5b2 - // First figure out if it's a status post that would've been - // created using tinymce. Otherwise leave it alone. +logger('body: ' . $body); - $plaintext = ((feature_enabled($profile_uid,'richtext')) ? false : true); - if((! $parent) && (! $api_source) && (! $plaintext)) { - $body = fix_mce_lf($body); - } + if($mimetype === 'text/bbcode') { - // If we're sending a private top-level message with a single @-taggable channel as a recipient, @-tag it. + // BBCODE alert: the following functions assume bbcode input + // and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.) + // we may need virtual or template classes to implement the possible alternatives - if((! $parent) && (substr_count($str_contact_allow,'<') == 1) && ($str_group_allow == '') && ($str_contact_deny == '') && ($str_group_deny == '')) { - $x = q("select abook_id, abook_their_perms from abook where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc(str_replace(array('<','>'),array('',''),$str_contact_allow)), - intval($profile_uid) - ); - if($x && ($x[0]['abook_their_perms'] & PERMS_W_TAGWALL)) - $body .= "\n\n@group+" . $x[0]['abook_id'] . "\n"; - } + // Work around doubled linefeeds in Tinymce 3.5b2 + // First figure out if it's a status post that would've been + // created using tinymce. Otherwise leave it alone. - /** - * fix naked links by passing through a callback to see if this is a red site - * (already known to us) which will get a zrl, otherwise link with url - */ + $plaintext = ((feature_enabled($profile_uid,'richtext')) ? false : true); + if((! $parent) && (! $api_source) && (! $plaintext)) { + $body = fix_mce_lf($body); + } - $body = preg_replace_callback("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,]+)/ism", 'red_zrl_callback', $body); + // If we're sending a private top-level message with a single @-taggable channel as a recipient, @-tag it. - /** - * - * When a photo was uploaded into the message using the (profile wall) ajax - * uploader, The permissions are initially set to disallow anybody but the - * owner from seeing it. This is because the permissions may not yet have been - * set for the post. If it's private, the photo permissions should be set - * appropriately. But we didn't know the final permissions on the post until - * now. So now we'll look for links of uploaded messages that are in the - * post and set them to the same permissions as the post itself. - * - */ + if((! $parent) && (substr_count($str_contact_allow,'<') == 1) && ($str_group_allow == '') && ($str_contact_deny == '') && ($str_group_deny == '')) { + $x = q("select abook_id, abook_their_perms from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc(str_replace(array('<','>'),array('',''),$str_contact_allow)), + intval($profile_uid) + ); + if($x && ($x[0]['abook_their_perms'] & PERMS_W_TAGWALL)) + $body .= "\n\n@group+" . $x[0]['abook_id'] . "\n"; + } - if(! $preview) { - fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],$body, - $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); + /** + * fix naked links by passing through a callback to see if this is a red site + * (already known to us) which will get a zrl, otherwise link with url + */ - fix_attached_file_permissions($channel,$observer['xchan_hash'],$body, - $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); + $body = preg_replace_callback("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,]+)/ism", 'red_zrl_callback', $body); - } + /** + * + * When a photo was uploaded into the message using the (profile wall) ajax + * uploader, The permissions are initially set to disallow anybody but the + * owner from seeing it. This is because the permissions may not yet have been + * set for the post. If it's private, the photo permissions should be set + * appropriately. But we didn't know the final permissions on the post until + * now. So now we'll look for links of uploaded messages that are in the + * post and set them to the same permissions as the post itself. + * + */ + if(! $preview) { + fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],$body, + $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); + fix_attached_file_permissions($channel,$observer['xchan_hash'],$body, + $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); - $body = bb_translate_video($body); + } - /** - * Fold multi-line [code] sequences - */ - $body = preg_replace('/\[\/code\]\s*\[code\]/ism',"\n",$body); - $body = scale_external_images($body,false); + $body = bb_translate_video($body); - /** - * Look for any tags and linkify them - */ + /** + * Fold multi-line [code] sequences + */ - $str_tags = ''; - $inform = ''; - $post_tags = array(); + $body = preg_replace('/\[\/code\]\s*\[code\]/ism',"\n",$body); - $tags = get_tags($body); + $body = scale_external_images($body,false); - $tagged = array(); + /** + * Look for any tags and linkify them + */ - $private_forum = false; + $str_tags = ''; + $inform = ''; + $post_tags = array(); - if(count($tags)) { - foreach($tags as $tag) { + $tags = get_tags($body); - // If we already tagged 'Robert Johnson', don't try and tag 'Robert'. - // Robert Johnson should be first in the $tags array + $tagged = array(); - $fullnametagged = false; - for($x = 0; $x < count($tagged); $x ++) { - if(stristr($tagged[$x],$tag . ' ')) { - $fullnametagged = true; - break; + $private_forum = false; + + if(count($tags)) { + foreach($tags as $tag) { + + // If we already tagged 'Robert Johnson', don't try and tag 'Robert'. + // Robert Johnson should be first in the $tags array + + $fullnametagged = false; + for($x = 0; $x < count($tagged); $x ++) { + if(stristr($tagged[$x],$tag . ' ')) { + $fullnametagged = true; + break; + } + } + if($fullnametagged) + continue; + + $success = handle_tag($a, $body, $inform, $str_tags, (local_user()) ? local_user() : $profile_uid , $tag); + logger('handle_tag: ' . print_r($success,tue)); + + if($success['replaced']) { + $tagged[] = $tag; + $post_tags[] = array( + 'uid' => $profile_uid, + 'type' => $success['termtype'], + 'otype' => TERM_OBJ_POST, + 'term' => $success['term'], + 'url' => $success['url'] + ); + } + if(is_array($success['contact']) && intval($success['contact']['prv'])) { + $private_forum = true; + $private_id = $success['contact']['id']; } - } - if($fullnametagged) - continue; - - $success = handle_tag($a, $body, $inform, $str_tags, (local_user()) ? local_user() : $profile_uid , $tag); - logger('handle_tag: ' . print_r($success,tue)); - - if($success['replaced']) { - $tagged[] = $tag; - $post_tags[] = array( - 'uid' => $profile_uid, - 'type' => $success['termtype'], - 'otype' => TERM_OBJ_POST, - 'term' => $success['term'], - 'url' => $success['url'] - ); - } - if(is_array($success['contact']) && intval($success['contact']['prv'])) { - $private_forum = true; - $private_id = $success['contact']['id']; } } - } // logger('post_tags: ' . print_r($post_tags,true)); - if(($private_forum) && (! $parent) && (! $private)) { - // we tagged a private forum in a top level post and the message was public. - // Restrict it. - $private = 1; - $str_contact_allow = '<' . $private_id . '>'; - } - - $attachments = ''; - $match = false; + if(($private_forum) && (! $parent) && (! $private)) { + // we tagged a private forum in a top level post and the message was public. + // Restrict it. + $private = 1; + $str_contact_allow = '<' . $private_id . '>'; + } - if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) { - $attachments = array(); - foreach($match[2] as $mtch) { - $hash = substr($mtch,0,strpos($mtch,',')); - $rev = intval(substr($mtch,strpos($mtch,','))); - $r = attach_by_hash_nodata($hash,$rev); - if($r['success']) { - $attachments[] = array( - 'href' => $a->get_baseurl() . '/attach/' . $r['data']['hash'], - 'length' => $r['data']['filesize'], - 'type' => $r['data']['filetype'], - 'title' => urlencode($r['data']['filename']), - 'revision' => $r['data']['revision'] - ); + $attachments = ''; + $match = false; + + if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) { + $attachments = array(); + foreach($match[2] as $mtch) { + $hash = substr($mtch,0,strpos($mtch,',')); + $rev = intval(substr($mtch,strpos($mtch,','))); + $r = attach_by_hash_nodata($hash,$rev); + if($r['success']) { + $attachments[] = array( + 'href' => $a->get_baseurl() . '/attach/' . $r['data']['hash'], + 'length' => $r['data']['filesize'], + 'type' => $r['data']['filetype'], + 'title' => urlencode($r['data']['filename']), + 'revision' => $r['data']['revision'] + ); + } + $body = str_replace($match[1],'',$body); } - $body = str_replace($match[1],'',$body); } } @@ -530,7 +540,7 @@ function item_post(&$a) { $datarray['changed'] = datetime_convert(); $datarray['mid'] = $mid; $datarray['parent_mid'] = $parent_mid; - $datarray['mimetype'] = $content_type; + $datarray['mimetype'] = $mimetype; $datarray['title'] = $title; $datarray['body'] = $body; $datarray['app'] = $app; diff --git a/mod/webpages.php b/mod/webpages.php index f3e1cd2f7..081297eb9 100644 --- a/mod/webpages.php +++ b/mod/webpages.php @@ -52,10 +52,13 @@ require_once ('include/conversation.php'); 'bang' => (($group || $cid) ? '!' : ''), 'visitor' => 'block', 'profile_uid' => intval($owner), + 'plaintext' => 1, + 'mimeselect' => 1, ); $o .= status_editor($a,$x); + //Get a list of webpages. We can't display all them because endless scroll makes that unusable, so just list titles and an edit link. //TODO - this should be replaced with pagelist_widget diff --git a/version.inc b/version.inc index 6119cf100..5a1e9d9a7 100644 --- a/version.inc +++ b/version.inc @@ -1 +1 @@ -2013-09-01.423 +2013-09-02.424 diff --git a/view/tpl/jot.tpl b/view/tpl/jot.tpl index 8092a7047..e67caf3d2 100755 --- a/view/tpl/jot.tpl +++ b/view/tpl/jot.tpl @@ -9,6 +9,9 @@ <input type="hidden" name="post_id" value="{{$post_id}}" /> <input type="hidden" name="webpage" value="{{$webpage}}" /> <input type="hidden" name="preview" id="jot-preview" value="0" /> + + {{$mimeselect}} + <div id="jot-title-wrap"><input name="title" id="jot-title" type="text" placeholder="{{$placeholdertitle}}" value="{{$title}}" class="jothidden" style="display:none"></div> {{if $catsenabled}} <div id="jot-category-wrap"><input name="category" id="jot-category" type="text" placeholder="{{$placeholdercategory}}" value="{{$category}}" class="jothidden" style="display:none" /></div> |