diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/auth.php | 39 | ||||
-rw-r--r-- | include/bbcode.php | 4 | ||||
-rw-r--r-- | include/event.php | 182 | ||||
-rw-r--r-- | include/feedutils.php | 20 | ||||
-rw-r--r-- | include/html2bbcode.php | 2 | ||||
-rw-r--r-- | include/items.php | 76 | ||||
-rw-r--r-- | include/language.php | 5 | ||||
-rw-r--r-- | include/nav.php | 4 | ||||
-rw-r--r-- | include/network.php | 21 | ||||
-rw-r--r-- | include/oembed.php | 12 | ||||
-rw-r--r-- | include/plugin.php | 117 | ||||
-rw-r--r-- | include/text.php | 22 | ||||
-rw-r--r-- | include/zid.php | 2 |
13 files changed, 343 insertions, 163 deletions
diff --git a/include/auth.php b/include/auth.php index 8eeb077b5..07b8e2971 100644 --- a/include/auth.php +++ b/include/auth.php @@ -30,9 +30,9 @@ require_once('include/security.php'); * The return array is dependent on the login mechanism. * $ret['account'] will be set if either an email or channel address validation was successful (local login). * $ret['channel'] will be set if a channel address validation was successful. - * $ret['xchan'] will be set if a guest access token validation was successful. - * Keys will exist for invalid return arrays but will be set to null. - * This function does not perform a login. It merely validates systems passwords and tokens. + * $ret['xchan'] will be set if a guest access token validation was successful. + * Keys will exist for invalid return arrays but will be set to null. + * This function does not perform a login. It merely validates systems passwords and tokens. * */ @@ -44,7 +44,7 @@ function account_verify_password($login, $pass) { $email_verify = get_config('system', 'verify_email'); $register_policy = get_config('system', 'register_policy'); - if(! $login) + if(!$login || !$pass) return null; $account = null; @@ -72,7 +72,7 @@ function account_verify_password($login, $pass) { $ret['account'] = $addon_auth['user_record']; return $ret; } - else { + else { if(! strpos($login,'@')) { $channel = channelx_by_nick($login); if(! $channel) { @@ -102,7 +102,7 @@ function account_verify_password($login, $pass) { $account = $a[0]; // Currently we only verify email address if there is an open registration policy. - // This isn't because of any policy - it's because the workflow gets too complicated if + // This isn't because of any policy - it's because the workflow gets too complicated if // you have to verify the email and then go through the account approval workflow before // letting them login. @@ -112,7 +112,7 @@ function account_verify_password($login, $pass) { } if($channel) { - // Try the authentication plugin again since weve determined we are using the channel login instead of account login + // Try the authentication plugin again since weve determined we are using the channel login instead of account login $addon_auth = [ 'username' => $account['account_email'], 'password' => trim($pass), @@ -128,7 +128,7 @@ function account_verify_password($login, $pass) { } } - if(($account['account_flags'] == ACCOUNT_OK) + if(($account['account_flags'] == ACCOUNT_OK) && (hash('whirlpool',$account['account_salt'] . $pass) === $account['account_password'])) { logger('password verified for ' . $login); $ret['account'] = $account; @@ -193,7 +193,7 @@ if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) && $_SESSION = $_SESSION['delegate_push']; info( t('Delegation session ended.') . EOL); } - else { + else { App::$session->nuke(); info( t('Logged out.') . EOL); } @@ -280,8 +280,11 @@ else { // handle a fresh login request - if((x($_POST, 'password')) && strlen($_POST['password'])) - $encrypted = hash('whirlpool', trim($_POST['password'])); + $password = $_POST['main_login_password'] ?? $_POST['modal_login_password']; + $username = $_POST['main_login_username'] ?? $_POST['modal_login_username']; + + if($password) + $encrypted = hash('whirlpool', trim($password)); if((x($_POST, 'auth-params')) && $_POST['auth-params'] === 'login') { @@ -289,10 +292,10 @@ else { $account = null; $channel = null; - $verify = account_verify_password($_POST['username'], $_POST['password']); + $verify = account_verify_password($username, $password); if($verify && array_key_exists('reason',$verify) && $verify['reason'] === 'unvalidated') { notice( t('Email validation is incomplete. Please check your email.')); - goaway(z_root() . '/email_validation/' . bin2hex(punify(trim(escape_tags($_POST['username']))))); + goaway(z_root() . '/email_validation/' . bin2hex(punify(trim(escape_tags($username))))); } elseif($verify) { $atoken = $verify['xchan']; @@ -311,8 +314,8 @@ else { } if(! ($account || $atoken)) { - $error = 'authenticate: failed login attempt: ' . notags(trim($_POST['username'])) . ' from IP ' . $_SERVER['REMOTE_ADDR']; - logger($error); + $error = 'authenticate: failed login attempt: ' . notags(trim($username)) . ' from IP ' . $_SERVER['REMOTE_ADDR']; + logger($error); // Also log failed logins to a separate auth log to reduce overhead for server side intrusion prevention $authlog = get_config('system', 'authlog'); if ($authlog) @@ -334,7 +337,9 @@ else { // (i.e. expire when the browser is closed), even when there's a time expiration // on the cookie - if(($_POST['remember_me']) || ($_POST['remember'])) { + $remember = $_POST['main_login_remember'] ?? $_POST['modal_login_remember']; + + if($remember) { $_SESSION['remember_me'] = 1; App::$session->new_cookie(31449600); // one year } @@ -360,7 +365,7 @@ else { * and returns the corresponding channel_id. * * @fixme How do we prevent that an OpenID identity is used more than once? - * + * * @param string $authid * The given openid_identity * @return int|bool diff --git a/include/bbcode.php b/include/bbcode.php index 03115effe..794cb25d0 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -488,9 +488,9 @@ function getAttachmentData($body) { $data["preview"] = html_entity_decode($preview, ENT_QUOTES, 'UTF-8'); } - $data["description"] = trim($match[3]); + $data["description"] = ((isset($match[3])) ? trim($match[3]) : ''); - $data["after"] = trim($match[4]); + $data["after"] = ((isset($match[4])) ? trim($match[4]) : ''); return $data; } diff --git a/include/event.php b/include/event.php index 440f559da..3d3dda035 100644 --- a/include/event.php +++ b/include/event.php @@ -70,8 +70,87 @@ function format_event_html($ev) { } function format_event_obj($jobject) { + $event = []; + $object = json_decode($jobject, true); + +/******* + This is our encoded format + + $x = [ + 'type' => 'Event', + 'id' => z_root() . '/event/' . $r[0]['resource_id'], + 'summary' => bbcode($arr['summary']), + // RFC3339 Section 4.3 + 'startTime' => (($arr['adjust']) ? datetime_convert('UTC','UTC',$arr['dtstart'], ATOM_TIME) : datetime_convert('UTC','UTC',$arr['dtstart'],'Y-m-d\\TH:i:s-00:00')), + 'content' => bbcode($arr['description']), + 'location' => [ 'type' => 'Place', 'content' => $arr['location'] ], + 'source' => [ 'content' => format_event_bbcode($arr), 'mediaType' => 'text/x-multicode' ], + 'url' => [ [ 'mediaType' => 'text/calendar', 'href' => z_root() . '/events/ical/' . $event['event_hash'] ] ], + 'actor' => Activity::encode_person($r[0],false), + ]; + if(! $arr['nofinish']) { + $x['endTime'] = (($arr['adjust']) ? datetime_convert('UTC','UTC',$arr['dtend'], ATOM_TIME) : datetime_convert('UTC','UTC',$arr['dtend'],'Y-m-d\\TH:i:s-00:00')); + } + +******/ + + if (is_array($object) && (array_key_exists('summary', $object) || array_key_exists('name', $object))) { + + $dtend = ((array_key_exists('endTime', $object)) ? $object['endTime'] : NULL_DATE); + $title = ((isset($object['summary']) && $object['summary']) ? zidify_links(smilies(bbcode($object['summary']))) : $object['name']); + + // mobilizon sets a timezone in the object + // we will assume that events with an timezone should be adjusted + $tz = $object['timezone'] ?? ''; + + // friendica has its own flag for adjust + $dfrn_adjust = $object['dfrn:adjust'] ?? ''; + + $adjust = ((strpos($object['startTime'], 'Z') !== false) || $tz || $dfrn_adjust); + + $allday = (($adjust) ? false : true); + + $dtstart = new DateTime($object['startTime']); + $dtend_obj = new DateTime($dtend); + + $dtdiff = $dtstart->diff($dtend_obj); + + if($allday && ($dtdiff->days < 2)) + $oneday = true; + + if($allday && !$oneday) { + // Subtract one day from the end date so we can use the "first day - last day" format for display. + $dtend_obj->modify('-1 day'); + $dtend = datetime_convert('UTC', 'UTC', $dtend_obj->format('Y-m-d H:i:s')); + } + + $bd_format = (($allday) ? t('l F d, Y') : t('l F d, Y \@ g:i A')); // Friday January 18, 2011 @ 8:01 AM or Friday January 18, 2011 for allday events + + $event['header'] = replace_macros(get_markup_template('event_item_header.tpl'), array( + '$title' => $title, + '$dtstart_label' => t('Start:'), + '$dtstart_title' => datetime_convert('UTC', 'UTC', $object['startTime'], ((strpos($object['startTime'], 'Z')) ? ATOM_TIME : 'Y-m-d\TH:i:s' )), + '$dtstart_dt' => (($adjust) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $object['startTime'], $bd_format)) : day_translate(datetime_convert('UTC', 'UTC', $object['startTime'], $bd_format))), + '$finish' => ((array_key_exists('endTime', $object)) ? true : false), + '$dtend_label' => t('End:'), + '$dtend_title' => datetime_convert('UTC', 'UTC', $dtend, ((strpos($object['startTime'], 'Z')) ? ATOM_TIME : 'Y-m-d\TH:i:s' )), + '$dtend_dt' => (($adjust) ? day_translate(datetime_convert('UTC', date_default_timezone_get(), $dtend, $bd_format)) : day_translate(datetime_convert('UTC', 'UTC', $dtend, $bd_format))), + '$allday' => $allday, + '$oneday' => $oneday, + '$event_tz' => ['label' => t('Timezone'), 'value' => (($tz === date_default_timezone_get()) ? '' : $tz)] + )); + $event['content'] = replace_macros(get_markup_template('event_item_content.tpl'), array( + '$description' => $object['content'], + '$location_label' => t('Location:'), + '$location' => ((array_path_exists('location/name', $object)) ? zidify_links(smilies(bbcode($object['location']['name']))) : EMPTY_STR) + )); + } + + return $event; +/* + $event = []; $object = json_decode($jobject,true); $event_tz = ''; @@ -136,6 +215,7 @@ function format_event_obj($jobject) { )); return $event; +*/ } function ical_wrapper($ev) { @@ -1122,34 +1202,35 @@ function event_store_item($arr, $event) { if($r) { - set_iconfig($r[0]['id'], 'event', 'timezone', $arr['timezone'], true); - xchan_query($r); - $r = fetch_post_tags($r,true); - - $object = json_encode(array( - 'type' => ACTIVITY_OBJ_EVENT, - 'id' => z_root() . '/event/' . $r[0]['resource_id'], - 'title' => $arr['summary'], - 'timezone' => $arr['timezone'], - 'dtstart' => $arr['dtstart'], - 'dtend' => $arr['dtend'], - 'nofinish' => $arr['nofinish'], - 'description' => $arr['description'], - 'location' => $arr['location'], - 'adjust' => $arr['adjust'], - 'content' => format_event_bbcode($arr), + //set_iconfig($r[0]['id'], 'event', 'timezone', $arr['timezone'], true); + //xchan_query($r); + //$r = fetch_post_tags($r,true); + + $x = [ + 'type' => 'Event', + 'id' => z_root() . '/event/' . $r[0]['resource_id'], + 'name' => $arr['summary'], +// 'summary' => bbcode($arr['summary']), + // RFC3339 Section 4.3 + 'startTime' => (($arr['adjust']) ? datetime_convert('UTC', 'UTC', $arr['dtstart'], ATOM_TIME) : datetime_convert('UTC', 'UTC', $arr['dtstart'], 'Y-m-d\\TH:i:s-00:00')), + 'content' => bbcode($arr['description']), + 'location' => [ 'type' => 'Place', 'name' => $arr['location'] ], + 'source' => [ 'content' => format_event_bbcode($arr), 'mediaType' => 'text/x-multicode' ], + 'url' => [ [ 'mediaType' => 'text/calendar', 'href' => z_root() . '/events/ical/' . $event['event_hash'] ] ], + 'actor' => Activity::encode_person($r[0], false), 'attachment' => Activity::encode_attachment($r[0]), - 'author' => array( - 'name' => $r[0]['author']['xchan_name'], - 'address' => $r[0]['author']['xchan_addr'], - 'guid' => $r[0]['author']['xchan_guid'], - 'guid_sig' => $r[0]['author']['xchan_guid_sig'], - 'link' => array( - array('rel' => 'alternate', 'type' => 'text/html', 'href' => $r[0]['author']['xchan_url']), - array('rel' => 'photo', 'type' => $r[0]['author']['xchan_photo_mimetype'], 'href' => $r[0]['author']['xchan_photo_m']) - ), - ), - )); + 'tag' => Activity::encode_taxonomy($r[0]) + ]; + + if (! $arr['nofinish']) { + $x['endTime'] = (($arr['adjust']) ? datetime_convert('UTC', 'UTC', $arr['dtend'], ATOM_TIME) : datetime_convert('UTC', 'UTC', $arr['dtend'], 'Y-m-d\\TH:i:s-00:00')); + } + + if ($event['event_repeat']) { + $x['eventRepeat'] = $event['event_repeat']; + } + + $object = json_encode($x); $private = (($arr['allow_cid'] || $arr['allow_gid'] || $arr['deny_cid'] || $arr['deny_gid']) ? 1 : 0); @@ -1285,29 +1366,30 @@ function event_store_item($arr, $event) { dbesc($arr['event_xchan']) ); if($x) { - $item_arr['obj'] = json_encode(array( - 'type' => ACTIVITY_OBJ_EVENT, - 'id' => z_root() . '/event/' . $event['event_hash'], - 'title' => $arr['summary'], - 'timezone' => $arr['timezone'], - 'dtstart' => $arr['dtstart'], - 'dtend' => $arr['dtend'], - 'nofinish' => $arr['nofinish'], - 'description' => $arr['description'], - 'location' => $arr['location'], - 'adjust' => $arr['adjust'], - 'content' => format_event_bbcode($arr), - 'attachment' => Activity::encode_attachment($item_arr), - 'author' => array( - 'name' => $x[0]['xchan_name'], - 'address' => $x[0]['xchan_addr'], - 'guid' => $x[0]['xchan_guid'], - 'guid_sig' => $x[0]['xchan_guid_sig'], - 'link' => array( - array('rel' => 'alternate', 'type' => 'text/html', 'href' => $x[0]['xchan_url']), - array('rel' => 'photo', 'type' => $x[0]['xchan_photo_mimetype'], 'href' => $x[0]['xchan_photo_m'])), - ), - )); + $y = [ + 'type' => 'Event', + 'id' => z_root() . '/event/' . $event['event_hash'], + 'name' => $arr['summary'], +// 'summary' => bbcode($arr['summary']), + // RFC3339 Section 4.3 + 'startTime' => (($arr['adjust']) ? datetime_convert('UTC', 'UTC', $arr['dtstart'], ATOM_TIME) : datetime_convert('UTC', 'UTC', $arr['dtstart'], 'Y-m-d\\TH:i:s-00:00')), + 'content' => bbcode($arr['description']), + 'location' => [ 'type' => 'Place', 'name' => bbcode($arr['location']) ], + 'source' => [ 'content' => format_event_bbcode($arr), 'mediaType' => 'text/x-multicode' ], + 'url' => [ [ 'mediaType' => 'text/calendar', 'href' => z_root() . '/events/ical/' . $event['event_hash'] ] ], + 'actor' => Activity::encode_person($z, false), + 'attachment' => Activity::encode_attachment($item_arr), + 'tag' => Activity::encode_taxonomy($item_arr) + ]; + + if (! $arr['nofinish']) { + $y['endTime'] = (($arr['adjust']) ? datetime_convert('UTC', 'UTC', $arr['dtend'], ATOM_TIME) : datetime_convert('UTC', 'UTC', $arr['dtend'], 'Y-m-d\\TH:i:s-00:00')); + } + if ($arr['event_repeat']) { + $y['eventRepeat'] = $arr['event_repeat']; + } + + $item_arr['obj'] = json_encode($y); } // propagate the event resource_id so that posts containing it are easily searchable in downstream copies diff --git a/include/feedutils.php b/include/feedutils.php index 1c653325d..734018922 100644 --- a/include/feedutils.php +++ b/include/feedutils.php @@ -194,14 +194,14 @@ function construct_activity_object($item) { $r = json_decode($item['obj'],false); if(! $r) - return ''; - if($r->type) + return EMPTY_STR; + if(isset($r->type)) $o .= '<as:obj_type>' . xmlify($r->type) . '</as:obj_type>' . "\r\n"; - if($r->id) + if(isset($r->id)) $o .= '<id>' . xmlify($r->id) . '</id>' . "\r\n"; - if($r->title) + if(isset($r->title)) $o .= '<title>' . xmlify($r->title) . '</title>' . "\r\n"; - if($r->links) { + if(isset($r->links)) { /** @FIXME!! */ if(substr($r->link,0,1) === '<') { $r->link = preg_replace('/\<link(.*?)\"\>/','<link$1"/>',$r->link); @@ -210,7 +210,7 @@ function construct_activity_object($item) { else $o .= '<link rel="alternate" type="text/html" href="' . xmlify($r->link) . '" />' . "\r\n"; } - if($r->content) { + if(isset($r->content)) { $o .= '<content type="html" >' . xmlify(bbcode($r->content)) . '</content>' . "\r\n"; } $o .= '</as:object>' . "\r\n"; @@ -218,7 +218,7 @@ function construct_activity_object($item) { return $o; } - return ''; + return EMPTY_STR; } function construct_activity_target($item) { @@ -1060,6 +1060,8 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { return; } + + $sys_expire = intval(get_config('system', 'default_expire_days')); $chn_expire = intval($importer['channel_expire_days']); @@ -1353,7 +1355,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { } } - if(! post_is_importable($datarray, $contact)) + if(! post_is_importable($importer['channel_id'], $datarray, [$contact])) continue; $datarray['parent_mid'] = $datarray['mid']; @@ -1509,7 +1511,7 @@ function consume_feed($xml, $importer, &$contact, $pass = 0) { } } - if(! post_is_importable($datarray, $contact)) + if(! post_is_importable($importer['channel_id'], $datarray, [$contact])) continue; logger('author: ' . print_r($author, true), LOGGER_DEBUG); diff --git a/include/html2bbcode.php b/include/html2bbcode.php index 173ea63bd..cc67a5666 100644 --- a/include/html2bbcode.php +++ b/include/html2bbcode.php @@ -87,7 +87,7 @@ function deletenode(&$doc, $node) function html2bbcode($message) { - if(!$message) + if(!is_string($message) && !$message) return; $message = str_replace("\r", "", $message); diff --git a/include/items.php b/include/items.php index 0b33d876d..8a2faa623 100644 --- a/include/items.php +++ b/include/items.php @@ -10,6 +10,7 @@ use Zotlabs\Lib\MarkdownSoap; use Zotlabs\Lib\MessageFilter; use Zotlabs\Lib\ThreadListener; use Zotlabs\Lib\IConfig; +use Zotlabs\Lib\PConfig; use Zotlabs\Lib\Activity; use Zotlabs\Lib\Libsync; use Zotlabs\Lib\Libzot; @@ -1072,21 +1073,6 @@ function encode_item($item,$mirror = false,$zap_compat = false) { $x['type'] = 'activity'; $x['encoding'] = 'zot'; - $r = q("select channel_id from channel where channel_id = %d limit 1", - intval($item['uid']) - ); - - if($r) - $comment_scope = PermissionLimits::Get($item['uid'],'post_comments'); - else - $comment_scope = 0; - - $scope = $item['public_policy']; - if(! $scope) - $scope = 'public'; - - $c_scope = map_scope($comment_scope); - $key = get_config('system','prvkey'); // If we're trying to backup an item so that it's recoverable or for export/imprt, @@ -1179,10 +1165,7 @@ function encode_item($item,$mirror = false,$zap_compat = false) { $x['public_scope'] = $scope; - if($item['item_nocomment']) - $x['comment_scope'] = 'none'; - else - $x['comment_scope'] = $c_scope; + $x['comment_scope'] = $item['comment_policy']; if(! empty($item['term'])) $x['tags'] = encode_item_terms($item['term'],$mirror); @@ -2218,9 +2201,9 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) { $arr['deny_gid'] = ((array_key_exists('deny_gid',$arr)) ? trim($arr['deny_gid']) : $orig[0]['deny_gid']); $arr['item_private'] = ((array_key_exists('item_private',$arr)) ? intval($arr['item_private']) : $orig[0]['item_private']); - $arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : ''); - $arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : ''); - $arr['html'] = ((array_key_exists('html',$arr) && strlen($arr['html'])) ? trim($arr['html']) : ''); + $arr['title'] = ((array_key_exists('title',$arr) && $arr['title']) ? trim($arr['title']) : ''); + $arr['body'] = ((array_key_exists('body',$arr) && $arr['body']) ? trim($arr['body']) : ''); + $arr['html'] = ((array_key_exists('html',$arr) && $arr['html']) ? trim($arr['html']) : ''); $arr['attach'] = ((array_key_exists('attach',$arr)) ? notags(trim($arr['attach'])) : $orig[0]['attach']); $arr['app'] = ((array_key_exists('app',$arr)) ? notags(trim($arr['app'])) : $orig[0]['app']); @@ -3495,24 +3478,57 @@ function check_item_source($uid, $item) { return false; } -function post_is_importable($item,$abook) { - if(! $abook) - return true; +// Checks an incoming item against the per-channel and per-connection content filter. +// This implements the backend of the 'Content Filter' system app - if(($abook['abook_channel']) && (! feature_enabled($abook['abook_channel'],'connfilter'))) - return true; +function post_is_importable($channel_id, $item, $abook) { - if(! $item) + if (! $item) { return false; + } - if(! ($abook['abook_incl'] || $abook['abook_excl'])) + $incl = PConfig::get($channel_id, 'system', 'message_filter_incl', EMPTY_STR); + $excl = PConfig::get($channel_id, 'system', 'message_filter_excl', EMPTY_STR); + + if ($incl || $excl) { + $x = MessageFilter::evaluate($item, $incl, $excl); + if (! $x) { + logger('MessageFilter: channel blocked content', LOGGER_DEBUG, LOG_INFO); + return false; + } + } + + if(!feature_enabled($channel_id, 'connfilter')) { return true; + } - return MessageFilter::evaluate($item,$abook['abook_incl'],$abook['abook_excl']); + if (! $abook) { + return true; + } + foreach ($abook as $ab) { + // check eligibility + if (intval($ab['abook_self'])) { + continue; + } + if (! ($ab['abook_incl'] || $ab['abook_excl'])) { + continue; + } + + $evaluator = MessageFilter::evaluate($item, $ab['abook_incl'], $ab['abook_excl']); + // A negative assessment for any individual connections + // is an instant fail + if (! $evaluator) { + logger('MessageFilter: connection blocked content', LOGGER_DEBUG, LOG_INFO); + return false; + } + } + + return true; } + function fix_private_photos($s, $uid, $item = null, $cid = 0) { logger('fix_private_photos', LOGGER_DEBUG); diff --git a/include/language.php b/include/language.php index d291deb63..23aff0a02 100644 --- a/include/language.php +++ b/include/language.php @@ -311,6 +311,11 @@ function string_plural_select_default($n) { * @return string Language code in 2-letter ISO 639-1 (en, de, fr) format */ function detect_language($s) { + + if (!$s) { + return EMPTY_STR; + } + $min_length = get_config('system', 'language_detect_min_length'); if ($min_length === false) $min_length = LANGUAGE_DETECT_MIN_LENGTH; diff --git a/include/nav.php b/include/nav.php index 9278c1587..b9b24e34c 100644 --- a/include/nav.php +++ b/include/nav.php @@ -118,11 +118,11 @@ function nav($template = 'default') { else { if (!get_account_id()) { if (App::$module === 'channel') { - $nav['login'] = login(true, 'main-login', false, false); + $nav['login'] = login(true, 'modal_login', false, false); $nav['loginmenu'][] = ['login', t('Login'), '', t('Sign in'), '']; } else { - $nav['login'] = login(true, 'main-login', false, false); + $nav['login'] = login(true, 'modal_login', false, false); $nav['loginmenu'][] = ['login', t('Login'), '', t('Sign in'), 'login_nav_btn']; App::$page['content'] .= replace_macros(get_markup_template('nav_login.tpl'), diff --git a/include/network.php b/include/network.php index 64605749d..a236a6f8e 100644 --- a/include/network.php +++ b/include/network.php @@ -365,9 +365,14 @@ function z_post_url($url, $params, $redirects = 0, $opts = array()) { if($http_code == 301 || $http_code == 302 || $http_code == 303 || $http_code == 307 || $http_code == 308) { $matches = array(); preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches); - $newurl = trim(array_pop($matches)); - if(strpos($newurl,'/') === 0) + + $newurl = ''; + if (array_pop($matches)) + $newurl = trim(array_pop($matches)); + + if($newurl && strpos($newurl,'/') === 0) $newurl = $url . $newurl; + $url_parsed = @parse_url($newurl); if (isset($url_parsed)) { curl_close($ch); @@ -554,6 +559,14 @@ function z_dns_check($h,$check_mx = 0) { return((@dns_get_record($h,$opts) || filter_var($h, FILTER_VALIDATE_IP)) ? true : false); } +function is_local_url($url) { + if (str_starts_with($url, z_root()) || str_starts_with($url, '/')) { + return true; + } + + return false; +} + /** * @brief Validates a given URL. * @@ -1986,6 +1999,10 @@ function getBestSupportedMimeType($mimeTypes = null, $acceptedTypes = false) { if($acceptedTypes === false) $acceptedTypes = $_SERVER['HTTP_ACCEPT']; + if (!$acceptedTypes) { + return null; + } + // Accept header is case insensitive, and whitespace isn’t important $accept = strtolower(str_replace(' ', '', $acceptedTypes)); // divide it into parts in the place of a "," diff --git a/include/oembed.php b/include/oembed.php index 9a25686fa..36938c577 100644 --- a/include/oembed.php +++ b/include/oembed.php @@ -134,6 +134,7 @@ function oembed_fetch_url($embedurl){ } $txt = null; + $j = null; // we should try to cache this and avoid a lookup on each render $is_matrix = is_matrix_url($embedurl); @@ -160,7 +161,7 @@ function oembed_fetch_url($embedurl){ if(is_null($txt)) { - $txt = ""; + $txt = EMPTY_STR; if ($action !== 'block') { // try oembed autodiscovery @@ -168,7 +169,7 @@ function oembed_fetch_url($embedurl){ $result = z_fetch_url($furl, false, $redirects, [ 'timeout' => 30, - 'accept_content' => "text/*", + 'accept_content' => 'text/*', 'novalidate' => true, 'session' => ((local_channel() && $zrl) ? true : false) ] @@ -227,9 +228,10 @@ function oembed_fetch_url($embedurl){ $txt = $x['embed']; } - $txt=trim($txt); + $txt = trim($txt); - if ($txt[0]!="{") $txt='{"type":"error"}'; + if (substr($txt, 0, 1) !== '{') + $txt = '{"type":"error"}'; // save in cache @@ -247,7 +249,7 @@ function oembed_fetch_url($embedurl){ } if($action === 'filter') { - if($j['html']) { + if(isset($j['html']) && $j['html']) { $orig = $j['html']; $allow_position = (($is_matrix) ? true : false); diff --git a/include/plugin.php b/include/plugin.php index 95c9882d0..f9cee7ed6 100644 --- a/include/plugin.php +++ b/include/plugin.php @@ -794,6 +794,79 @@ function get_theme_info($theme){ } /** + * @brief Parse template comment in search of template info. + * + * like + * \code + * * Name: MyWidget + * * Description: A widget + * * Version: 1.2.3 + * * Author: John <profile url> + * * Author: Jane <email> + * * ContentRegionID: some_id + * * ContentRegionID: some_other_id + * * + *\endcode + * @param string $widget the name of the widget + * @return array with the information + */ +function get_template_info($template){ + $m = array(); + $info = array( + 'name' => $template, + 'description' => '', + 'author' => array(), + 'maintainer' => array(), + 'version' => '', + 'content_regions' => [] + ); + + $checkpaths = [ + "view/php/$template.php", + ]; + + $template_found = false; + + foreach ($checkpaths as $path) { + if (is_file($path)) { + $template_found = true; + $f = file_get_contents($path); + break; + } + } + + if(! ($template_found && $f)) + return $info; + + $f = escape_tags($f); + $r = preg_match("|/\*.*\*/|msU", $f, $m); + + if ($r) { + $ll = explode("\n", $m[0]); + foreach( $ll as $l ) { + $l = trim($l, "\t\n\r */"); + if ($l != ""){ + list($k, $v) = array_map("trim", explode(":", $l, 2)); + $k = strtolower($k); + if ($k == 'author' || $k == 'maintainer'){ + $r = preg_match("|([^<]+)<([^>]+)>|", $v, $m); + if ($r) { + $info[$k][] = array('name' => $m[1], 'link' => $m[2]); + } else { + $info[$k][] = array('name' => $v); + } + } + else { + $info[$k] = $v; + } + } + } + } + + return $info; +} + +/** * @brief Returns the theme's screenshot. * * The screenshot is expected as view/theme/$theme/img/screenshot.[png|jpg]. @@ -868,9 +941,7 @@ function head_get_links() { function format_css_if_exists($source) { - // script_path() returns https://yoursite.tld - - $path_prefix = script_path(); + $path_prefix = z_root(); $script = $source[0]; @@ -892,44 +963,6 @@ function format_css_if_exists($source) { } } -/** - * This basically calculates the baseurl. We have other functions to do that, but - * there was an issue with script paths and mixed-content whose details are arcane - * and perhaps lost in the message archives. The short answer is that we're ignoring - * the URL which we are "supposed" to use, and generating script paths relative to - * the URL which we are currently using; in order to ensure they are found and aren't - * blocked due to mixed content issues. - * - * @return string - */ -function script_path() { - if(x($_SERVER,'HTTPS') && $_SERVER['HTTPS']) - $scheme = 'https'; - elseif(x($_SERVER,'SERVER_PORT') && (intval($_SERVER['SERVER_PORT']) == 443)) - $scheme = 'https'; - elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') - $scheme = 'https'; - else - $scheme = 'http'; - - // Some proxy setups may require using http_host - - if(isset(App::$config['system']['script_path_use_http_host']) && intval(App::$config['system']['script_path_use_http_host'])) - $server_var = 'HTTP_HOST'; - else - $server_var = 'SERVER_NAME'; - - - if(x($_SERVER,$server_var)) { - $hostname = $_SERVER[$server_var]; - } - else { - return z_root(); - } - - return $scheme . '://' . $hostname; -} - function head_add_js($src, $priority = 0) { if(isset(App::$js_sources[$priority]) && !is_array(App::$js_sources[$priority])) App::$js_sources[$priority] = []; @@ -981,7 +1014,7 @@ function head_get_main_js() { } function format_js_if_exists($source) { - $path_prefix = script_path(); + $path_prefix = z_root(); if(strpos($source,'/') !== false) { // The source is a known path on the system diff --git a/include/text.php b/include/text.php index 29a2ab3b1..0c806d009 100644 --- a/include/text.php +++ b/include/text.php @@ -108,9 +108,24 @@ function notags($string) { * @return string */ function escape_tags($string) { - return(htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false)); + if (!$string) { + return EMPTY_STR; + } + return (htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false)); } +/** + * Escape URL's so they're safe for use in HTML and in HTML element attributes. + */ +function escape_url($input) { + if (empty($input)) { + return EMPTY_STR; + } + + // This is a bit crude but seems to do the trick for now. It makes no + // guarantees that the URL is valid for use after escaping. + return htmlspecialchars($input, ENT_HTML5 | ENT_QUOTES); +} function z_input_filter($s,$type = 'text/bbcode',$allow_code = false) { @@ -3531,7 +3546,7 @@ function text_highlight($s, $lang) { // echo (($xml->asXML('data.xml')) ? 'Your XML file has been generated successfully!' : 'Error generating XML file!'); function arrtoxml($root_elem,$arr) { - $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><' . $root_elem . '></' . $root_elem . '>', null, false); + $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><' . $root_elem . '></' . $root_elem . '>', 0, false); array2XML($xml,$arr); return $xml->asXML(); @@ -4054,9 +4069,10 @@ function sanitize_text_field($str) { */ function substr_words($str, $max_length, $suffix = '...') { + $ret = ''; + if (strlen($str) > $max_length) { $words = preg_split('/\s/', $str); - $ret = ''; $i = 0; while (true) { $length = (strlen($ret) + strlen($words[$i])); diff --git a/include/zid.php b/include/zid.php index ae7d9e252..5710d9f3f 100644 --- a/include/zid.php +++ b/include/zid.php @@ -58,6 +58,8 @@ function zid($s, $address = '') { $mine_parsed = parse_url($mine); $s_parsed = parse_url($s); + + $url_match = false; if(isset($mine_parsed['host']) && isset($s_parsed['host']) && $mine_parsed['host'] === $s_parsed['host']) $url_match = true; |