diff --git a/config/dbstructure.php b/config/dbstructure.php index 96f90fb82..99e3de9d0 100644 --- a/config/dbstructure.php +++ b/config/dbstructure.php @@ -34,7 +34,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1289); + define('DB_UPDATE_VERSION', 1290); } return [ @@ -1368,7 +1368,10 @@ return [ "pid" => ["pid"], "parameter" => ["parameter(64)"], "priority_created_next_try" => ["priority", "created", "next_try"], - "done_executed_next_try" => ["done", "executed", "next_try"] + "done_priority_executed_next_try" => ["done", "priority", "executed", "next_try"], + "done_executed_next_try" => ["done", "executed", "next_try"], + "done_priority_next_try" => ["done", "priority", "next_try"], + "done_next_try" => ["done", "next_try"] ] ] ]; diff --git a/include/api.php b/include/api.php index 0f7fa85bd..5bfb2d65a 100644 --- a/include/api.php +++ b/include/api.php @@ -43,6 +43,7 @@ use Friendica\Protocol\Diaspora; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; use Friendica\Util\XML; require_once 'include/conversation.php'; @@ -526,7 +527,7 @@ function api_get_user(App $a, $contact_id = null) // Searching for contact URL if (!is_null($contact_id) && (intval($contact_id) == 0)) { - $user = DBA::escape(normalise_link($contact_id)); + $user = DBA::escape(Strings::normaliseLink($contact_id)); $url = $user; $extra_query = "AND `contact`.`nurl` = '%s' "; if (api_user() !== false) { @@ -571,7 +572,7 @@ function api_get_user(App $a, $contact_id = null) } if (is_null($user) && x($_GET, 'profileurl')) { - $user = DBA::escape(normalise_link($_GET['profileurl'])); + $user = DBA::escape(Strings::normaliseLink($_GET['profileurl'])); $extra_query = "AND `contact`.`nurl` = '%s' "; if (api_user() !== false) { $extra_query .= "AND `contact`.`uid`=".intval(api_user()); @@ -639,7 +640,7 @@ function api_get_user(App $a, $contact_id = null) throw new BadRequestException("User not found."); } - $contact = DBA::selectFirst('contact', [], ['uid' => 0, 'nurl' => normalise_link($url)]); + $contact = DBA::selectFirst('contact', [], ['uid' => 0, 'nurl' => Strings::normaliseLink($url)]); if (DBA::isResult($contact)) { $network_name = ContactSelector::networkToName($contact['network'], $contact['url']); @@ -2662,7 +2663,7 @@ function api_get_entitities(&$text, $bbcode) "id" => $start+1, "id_str" => (string)$start+1, "indices" => [$start, $start+strlen($url)], - "media_url" => normalise_link($media_url), + "media_url" => Strings::normaliseLink($media_url), "media_url_https" => $media_url, "url" => $url, "display_url" => $display_url, @@ -3665,8 +3666,8 @@ function api_friendships_destroy($type) $url = $contact["url"]; $condition = ["`uid` = ? AND (`rel` = ? OR `rel` = ?) AND (`nurl` = ? OR `alias` = ? OR `alias` = ?)", - $uid, Contact::SHARING, Contact::FRIEND, normalise_link($url), - normalise_link($url), $url]; + $uid, Contact::SHARING, Contact::FRIEND, Strings::normaliseLink($url), + Strings::normaliseLink($url), $url]; $contact = DBA::selectFirst('contact', [], $condition); if (!DBA::isResult($contact)) { @@ -3790,9 +3791,9 @@ function api_direct_messages_box($type, $box, $verbose) foreach ($r as $item) { if ($box == "inbox" || $item['from-url'] != $profile_url) { $recipient = $user_info; - $sender = api_get_user($a, normalise_link($item['contact-url'])); + $sender = api_get_user($a, Strings::normaliseLink($item['contact-url'])); } elseif ($box == "sentbox" || $item['from-url'] == $profile_url) { - $recipient = api_get_user($a, normalise_link($item['contact-url'])); + $recipient = api_get_user($a, Strings::normaliseLink($item['contact-url'])); $sender = $user_info; } @@ -4499,7 +4500,7 @@ function save_media_to_database($mediatype, $media, $type, $album, $allow_cid, $ // check against max upload size within Friendica instance $maximagesize = Config::get('system', 'maximagesize'); if ($maximagesize && ($filesize > $maximagesize)) { - $formattedBytes = formatBytes($maximagesize); + $formattedBytes = Strings::formatBytes($maximagesize); throw new InternalServerErrorException("image size exceeds Friendica config setting (uploaded size: $formattedBytes)"); } @@ -4779,7 +4780,7 @@ function api_friendica_remoteauth() throw new BadRequestException("Wrong parameters."); } - $c_url = normalise_link($c_url); + $c_url = Strings::normaliseLink($c_url); // traditional DFRN @@ -4802,7 +4803,7 @@ function api_friendica_remoteauth() $dfrn_id = '0:' . $orig_id; } - $sec = random_string(); + $sec = Strings::getRandomHex(); $fields = ['uid' => api_user(), 'cid' => $cid, 'dfrn_id' => $dfrn_id, 'sec' => $sec, 'expire' => time() + 45]; @@ -4943,7 +4944,7 @@ function api_get_nick($profile) $r = q( "SELECT `nick` FROM `contact` WHERE `uid` = 0 AND `nurl` = '%s'", - DBA::escape(normalise_link($profile)) + DBA::escape(Strings::normaliseLink($profile)) ); if (DBA::isResult($r)) { @@ -4953,7 +4954,7 @@ function api_get_nick($profile) if (!$nick == "") { $r = q( "SELECT `nick` FROM `contact` WHERE `uid` = 0 AND `nurl` = '%s'", - DBA::escape(normalise_link($profile)) + DBA::escape(Strings::normaliseLink($profile)) ); if (DBA::isResult($r)) { @@ -5836,9 +5837,9 @@ function api_friendica_direct_messages_search($type, $box = "") foreach ($r as $item) { if ($box == "inbox" || $item['from-url'] != $profile_url) { $recipient = $user_info; - $sender = api_get_user($a, normalise_link($item['contact-url'])); + $sender = api_get_user($a, Strings::normaliseLink($item['contact-url'])); } elseif ($box == "sentbox" || $item['from-url'] == $profile_url) { - $recipient = api_get_user($a, normalise_link($item['contact-url'])); + $recipient = api_get_user($a, Strings::normaliseLink($item['contact-url'])); $sender = $user_info; } diff --git a/include/conversation.php b/include/conversation.php index cd635521e..ee286ca98 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -26,6 +26,7 @@ use Friendica\Object\Thread; use Friendica\Util\DateTimeFormat; use Friendica\Util\Proxy as ProxyUtils; use Friendica\Util\Temporal; +use Friendica\Util\Strings; use Friendica\Util\XML; use Friendica\Util\Crypto; @@ -482,7 +483,7 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ if (!$update) { $tab = 'posts'; if (x($_GET, 'tab')) { - $tab = notags(trim($_GET['tab'])); + $tab = Strings::escapeTags(trim($_GET['tab'])); } if ($tab === 'posts') { /* @@ -638,7 +639,7 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ $lock = false; $likebuttons = false; - $body = prepare_body($item, true, $preview); + $body = Item::prepareBody($item, true, $preview); list($categories, $folders) = get_cats_and_terms($item); @@ -689,7 +690,7 @@ function conversation(App $a, array $items, Pager $pager, $mode, $update, $previ 'owner_name' => $owner_name_e, 'owner_url' => $owner_url, 'owner_photo' => System::removedBaseUrl(ProxyUtils::proxifyUrl($item['owner-avatar'], false, ProxyUtils::SIZE_THUMB)), - 'plink' => get_plink($item), + 'plink' => Item::getPlink($item), 'edpost' => false, 'isstarred' => $isstarred, 'star' => $star, @@ -842,7 +843,7 @@ function item_photo_menu($item) { $cid = 0; $network = ''; $rel = 0; - $condition = ['uid' => local_user(), 'nurl' => normalise_link($item['author-link'])]; + $condition = ['uid' => local_user(), 'nurl' => Strings::normaliseLink($item['author-link'])]; $contact = DBA::selectFirst('contact', ['id', 'network', 'rel'], $condition); if (DBA::isResult($contact)) { $cid = $contact['id']; diff --git a/include/enotify.php b/include/enotify.php index 339e31a3c..a4b0fd14b 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -15,6 +15,7 @@ use Friendica\Model\Contact; use Friendica\Model\Item; use Friendica\Util\DateTimeFormat; use Friendica\Util\Emailer; +use Friendica\Util\Strings; /** * @brief Creates a notification entry and possibly sends a mail @@ -157,7 +158,7 @@ function notification($params) $item = Item::selectFirstForUser($params['uid'], Item::ITEM_FIELDLIST, ['id' => $parent_id]); } - $item_post_type = item_post_type($item); + $item_post_type = Item::postType($item); $itemlink = $item['plink']; // "a post" @@ -457,7 +458,7 @@ function notification($params) Logger::log("adding notification entry", Logger::DEBUG); do { $dups = false; - $hash = random_string(); + $hash = Strings::getRandomHex(); if (DBA::exists('notify', ['hash' => $hash])) { $dups = true; } @@ -703,11 +704,11 @@ function check_item_notification($itemid, $uid, $defaulttype = "") { // Check for invalid profile urls. 13 should be the shortest possible profile length: // http://a.bc/d // Additionally check for invalid urls that would return the normalised value "http:" - if ((strlen($profile) >= 13) && (normalise_link($profile) != "http:")) { + if ((strlen($profile) >= 13) && (Strings::normaliseLink($profile) != "http:")) { if (!in_array($profile, $profiles2)) $profiles2[] = $profile; - $profile = normalise_link($profile); + $profile = Strings::normaliseLink($profile); if (!in_array($profile, $profiles2)) $profiles2[] = $profile; @@ -761,7 +762,7 @@ function check_item_notification($itemid, $uid, $defaulttype = "") { if (DBA::isResult($tags)) { foreach ($tags AS $tag) { - $condition = ['nurl' => normalise_link($tag["url"]), 'uid' => $uid, 'notify_new_posts' => true]; + $condition = ['nurl' => Strings::normaliseLink($tag["url"]), 'uid' => $uid, 'notify_new_posts' => true]; $r = DBA::exists('contact', $condition); if ($r) { $send_notification = true; diff --git a/include/items.php b/include/items.php index 9929f535f..adc5bf013 100644 --- a/include/items.php +++ b/include/items.php @@ -21,6 +21,7 @@ use Friendica\Protocol\OStatus; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\ParseUrl; +use Friendica\Util\Strings; use Friendica\Util\Temporal; require_once 'include/text.php'; @@ -308,7 +309,7 @@ function subscribe_to_hub($url, array $importer, array $contact, $hubmode = 'sub $push_url = System::baseUrl() . '/pubsub/' . $user['nickname'] . '/' . $contact['id']; // Use a single verify token, even if multiple hubs - $verify_token = ((strlen($contact['hub-verify'])) ? $contact['hub-verify'] : random_string()); + $verify_token = ((strlen($contact['hub-verify'])) ? $contact['hub-verify'] : Strings::getRandomHex()); $params= 'hub.mode=' . $hubmode . '&hub.callback=' . urlencode($push_url) . '&hub.topic=' . urlencode($contact['poll']) . '&hub.verify=async&hub.verify_token=' . $verify_token; diff --git a/include/text.php b/include/text.php index d2e3d0c9f..ee83345c0 100644 --- a/include/text.php +++ b/include/text.php @@ -26,144 +26,12 @@ use Friendica\Util\Proxy as ProxyUtils; use Friendica\Core\Logger; use Friendica\Core\Renderer; use Friendica\Model\FileTag; +use Friendica\Util\Strings; use Friendica\Util\XML; use Friendica\Content\Text\HTML; require_once "include/conversation.php"; -/** - * @brief Generates a pseudo-random string of hexadecimal characters - * - * @param int $size - * @return string - */ -function random_string($size = 64) -{ - $byte_size = ceil($size / 2); - - $bytes = random_bytes($byte_size); - - $return = substr(bin2hex($bytes), 0, $size); - - return $return; -} - -/** - * This is our primary input filter. - * - * The high bit hack only involved some old IE browser, forget which (IE5/Mac?) - * that had an XSS attack vector due to stripping the high-bit on an 8-bit character - * after cleansing, and angle chars with the high bit set could get through as markup. - * - * This is now disabled because it was interfering with some legitimate unicode sequences - * and hopefully there aren't a lot of those browsers left. - * - * Use this on any text input where angle chars are not valid or permitted - * They will be replaced with safer brackets. This may be filtered further - * if these are not allowed either. - * - * @param string $string Input string - * @return string Filtered string - */ -function notags($string) { - return str_replace(["<", ">"], ['[', ']'], $string); - -// High-bit filter no longer used -// return str_replace(array("<",">","\xBA","\xBC","\xBE"), array('[',']','','',''), $string); -} - - -/** - * use this on "body" or "content" input where angle chars shouldn't be removed, - * and allow them to be safely displayed. - * @param string $string - * @return string - */ -function escape_tags($string) { - return htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false); -} - - -/** - * generate a string that's random, but usually pronounceable. - * used to generate initial passwords - * @param int $len - * @return string - */ -function autoname($len) { - - if ($len <= 0) { - return ''; - } - - $vowels = ['a','a','ai','au','e','e','e','ee','ea','i','ie','o','ou','u']; - if (mt_rand(0, 5) == 4) { - $vowels[] = 'y'; - } - - $cons = [ - 'b','bl','br', - 'c','ch','cl','cr', - 'd','dr', - 'f','fl','fr', - 'g','gh','gl','gr', - 'h', - 'j', - 'k','kh','kl','kr', - 'l', - 'm', - 'n', - 'p','ph','pl','pr', - 'qu', - 'r','rh', - 's','sc','sh','sm','sp','st', - 't','th','tr', - 'v', - 'w','wh', - 'x', - 'z','zh' - ]; - - $midcons = ['ck','ct','gn','ld','lf','lm','lt','mb','mm', 'mn','mp', - 'nd','ng','nk','nt','rn','rp','rt']; - - $noend = ['bl', 'br', 'cl','cr','dr','fl','fr','gl','gr', - 'kh', 'kl','kr','mn','pl','pr','rh','tr','qu','wh','q']; - - $start = mt_rand(0,2); - if ($start == 0) { - $table = $vowels; - } else { - $table = $cons; - } - - $word = ''; - - for ($x = 0; $x < $len; $x ++) { - $r = mt_rand(0,count($table) - 1); - $word .= $table[$r]; - - if ($table == $vowels) { - $table = array_merge($cons,$midcons); - } else { - $table = $vowels; - } - - } - - $word = substr($word,0,$len); - - foreach ($noend as $noe) { - $noelen = strlen($noe); - if ((strlen($word) > $noelen) && (substr($word, -$noelen) == $noe)) { - $word = autoname($len); - break; - } - } - - return $word; -} - /** * Turn user/group ACLs stored as angle bracketed text into arrays * @@ -194,7 +62,7 @@ function expand_acl($s) { */ function sanitise_acl(&$item) { if (intval($item)) { - $item = '<' . intval(notags(trim($item))) . '>'; + $item = '<' . intval(Strings::escapeTags(trim($item))) . '>'; } else { unset($item); } @@ -255,78 +123,6 @@ function activity_match($haystack,$needle) { return (($haystack === $needle) || ((basename($needle) === $haystack) && strstr($needle, NAMESPACE_ACTIVITY_SCHEMA))); } - -/** - * @brief Pull out all #hashtags and @person tags from $string. - * - * We also get @person@domain.com - which would make - * the regex quite complicated as tags can also - * end a sentence. So we'll run through our results - * and strip the period from any tags which end with one. - * Returns array of tags found, or empty array. - * - * @param string $string Post content - * @return array List of tag and person names - */ -function get_tags($string) { - $ret = []; - - // Convert hashtag links to hashtags - $string = preg_replace('/#\[url\=([^\[\]]*)\](.*?)\[\/url\]/ism', '#$2', $string); - - // ignore anything in a code block - $string = preg_replace('/\[code\](.*?)\[\/code\]/sm', '', $string); - - // Force line feeds at bbtags - $string = str_replace(['[', ']'], ["\n[", "]\n"], $string); - - // ignore anything in a bbtag - $string = preg_replace('/\[(.*?)\]/sm', '', $string); - - // Match full names against @tags including the space between first and last - // We will look these up afterward to see if they are full names or not recognisable. - - if (preg_match_all('/(@[^ \x0D\x0A,:?]+ [^ \x0D\x0A@,:?]+)([ \x0D\x0A@,:?]|$)/', $string, $matches)) { - foreach ($matches[1] as $match) { - if (strstr($match, ']')) { - // we might be inside a bbcode color tag - leave it alone - continue; - } - if (substr($match, -1, 1) === '.') { - $ret[] = substr($match, 0, -1); - } else { - $ret[] = $match; - } - } - } - - // Otherwise pull out single word tags. These can be @nickname, @first_last - // and #hash tags. - - if (preg_match_all('/([!#@][^\^ \x0D\x0A,;:?]+)([ \x0D\x0A,;:?]|$)/', $string, $matches)) { - foreach ($matches[1] as $match) { - if (strstr($match, ']')) { - // we might be inside a bbcode color tag - leave it alone - continue; - } - if (substr($match, -1, 1) === '.') { - $match = substr($match,0,-1); - } - // ignore strictly numeric tags like #1 - if ((strpos($match, '#') === 0) && ctype_digit(substr($match, 1))) { - continue; - } - // try not to catch url fragments - if (strpos($string, $match) && preg_match('/[a-zA-z0-9\/]/', substr($string, strpos($string, $match) - 1, 1))) { - continue; - } - $ret[] = $match; - } - } - return $ret; -} - - /** * quick and dirty quoted_printable encoding * @@ -337,45 +133,6 @@ function qp($s) { return str_replace("%", "=", rawurlencode($s)); } -/** - * @brief Check for a valid email string - * - * @param string $email_address - * @return boolean - */ -function valid_email($email_address) -{ - return preg_match('/^[_a-zA-Z0-9\-\+]+(\.[_a-zA-Z0-9\-\+]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+$/', $email_address); -} - -/** - * Normalize url - * - * @param string $url - * @return string - */ -function normalise_link($url) { - $ret = str_replace(['https:', '//www.'], ['http:', '//'], $url); - return rtrim($ret,'/'); -} - - -/** - * Compare two URLs to see if they are the same, but ignore - * slight but hopefully insignificant differences such as if one - * is https and the other isn't, or if one is www.something and - * the other isn't - and also ignore case differences. - * - * @param string $a first url - * @param string $b second url - * @return boolean True if the URLs match, otherwise False - * - */ -function link_compare($a, $b) { - return (strcasecmp(normalise_link($a), normalise_link($b)) === 0); -} - - /** * @brief Find any non-embedded images in private items and add redir links to them * @@ -400,236 +157,6 @@ function redir_private_images($a, &$item) } } -/** - * Sets the "rendered-html" field of the provided item - * - * Body is preserved to avoid side-effects as we modify it just-in-time for spoilers and private image links - * - * @param array $item - * @param bool $update - * - * @todo Remove reference, simply return "rendered-html" and "rendered-hash" - */ -function put_item_in_cache(&$item, $update = false) -{ - $body = $item["body"]; - - $rendered_hash = defaults($item, 'rendered-hash', ''); - $rendered_html = defaults($item, 'rendered-html', ''); - - if ($rendered_hash == '' - || $rendered_html == "" - || $rendered_hash != hash("md5", $item["body"]) - || Config::get("system", "ignore_cache") - ) { - $a = get_app(); - redir_private_images($a, $item); - - $item["rendered-html"] = prepare_text($item["body"]); - $item["rendered-hash"] = hash("md5", $item["body"]); - - $hook_data = ['item' => $item, 'rendered-html' => $item['rendered-html'], 'rendered-hash' => $item['rendered-hash']]; - Addon::callHooks('put_item_in_cache', $hook_data); - $item['rendered-html'] = $hook_data['rendered-html']; - $item['rendered-hash'] = $hook_data['rendered-hash']; - unset($hook_data); - - // Force an update if the generated values differ from the existing ones - if ($rendered_hash != $item["rendered-hash"]) { - $update = true; - } - - // Only compare the HTML when we forcefully ignore the cache - if (Config::get("system", "ignore_cache") && ($rendered_html != $item["rendered-html"])) { - $update = true; - } - - if ($update && !empty($item["id"])) { - Item::update(['rendered-html' => $item["rendered-html"], 'rendered-hash' => $item["rendered-hash"]], - ['id' => $item["id"]]); - } - } - - $item["body"] = $body; -} - -/** - * @brief Given an item array, convert the body element from bbcode to html and add smilie icons. - * If attach is true, also add icons for item attachments. - * - * @param array $item - * @param boolean $attach - * @param boolean $is_preview - * @return string item body html - * @hook prepare_body_init item array before any work - * @hook prepare_body_content_filter ('item'=>item array, 'filter_reasons'=>string array) before first bbcode to html - * @hook prepare_body ('item'=>item array, 'html'=>body string, 'is_preview'=>boolean, 'filter_reasons'=>string array) after first bbcode to html - * @hook prepare_body_final ('item'=>item array, 'html'=>body string) after attach icons and blockquote special case handling (spoiler, author) - */ -function prepare_body(array &$item, $attach = false, $is_preview = false) -{ - $a = get_app(); - Addon::callHooks('prepare_body_init', $item); - - // In order to provide theme developers more possibilities, event items - // are treated differently. - if ($item['object-type'] === ACTIVITY_OBJ_EVENT && isset($item['event-id'])) { - $ev = Event::getItemHTML($item); - return $ev; - } - - $tags = \Friendica\Model\Term::populateTagsFromItem($item); - - $item['tags'] = $tags['tags']; - $item['hashtags'] = $tags['hashtags']; - $item['mentions'] = $tags['mentions']; - - // Compile eventual content filter reasons - $filter_reasons = []; - if (!$is_preview && public_contact() != $item['author-id']) { - if (!empty($item['content-warning']) && (!local_user() || !PConfig::get(local_user(), 'system', 'disable_cw', false))) { - $filter_reasons[] = L10n::t('Content warning: %s', $item['content-warning']); - } - - $hook_data = [ - 'item' => $item, - 'filter_reasons' => $filter_reasons - ]; - Addon::callHooks('prepare_body_content_filter', $hook_data); - $filter_reasons = $hook_data['filter_reasons']; - unset($hook_data); - } - - // Update the cached values if there is no "zrl=..." on the links. - $update = (!local_user() && !remote_user() && ($item["uid"] == 0)); - - // Or update it if the current viewer is the intented viewer. - if (($item["uid"] == local_user()) && ($item["uid"] != 0)) { - $update = true; - } - - put_item_in_cache($item, $update); - $s = $item["rendered-html"]; - - $hook_data = [ - 'item' => $item, - 'html' => $s, - 'preview' => $is_preview, - 'filter_reasons' => $filter_reasons - ]; - Addon::callHooks('prepare_body', $hook_data); - $s = $hook_data['html']; - unset($hook_data); - - if (!$attach) { - // Replace the blockquotes with quotes that are used in mails. - $mailquote = '
'; - $s = str_replace(['', '', ''], [$mailquote, $mailquote, $mailquote], $s); - return $s; - } - - $as = ''; - $vhead = false; - $matches = []; - preg_match_all('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\"(?: title=\"(.*?)\")?|', $item['attach'], $matches, PREG_SET_ORDER); - foreach ($matches as $mtch) { - $mime = $mtch[3]; - - $the_url = Contact::magicLinkById($item['author-id'], $mtch[1]); - - if (strpos($mime, 'video') !== false) { - if (!$vhead) { - $vhead = true; - $a->page['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('videos_head.tpl'), [ - '$baseurl' => System::baseUrl(), - ]); - } - - $url_parts = explode('/', $the_url); - $id = end($url_parts); - $as .= Renderer::replaceMacros(Renderer::getMarkupTemplate('video_top.tpl'), [ - '$video' => [ - 'id' => $id, - 'title' => L10n::t('View Video'), - 'src' => $the_url, - 'mime' => $mime, - ], - ]); - } - - $filetype = strtolower(substr($mime, 0, strpos($mime, '/'))); - if ($filetype) { - $filesubtype = strtolower(substr($mime, strpos($mime, '/') + 1)); - $filesubtype = str_replace('.', '-', $filesubtype); - } else { - $filetype = 'unkn'; - $filesubtype = 'unkn'; - } - - $title = escape_tags(trim(!empty($mtch[4]) ? $mtch[4] : $mtch[1])); - $title .= ' ' . $mtch[2] . ' ' . L10n::t('bytes'); - - $icon = ''; - $as .= '' . $icon . ''; - } - - if ($as != '') { - $s .= ''.$as.''; - } - - // Map. - if (strpos($s, '') !== false && x($item, 'coord')) { - $x = Map::byCoordinates(trim($item['coord'])); - if ($x) { - $s = preg_replace('/\/', '$0' . $x, $s); - } - } - - - // Look for spoiler. - $spoilersearch = ''; - - // Remove line breaks before the spoiler. - while ((strpos($s, "\n" . $spoilersearch) !== false)) { - $s = str_replace("\n" . $spoilersearch, $spoilersearch, $s); - } - while ((strpos($s, "
" . $spoilersearch) !== false)) { - $s = str_replace("
" . $spoilersearch, $spoilersearch, $s); - } - - while ((strpos($s, $spoilersearch) !== false)) { - $pos = strpos($s, $spoilersearch); - $rnd = random_string(8); - $spoilerreplace = '
' . L10n::t('Click to open/close') . ''. - ''; - $s = substr($s, 0, $pos) . $spoilerreplace . substr($s, $pos + strlen($spoilersearch)); - } - - // Look for quote with author. - $authorsearch = ''; - - while ((strpos($s, $authorsearch) !== false)) { - $pos = strpos($s, $authorsearch); - $rnd = random_string(8); - $authorreplace = '
' . L10n::t('Click to open/close') . ''. - ''; - $s = substr($s, 0, $pos) . $authorreplace . substr($s, $pos + strlen($authorsearch)); - } - - // Replace friendica image url size with theme preference. - if (x($a->theme_info, 'item_image_size')){ - $ps = $a->theme_info['item_image_size']; - $s = preg_replace('|(]+src="[^"]+/photo/[0-9a-f]+)-[0-9]|', "$1-" . $ps, $s); - } - - $s = HTML::applyContentFilter($s, $filter_reasons); - - $hook_data = ['item' => $item, 'html' => $s]; - Addon::callHooks('prepare_body_final', $hook_data); - - return $hook_data['html']; -} - /** * @brief Given a text string, convert from bbcode to html and add smilie icons. * @@ -723,42 +250,6 @@ function get_cats_and_terms($item) return [$categories, $folders]; } - -/** - * get private link for item - * @param array $item - * @return boolean|array False if item has not plink, otherwise array('href'=>plink url, 'title'=>translated title) - */ -function get_plink($item) { - $a = get_app(); - - if ($a->user['nickname'] != "") { - $ret = [ - //'href' => "display/" . $a->user['nickname'] . "/" . $item['id'], - 'href' => "display/" . $item['guid'], - 'orig' => "display/" . $item['guid'], - 'title' => L10n::t('View on separate page'), - 'orig_title' => L10n::t('view on separate page'), - ]; - - if (x($item, 'plink')) { - $ret["href"] = $a->removeBaseURL($item['plink']); - $ret["title"] = L10n::t('link to source'); - } - - } elseif (x($item, 'plink') && ($item['private'] != 1)) { - $ret = [ - 'href' => $item['plink'], - 'orig' => $item['plink'], - 'title' => L10n::t('link to source'), - ]; - } else { - $ret = []; - } - - return $ret; -} - /** * return number of bytes in size (K, M, G) * @param string $size_str @@ -773,53 +264,6 @@ function return_bytes($size_str) { } } -/** - * @param string $s - * @param boolean $strip_padding - * @return string - */ -function base64url_encode($s, $strip_padding = false) { - - $s = strtr(base64_encode($s), '+/', '-_'); - - if ($strip_padding) { - $s = str_replace('=','',$s); - } - - return $s; -} - -/** - * @param string $s - * @return string - */ -function base64url_decode($s) { - - if (is_array($s)) { - Logger::log('base64url_decode: illegal input: ' . print_r(debug_backtrace(), true)); - return $s; - } - -/* - * // Placeholder for new rev of salmon which strips base64 padding. - * // PHP base64_decode handles the un-padded input without requiring this step - * // Uncomment if you find you need it. - * - * $l = strlen($s); - * if (!strpos($s,'=')) { - * $m = $l % 4; - * if ($m == 2) - * $s .= '=='; - * if ($m == 3) - * $s .= '='; - * } - * - */ - - return base64_decode(strtr($s,'-_','+/')); -} - - function bb_translate_video($s) { $matches = null; @@ -836,31 +280,6 @@ function bb_translate_video($s) { return $s; } -/** - * get translated item type - * - * @param array $itme - * @return string - */ -function item_post_type($item) { - if (!empty($item['event-id'])) { - return L10n::t('event'); - } elseif (!empty($item['resource-id'])) { - return L10n::t('photo'); - } elseif (!empty($item['verb']) && $item['verb'] !== ACTIVITY_POST) { - return L10n::t('activity'); - } elseif ($item['id'] != $item['parent']) { - return L10n::t('comment'); - } - - return L10n::t('post'); -} - -function normalise_openid($s) { - return trim(str_replace(['http://', 'https://'], ['', ''], $s), '/'); -} - - function undo_post_tagging($s) { $matches = null; $cnt = preg_match_all('/([!#@])\[url=(.*?)\](.*?)\[\/url\]/ism', $s, $matches, PREG_SET_ORDER); @@ -876,10 +295,6 @@ function undo_post_tagging($s) { return $s; } -function protect_sprintf($s) { - return str_replace('%', '%%', $s); -} - /// @TODO Rewrite this function is_a_date_arg($s) { $i = intval($s); @@ -898,59 +313,3 @@ function is_a_date_arg($s) { return false; } - -/** - * remove intentation from a text - */ -function deindent($text, $chr = "[\t ]", $count = NULL) { - $lines = explode("\n", $text); - - if (is_null($count)) { - $m = []; - $k = 0; - while ($k < count($lines) && strlen($lines[$k]) == 0) { - $k++; - } - preg_match("|^" . $chr . "*|", $lines[$k], $m); - $count = strlen($m[0]); - } - - for ($k = 0; $k < count($lines); $k++) { - $lines[$k] = preg_replace("|^" . $chr . "{" . $count . "}|", "", $lines[$k]); - } - - return implode("\n", $lines); -} - -function formatBytes($bytes, $precision = 2) { - $units = ['B', 'KB', 'MB', 'GB', 'TB']; - - $bytes = max($bytes, 0); - $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); - $pow = min($pow, count($units) - 1); - - $bytes /= pow(1024, $pow); - - return round($bytes, $precision) . ' ' . $units[$pow]; -} - -/** - * @brief translate and format the networkname of a contact - * - * @param string $network - * Networkname of the contact (e.g. dfrn, rss and so on) - * @param sting $url - * The contact url - * @return string - */ -function format_network_name($network, $url = 0) { - if ($network != "") { - if ($url != "") { - $network_name = ''.ContactSelector::networkToName($network, $url).""; - } else { - $network_name = ContactSelector::networkToName($network); - } - - return $network_name; - } -} diff --git a/mod/acl.php b/mod/acl.php index a63cd83ae..cb378dc27 100644 --- a/mod/acl.php +++ b/mod/acl.php @@ -12,6 +12,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\Item; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; require_once 'include/dba.php'; @@ -188,7 +189,7 @@ function acl_content(App $a) ); } elseif ($type == 'x') { // autocomplete for global contact search (e.g. navbar search) - $search = notags(trim($_REQUEST['search'])); + $search = Strings::escapeTags(trim($_REQUEST['search'])); $mode = $_REQUEST['smode']; $r = ACL::contactAutocomplete($search, $mode); diff --git a/mod/admin.php b/mod/admin.php index 272b97a88..5adc8e9c4 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -30,6 +30,7 @@ use Friendica\Module\Tos; use Friendica\Util\Arrays; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Strings; use Friendica\Util\Temporal; require_once 'include/enotify.php'; @@ -416,8 +417,8 @@ function admin_page_blocklist_post(App $a) // Add new item to blocklist $blocklist = Config::get('system', 'blocklist'); $blocklist[] = [ - 'domain' => notags(trim($_POST['newentry_domain'])), - 'reason' => notags(trim($_POST['newentry_reason'])) + 'domain' => Strings::escapeTags(trim($_POST['newentry_domain'])), + 'reason' => Strings::escapeTags(trim($_POST['newentry_reason'])) ]; Config::set('system', 'blocklist', $blocklist); info(L10n::t('Server added to blocklist.') . EOL); @@ -426,8 +427,8 @@ function admin_page_blocklist_post(App $a) $blocklist = []; foreach ($_POST['domain'] as $id => $domain) { // Trimming whitespaces as well as any lingering slashes - $domain = notags(trim($domain, "\x00..\x1F/")); - $reason = notags(trim($_POST['reason'][$id])); + $domain = Strings::escapeTags(trim($domain, "\x00..\x1F/")); + $reason = Strings::escapeTags(trim($_POST['reason'][$id])); if (!x($_POST['delete'][$id])) { $blocklist[] = [ 'domain' => $domain, @@ -565,7 +566,7 @@ function admin_page_deleteitem_post(App $a) BaseModule::checkFormSecurityTokenRedirectOnError('/admin/deleteitem/', 'admin_deleteitem'); if (x($_POST['page_deleteitem_submit'])) { - $guid = trim(notags($_POST['deleteitemguid'])); + $guid = trim(Strings::escapeTags($_POST['deleteitemguid'])); // The GUID should not include a "/", so if there is one, we got an URL // and the last part of it is most likely the GUID. if (strpos($guid, '/')) { @@ -996,8 +997,8 @@ function admin_page_site_post(App $a) $old_url = $a->getBaseURL(true); // Generate host names for relocation the addresses in the format user@address.tld - $new_host = str_replace("http://", "@", normalise_link($new_url)); - $old_host = str_replace("http://", "@", normalise_link($old_url)); + $new_host = str_replace("http://", "@", Strings::normaliseLink($new_url)); + $old_host = str_replace("http://", "@", Strings::normaliseLink($old_url)); function update_table(App $a, $table_name, $fields, $old_url, $new_url) { @@ -1048,16 +1049,16 @@ function admin_page_site_post(App $a) } // end relocate - $sitename = ((x($_POST,'sitename')) ? notags(trim($_POST['sitename'])) : ''); - $hostname = ((x($_POST,'hostname')) ? notags(trim($_POST['hostname'])) : ''); - $sender_email = ((x($_POST,'sender_email')) ? notags(trim($_POST['sender_email'])) : ''); + $sitename = ((x($_POST,'sitename')) ? Strings::escapeTags(trim($_POST['sitename'])) : ''); + $hostname = ((x($_POST,'hostname')) ? Strings::escapeTags(trim($_POST['hostname'])) : ''); + $sender_email = ((x($_POST,'sender_email')) ? Strings::escapeTags(trim($_POST['sender_email'])) : ''); $banner = ((x($_POST,'banner')) ? trim($_POST['banner']) : false); - $shortcut_icon = ((x($_POST,'shortcut_icon')) ? notags(trim($_POST['shortcut_icon'])) : ''); - $touch_icon = ((x($_POST,'touch_icon')) ? notags(trim($_POST['touch_icon'])) : ''); + $shortcut_icon = ((x($_POST,'shortcut_icon')) ? Strings::escapeTags(trim($_POST['shortcut_icon'])) : ''); + $touch_icon = ((x($_POST,'touch_icon')) ? Strings::escapeTags(trim($_POST['touch_icon'])) : ''); $info = ((x($_POST,'info')) ? trim($_POST['info']) : false); - $language = ((x($_POST,'language')) ? notags(trim($_POST['language'])) : ''); - $theme = ((x($_POST,'theme')) ? notags(trim($_POST['theme'])) : ''); - $theme_mobile = ((x($_POST,'theme_mobile')) ? notags(trim($_POST['theme_mobile'])) : ''); + $language = ((x($_POST,'language')) ? Strings::escapeTags(trim($_POST['language'])) : ''); + $theme = ((x($_POST,'theme')) ? Strings::escapeTags(trim($_POST['theme'])) : ''); + $theme_mobile = ((x($_POST,'theme_mobile')) ? Strings::escapeTags(trim($_POST['theme_mobile'])) : ''); $maximagesize = ((x($_POST,'maximagesize')) ? intval(trim($_POST['maximagesize'])) : 0); $maximagelength = ((x($_POST,'maximagelength')) ? intval(trim($_POST['maximagelength'])) : MAX_IMAGE_LENGTH); $jpegimagequality = ((x($_POST,'jpegimagequality')) ? intval(trim($_POST['jpegimagequality'])) : JPEG_QUALITY); @@ -1069,14 +1070,14 @@ function admin_page_site_post(App $a) $register_text = ((x($_POST,'register_text')) ? strip_tags(trim($_POST['register_text'])) : ''); - $allowed_sites = ((x($_POST,'allowed_sites')) ? notags(trim($_POST['allowed_sites'])) : ''); - $allowed_email = ((x($_POST,'allowed_email')) ? notags(trim($_POST['allowed_email'])) : ''); - $forbidden_nicknames = ((x($_POST,'forbidden_nicknames')) ? strtolower(notags(trim($_POST['forbidden_nicknames']))) : ''); + $allowed_sites = ((x($_POST,'allowed_sites')) ? Strings::escapeTags(trim($_POST['allowed_sites'])) : ''); + $allowed_email = ((x($_POST,'allowed_email')) ? Strings::escapeTags(trim($_POST['allowed_email'])) : ''); + $forbidden_nicknames = ((x($_POST,'forbidden_nicknames')) ? strtolower(Strings::escapeTags(trim($_POST['forbidden_nicknames']))) : ''); $no_oembed_rich_content = x($_POST,'no_oembed_rich_content'); - $allowed_oembed = ((x($_POST,'allowed_oembed')) ? notags(trim($_POST['allowed_oembed'])) : ''); + $allowed_oembed = ((x($_POST,'allowed_oembed')) ? Strings::escapeTags(trim($_POST['allowed_oembed'])) : ''); $block_public = ((x($_POST,'block_public')) ? True : False); $force_publish = ((x($_POST,'publish_all')) ? True : False); - $global_directory = ((x($_POST,'directory')) ? notags(trim($_POST['directory'])) : ''); + $global_directory = ((x($_POST,'directory')) ? Strings::escapeTags(trim($_POST['directory'])) : ''); $newuser_private = ((x($_POST,'newuser_private')) ? True : False); $enotify_no_content = ((x($_POST,'enotify_no_content')) ? True : False); $private_addons = ((x($_POST,'private_addons')) ? True : False); @@ -1091,8 +1092,8 @@ function admin_page_site_post(App $a) $max_author_posts_community_page = ((x($_POST,'max_author_posts_community_page')) ? intval(trim($_POST['max_author_posts_community_page'])) : 0); $verifyssl = ((x($_POST,'verifyssl')) ? True : False); - $proxyuser = ((x($_POST,'proxyuser')) ? notags(trim($_POST['proxyuser'])) : ''); - $proxy = ((x($_POST,'proxy')) ? notags(trim($_POST['proxy'])) : ''); + $proxyuser = ((x($_POST,'proxyuser')) ? Strings::escapeTags(trim($_POST['proxyuser'])) : ''); + $proxy = ((x($_POST,'proxy')) ? Strings::escapeTags(trim($_POST['proxy'])) : ''); $timeout = ((x($_POST,'timeout')) ? intval(trim($_POST['timeout'])) : 60); $maxloadavg = ((x($_POST,'maxloadavg')) ? intval(trim($_POST['maxloadavg'])) : 50); $maxloadavg_frontend = ((x($_POST,'maxloadavg_frontend')) ? intval(trim($_POST['maxloadavg_frontend'])) : 50); @@ -1116,16 +1117,16 @@ function admin_page_site_post(App $a) $dbclean_expire_days = ((x($_POST,'dbclean_expire_days')) ? intval($_POST['dbclean_expire_days']) : 0); $dbclean_unclaimed = ((x($_POST,'dbclean_unclaimed')) ? intval($_POST['dbclean_unclaimed']) : 0); $suppress_tags = ((x($_POST,'suppress_tags')) ? True : False); - $itemcache = ((x($_POST,'itemcache')) ? notags(trim($_POST['itemcache'])) : ''); + $itemcache = ((x($_POST,'itemcache')) ? Strings::escapeTags(trim($_POST['itemcache'])) : ''); $itemcache_duration = ((x($_POST,'itemcache_duration')) ? intval($_POST['itemcache_duration']) : 0); $max_comments = ((x($_POST,'max_comments')) ? intval($_POST['max_comments']) : 0); - $temppath = ((x($_POST,'temppath')) ? notags(trim($_POST['temppath'])) : ''); - $basepath = ((x($_POST,'basepath')) ? notags(trim($_POST['basepath'])) : ''); - $singleuser = ((x($_POST,'singleuser')) ? notags(trim($_POST['singleuser'])) : ''); + $temppath = ((x($_POST,'temppath')) ? Strings::escapeTags(trim($_POST['temppath'])) : ''); + $basepath = ((x($_POST,'basepath')) ? Strings::escapeTags(trim($_POST['basepath'])) : ''); + $singleuser = ((x($_POST,'singleuser')) ? Strings::escapeTags(trim($_POST['singleuser'])) : ''); $proxy_disabled = ((x($_POST,'proxy_disabled')) ? True : False); $only_tag_search = ((x($_POST,'only_tag_search')) ? True : False); $rino = ((x($_POST,'rino')) ? intval($_POST['rino']) : 0); - $check_new_version_url = ((x($_POST, 'check_new_version_url')) ? notags(trim($_POST['check_new_version_url'])) : 'none'); + $check_new_version_url = ((x($_POST, 'check_new_version_url')) ? Strings::escapeTags(trim($_POST['check_new_version_url'])) : 'none'); $worker_queues = ((x($_POST,'worker_queues')) ? intval($_POST['worker_queues']) : 10); $worker_dont_fork = ((x($_POST,'worker_dont_fork')) ? True : False); @@ -1133,10 +1134,10 @@ function admin_page_site_post(App $a) $worker_frontend = ((x($_POST,'worker_frontend')) ? True : False); $relay_directly = ((x($_POST,'relay_directly')) ? True : False); - $relay_server = ((x($_POST,'relay_server')) ? notags(trim($_POST['relay_server'])) : ''); + $relay_server = ((x($_POST,'relay_server')) ? Strings::escapeTags(trim($_POST['relay_server'])) : ''); $relay_subscribe = ((x($_POST,'relay_subscribe')) ? True : False); - $relay_scope = ((x($_POST,'relay_scope')) ? notags(trim($_POST['relay_scope'])) : ''); - $relay_server_tags = ((x($_POST,'relay_server_tags')) ? notags(trim($_POST['relay_server_tags'])) : ''); + $relay_scope = ((x($_POST,'relay_scope')) ? Strings::escapeTags(trim($_POST['relay_scope'])) : ''); + $relay_server_tags = ((x($_POST,'relay_server_tags')) ? Strings::escapeTags(trim($_POST['relay_server_tags'])) : ''); $relay_user_tags = ((x($_POST,'relay_user_tags')) ? True : False); // Has the directory url changed? If yes, then resubmit the existing profiles there @@ -1695,10 +1696,10 @@ function admin_page_users_post(App $a) } $user = $result['user']; - $preamble = deindent(L10n::t(' + $preamble = Strings::deindent(L10n::t(' Dear %1$s, the administrator of %2$s has set up an account for you.')); - $body = deindent(L10n::t(' + $body = Strings::deindent(L10n::t(' The login details are as follows: Site Location: %1$s @@ -2370,7 +2371,7 @@ function admin_page_logs_post(App $a) if (x($_POST, "page_logs")) { BaseModule::checkFormSecurityTokenRedirectOnError('/admin/logs', 'admin_logs'); - $logfile = ((x($_POST,'logfile')) ? notags(trim($_POST['logfile'])) : ''); + $logfile = ((x($_POST,'logfile')) ? Strings::escapeTags(trim($_POST['logfile'])) : ''); $debugging = ((x($_POST,'debugging')) ? true : false); $loglevel = ((x($_POST,'loglevel')) ? intval(trim($_POST['loglevel'])) : 0); @@ -2477,9 +2478,9 @@ function admin_page_viewlogs(App $a) } $seek = fseek($fp, 0 - $size, SEEK_END); if ($seek === 0) { - $data = escape_tags(fread($fp, $size)); + $data = Strings::escapeHtml(fread($fp, $size)); while (!feof($fp)) { - $data .= escape_tags(fread($fp, 4096)); + $data .= Strings::escapeHtml(fread($fp, 4096)); } } } diff --git a/mod/bookmarklet.php b/mod/bookmarklet.php index e1ae9aa64..d9c2f52f8 100644 --- a/mod/bookmarklet.php +++ b/mod/bookmarklet.php @@ -9,6 +9,7 @@ use Friendica\Core\Config; use Friendica\Core\L10n; use Friendica\Core\System; use Friendica\Module\Login; +use Friendica\Util\Strings; require_once 'include/conversation.php'; require_once 'include/items.php'; @@ -26,8 +27,8 @@ function bookmarklet_content(App $a) return $o; } - $referer = normalise_link(defaults($_SERVER, 'HTTP_REFERER', '')); - $page = normalise_link(System::baseUrl() . "/bookmarklet"); + $referer = Strings::normaliseLink(defaults($_SERVER, 'HTTP_REFERER', '')); + $page = Strings::normaliseLink(System::baseUrl() . "/bookmarklet"); if (!strstr($referer, $page)) { if (empty($_REQUEST["url"])) { diff --git a/mod/common.php b/mod/common.php index 0f9bc096a..b335e296d 100644 --- a/mod/common.php +++ b/mod/common.php @@ -12,7 +12,7 @@ use Friendica\Database\DBA; use Friendica\Model; use Friendica\Module; use Friendica\Util\Proxy as ProxyUtils; - +use Friendica\Util\Strings; require_once 'include/dba.php'; @@ -67,11 +67,11 @@ function common_content(App $a) } if (!$cid && Model\Profile::getMyURL()) { - $contact = DBA::selectFirst('contact', ['id'], ['nurl' => normalise_link(Model\Profile::getMyURL()), 'uid' => $uid]); + $contact = DBA::selectFirst('contact', ['id'], ['nurl' => Strings::normaliseLink(Model\Profile::getMyURL()), 'uid' => $uid]); if (DBA::isResult($contact)) { $cid = $contact['id']; } else { - $gcontact = DBA::selectFirst('gcontact', ['id'], ['nurl' => normalise_link(Model\Profile::getMyURL())]); + $gcontact = DBA::selectFirst('gcontact', ['id'], ['nurl' => Strings::normaliseLink(Model\Profile::getMyURL())]); if (DBA::isResult($gcontact)) { $zcid = $gcontact['id']; } diff --git a/mod/crepair.php b/mod/crepair.php index 330831559..f9ba281d1 100644 --- a/mod/crepair.php +++ b/mod/crepair.php @@ -12,6 +12,7 @@ use Friendica\Core\Renderer; use Friendica\Database\DBA; use Friendica\Model; use Friendica\Module; +use Friendica\Util\Strings; function crepair_init(App $a) { @@ -61,7 +62,7 @@ function crepair_post(App $a) $attag = defaults($_POST, 'attag' , ''); $photo = defaults($_POST, 'photo' , ''); $remote_self = defaults($_POST, 'remote_self', false); - $nurl = normalise_link($url); + $nurl = Strings::normaliseLink($url); $r = q("UPDATE `contact` SET `name` = '%s', `nick` = '%s', `url` = '%s', `nurl` = '%s', `request` = '%s', `confirm` = '%s', `notify` = '%s', `poll` = '%s', `attag` = '%s' , `remote_self` = %d WHERE `id` = %d AND `uid` = %d", diff --git a/mod/delegate.php b/mod/delegate.php index 116245812..c8987ab57 100644 --- a/mod/delegate.php +++ b/mod/delegate.php @@ -12,6 +12,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model\User; use Friendica\Util\Security; +use Friendica\Util\Strings; require_once 'mod/settings.php'; @@ -72,7 +73,7 @@ function delegate_content(App $a) if (DBA::isResult($user)) { $condition = [ 'uid' => local_user(), - 'nurl' => normalise_link(System::baseUrl() . '/profile/' . $user['nickname']) + 'nurl' => Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname']) ]; if (DBA::exists('contact', $condition)) { DBA::insert('manage', ['uid' => $user_id, 'mid' => local_user()]); @@ -114,7 +115,7 @@ function delegate_content(App $a) AND SUBSTRING_INDEX(`nurl`, '/', 3) = '%s' AND `uid` = %d AND `network` = '%s' ", - DBA::escape(normalise_link(System::baseUrl())), + DBA::escape(Strings::normaliseLink(System::baseUrl())), intval(local_user()), DBA::escape(Protocol::DFRN) ); diff --git a/mod/dfrn_confirm.php b/mod/dfrn_confirm.php index 0f001b11a..48c8e32e5 100644 --- a/mod/dfrn_confirm.php +++ b/mod/dfrn_confirm.php @@ -33,6 +33,7 @@ use Friendica\Protocol\ActivityPub; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Strings; use Friendica\Util\XML; require_once 'include/enotify.php'; @@ -84,7 +85,7 @@ function dfrn_confirm_post(App $a, $handsfree = null) $cid = 0; $hidden = intval(defaults($handsfree, 'hidden' , 0)); } else { - $dfrn_id = notags(trim(defaults($_POST, 'dfrn_id' , ''))); + $dfrn_id = Strings::escapeTags(trim(defaults($_POST, 'dfrn_id' , ''))); $intro_id = intval(defaults($_POST, 'intro_id' , 0)); $duplex = intval(defaults($_POST, 'duplex' , 0)); $cid = intval(defaults($_POST, 'contact_id', 0)); @@ -263,7 +264,7 @@ function dfrn_confirm_post(App $a, $handsfree = null) break; case 1: // birthday paradox - generate new dfrn-id and fall through. - $new_dfrn_id = random_string(); + $new_dfrn_id = Strings::getRandomHex(); q("UPDATE contact SET `issued-id` = '%s' WHERE `id` = %d AND `uid` = %d", DBA::escape($new_dfrn_id), intval($contact_id), diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index b14c71fb8..63f53e060 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -14,6 +14,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Protocol\DFRN; use Friendica\Protocol\Diaspora; +use Friendica\Util\Strings; require_once 'include/items.php'; @@ -38,15 +39,15 @@ function dfrn_notify_post(App $a) { } } - $dfrn_id = ((x($_POST,'dfrn_id')) ? notags(trim($_POST['dfrn_id'])) : ''); + $dfrn_id = ((x($_POST,'dfrn_id')) ? Strings::escapeTags(trim($_POST['dfrn_id'])) : ''); $dfrn_version = ((x($_POST,'dfrn_version')) ? (float) $_POST['dfrn_version'] : 2.0); - $challenge = ((x($_POST,'challenge')) ? notags(trim($_POST['challenge'])) : ''); + $challenge = ((x($_POST,'challenge')) ? Strings::escapeTags(trim($_POST['challenge'])) : ''); $data = ((x($_POST,'data')) ? $_POST['data'] : ''); $key = ((x($_POST,'key')) ? $_POST['key'] : ''); $rino_remote = ((x($_POST,'rino')) ? intval($_POST['rino']) : 0); $dissolve = ((x($_POST,'dissolve')) ? intval($_POST['dissolve']) : 0); - $perm = ((x($_POST,'perm')) ? notags(trim($_POST['perm'])) : 'r'); - $ssl_policy = ((x($_POST,'ssl_policy')) ? notags(trim($_POST['ssl_policy'])): 'none'); + $perm = ((x($_POST,'perm')) ? Strings::escapeTags(trim($_POST['perm'])) : 'r'); + $ssl_policy = ((x($_POST,'ssl_policy')) ? Strings::escapeTags(trim($_POST['ssl_policy'])): 'none'); $page = ((x($_POST,'page')) ? intval($_POST['page']) : 0); $forum = (($page == 1) ? 1 : 0); @@ -253,7 +254,7 @@ function dfrn_notify_content(App $a) { * If this is a duplex communication, ours will be the opposite. */ - $dfrn_id = notags(trim($_GET['dfrn_id'])); + $dfrn_id = Strings::escapeTags(trim($_GET['dfrn_id'])); $dfrn_version = (float) $_GET['dfrn_version']; $rino_remote = ((x($_GET,'rino')) ? intval($_GET['rino']) : 0); $type = ""; @@ -267,7 +268,7 @@ function dfrn_notify_content(App $a) { $dfrn_id = substr($dfrn_id,2); } - $hash = random_string(); + $hash = Strings::getRandomHex(); $status = 0; diff --git a/mod/dfrn_poll.php b/mod/dfrn_poll.php index a961506d1..9cd110917 100644 --- a/mod/dfrn_poll.php +++ b/mod/dfrn_poll.php @@ -14,6 +14,7 @@ use Friendica\Module\Login; use Friendica\Protocol\DFRN; use Friendica\Protocol\OStatus; use Friendica\Util\Network; +use Friendica\Util\Strings; use Friendica\Util\XML; require_once 'include/items.php'; @@ -415,7 +416,7 @@ function dfrn_poll_content(App $a) if ($dfrn_id != '') { // initial communication from external contact - $hash = random_string(); + $hash = Strings::getRandomHex(); $status = 0; diff --git a/mod/dfrn_request.php b/mod/dfrn_request.php index fdb1a42ee..26d7efda5 100644 --- a/mod/dfrn_request.php +++ b/mod/dfrn_request.php @@ -28,6 +28,7 @@ use Friendica\Module\Login; use Friendica\Network\Probe; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Strings; require_once 'include/enotify.php'; @@ -75,7 +76,7 @@ function dfrn_request_post(App $a) if ((x($_POST, 'localconfirm')) && ($_POST['localconfirm'] == 1)) { // Ensure this is a valid request if (local_user() && ($a->user['nickname'] == $a->argv[1]) && (x($_POST, 'dfrn_url'))) { - $dfrn_url = notags(trim($_POST['dfrn_url'])); + $dfrn_url = Strings::escapeTags(trim($_POST['dfrn_url'])); $aes_allow = (((x($_POST, 'aes_allow')) && ($_POST['aes_allow'] == 1)) ? 1 : 0); $confirm_key = ((x($_POST, 'confirm_key')) ? $_POST['confirm_key'] : ""); $hidden = ((x($_POST, 'hidden-contact')) ? intval($_POST['hidden-contact']) : 0); @@ -87,7 +88,7 @@ function dfrn_request_post(App $a) // Lookup the contact based on their URL (which is the only unique thing we have at the moment) $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND NOT `self` LIMIT 1", intval(local_user()), - DBA::escape(normalise_link($dfrn_url)) + DBA::escape(Strings::normaliseLink($dfrn_url)) ); if (DBA::isResult($r)) { @@ -141,7 +142,7 @@ function dfrn_request_post(App $a) intval(local_user()), DateTimeFormat::utcNow(), DBA::escape($dfrn_url), - DBA::escape(normalise_link($dfrn_url)), + DBA::escape(Strings::normaliseLink($dfrn_url)), $parms['addr'], $parms['fn'], $parms['nick'], @@ -269,7 +270,7 @@ function dfrn_request_post(App $a) } } - $real_name = x($_POST, 'realname') ? notags(trim($_POST['realname'])) : ''; + $real_name = x($_POST, 'realname') ? Strings::escapeTags(trim($_POST['realname'])) : ''; $url = trim($_POST['dfrn_url']); if (!strlen($url)) { @@ -320,7 +321,7 @@ function dfrn_request_post(App $a) } } - $issued_id = random_string(); + $issued_id = Strings::getRandomHex(); if (is_array($contact_record)) { // There is a contact record but no issued-id, so this @@ -380,7 +381,7 @@ function dfrn_request_post(App $a) intval($uid), DBA::escape(DateTimeFormat::utcNow()), $parms['url'], - DBA::escape(normalise_link($url)), + DBA::escape(Strings::normaliseLink($url)), $parms['addr'], $parms['fn'], $parms['nick'], @@ -415,7 +416,7 @@ function dfrn_request_post(App $a) return; } - $hash = random_string() . (string) time(); // Generate a confirm_key + $hash = Strings::getRandomHex() . (string) time(); // Generate a confirm_key if (is_array($contact_record)) { $ret = q("INSERT INTO `intro` ( `uid`, `contact-id`, `blocked`, `knowyou`, `note`, `hash`, `datetime`) @@ -423,7 +424,7 @@ function dfrn_request_post(App $a) intval($uid), intval($contact_record['id']), ((x($_POST,'knowyou') && ($_POST['knowyou'] == 1)) ? 1 : 0), - DBA::escape(notags(trim(defaults($_POST, 'dfrn-request-message', '')))), + DBA::escape(Strings::escapeTags(trim(defaults($_POST, 'dfrn-request-message', '')))), DBA::escape($hash), DBA::escape(DateTimeFormat::utcNow()) ); @@ -497,12 +498,12 @@ function dfrn_request_content(App $a) return Login::form(); } - $dfrn_url = notags(trim(hex2bin($_GET['dfrn_url']))); + $dfrn_url = Strings::escapeTags(trim(hex2bin($_GET['dfrn_url']))); $aes_allow = x($_GET, 'aes_allow') && $_GET['aes_allow'] == 1 ? 1 : 0; $confirm_key = x($_GET, 'confirm_key') ? $_GET['confirm_key'] : ""; // Checking fastlane for validity - if (x($_SESSION, "fastlane") && (normalise_link($_SESSION["fastlane"]) == normalise_link($dfrn_url))) { + if (x($_SESSION, "fastlane") && (Strings::normaliseLink($_SESSION["fastlane"]) == Strings::normaliseLink($dfrn_url))) { $_POST["dfrn_url"] = $dfrn_url; $_POST["confirm_key"] = $confirm_key; $_POST["localconfirm"] = 1; diff --git a/mod/directory.php b/mod/directory.php index 10eaa4492..e59cf7b82 100644 --- a/mod/directory.php +++ b/mod/directory.php @@ -15,6 +15,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\Profile; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; function directory_init(App $a) { @@ -47,9 +48,9 @@ function directory_content(App $a) Nav::setSelected('directory'); if (x($a->data, 'search')) { - $search = notags(trim($a->data['search'])); + $search = Strings::escapeTags(trim($a->data['search'])); } else { - $search = ((x($_GET, 'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); + $search = ((x($_GET, 'search')) ? Strings::escapeTags(trim(rawurldecode($_GET['search']))) : ''); } $gdirpath = ''; diff --git a/mod/dirfind.php b/mod/dirfind.php index 2451beb18..d3298b64d 100644 --- a/mod/dirfind.php +++ b/mod/dirfind.php @@ -20,6 +20,7 @@ use Friendica\Network\Probe; use Friendica\Protocol\PortableContact; use Friendica\Util\Network; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; function dirfind_init(App $a) { @@ -45,15 +46,15 @@ function dirfind_content(App $a, $prefix = "") { $local = Config::get('system','poco_local_search'); - $search = $prefix.notags(trim(defaults($_REQUEST, 'search', ''))); + $search = $prefix.Strings::escapeTags(trim(defaults($_REQUEST, 'search', ''))); $header = ''; if (strpos($search,'@') === 0) { $search = substr($search,1); $header = L10n::t('People Search - %s', $search); - if ((valid_email($search) && Network::isEmailDomainValid($search)) || - (substr(normalise_link($search), 0, 7) == "http://")) { + if ((filter_var($search, FILTER_VALIDATE_EMAIL) && Network::isEmailDomainValid($search)) || + (substr(Strings::normaliseLink($search), 0, 7) == "http://")) { $user_data = Probe::uri($search); $discover_user = (in_array($user_data["network"], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS, Protocol::DIASPORA])); } @@ -125,8 +126,8 @@ function dirfind_content(App $a, $prefix = "") { (`url` LIKE '%s' OR `name` LIKE '%s' OR `location` LIKE '%s' OR `addr` LIKE '%s' OR `about` LIKE '%s' OR `keywords` LIKE '%s') $extra_sql", DBA::escape(Protocol::DFRN), DBA::escape($ostatus), DBA::escape($diaspora), - DBA::escape(escape_tags($search2)), DBA::escape(escape_tags($search2)), DBA::escape(escape_tags($search2)), - DBA::escape(escape_tags($search2)), DBA::escape(escape_tags($search2)), DBA::escape(escape_tags($search2))); + DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)), + DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2))); $results = q("SELECT `nurl` FROM `gcontact` @@ -137,8 +138,8 @@ function dirfind_content(App $a, $prefix = "") { GROUP BY `nurl` ORDER BY `updated` DESC LIMIT %d, %d", DBA::escape(Protocol::DFRN), DBA::escape($ostatus), DBA::escape($diaspora), - DBA::escape(escape_tags($search2)), DBA::escape(escape_tags($search2)), DBA::escape(escape_tags($search2)), - DBA::escape(escape_tags($search2)), DBA::escape(escape_tags($search2)), DBA::escape(escape_tags($search2)), + DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)), + DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)), DBA::escape(Strings::escapeHtml($search2)), $pager->getStart(), $pager->getItemsPerPage()); $j = new stdClass(); $j->total = $count[0]["total"]; diff --git a/mod/display.php b/mod/display.php index ac345d541..39661cb76 100644 --- a/mod/display.php +++ b/mod/display.php @@ -21,6 +21,7 @@ use Friendica\Model\Item; use Friendica\Model\Profile; use Friendica\Protocol\ActivityPub; use Friendica\Protocol\DFRN; +use Friendica\Util\Strings; function display_init(App $a) { @@ -90,8 +91,8 @@ function display_init(App $a) $profiledata = display_fetchauthor($a, $item); - if (strstr(normalise_link($profiledata["url"]), normalise_link(System::baseUrl()))) { - $nickname = str_replace(normalise_link(System::baseUrl())."/profile/", "", normalise_link($profiledata["url"])); + if (strstr(Strings::normaliseLink($profiledata["url"]), Strings::normaliseLink(System::baseUrl()))) { + $nickname = str_replace(Strings::normaliseLink(System::baseUrl())."/profile/", "", Strings::normaliseLink($profiledata["url"])); if (($nickname != $a->user["nickname"])) { $profile = DBA::fetchFirst("SELECT `profile`.`uid` AS `profile_uid`, `profile`.* , `contact`.`avatar-date` AS picdate, `user`.* FROM `profile` diff --git a/mod/events.php b/mod/events.php index c9461a48e..f147e0054 100644 --- a/mod/events.php +++ b/mod/events.php @@ -19,6 +19,7 @@ use Friendica\Model\Item; use Friendica\Model\Profile; use Friendica\Module\Login; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Strings; use Friendica\Util\Temporal; require_once 'include/items.php'; @@ -59,8 +60,8 @@ function events_post(App $a) $cid = !empty($_POST['cid']) ? intval($_POST['cid']) : 0; $uid = local_user(); - $start_text = escape_tags(defaults($_REQUEST, 'start_text', '')); - $finish_text = escape_tags(defaults($_REQUEST, 'finish_text', '')); + $start_text = Strings::escapeHtml(defaults($_REQUEST, 'start_text', '')); + $finish_text = Strings::escapeHtml(defaults($_REQUEST, 'finish_text', '')); $adjust = intval(defaults($_POST, 'adjust', 0)); $nofinish = intval(defaults($_POST, 'nofinish', 0)); @@ -96,9 +97,9 @@ function events_post(App $a) // and we'll waste a bunch of time responding to it. Time that // could've been spent doing something else. - $summary = escape_tags(trim(defaults($_POST, 'summary', ''))); - $desc = escape_tags(trim(defaults($_POST, 'desc', ''))); - $location = escape_tags(trim(defaults($_POST, 'location', ''))); + $summary = Strings::escapeHtml(trim(defaults($_POST, 'summary', ''))); + $desc = Strings::escapeHtml(trim(defaults($_POST, 'desc', ''))); + $location = Strings::escapeHtml(trim(defaults($_POST, 'location', ''))); $type = 'event'; $action = ($event_id == '') ? 'new' : "event/" . $event_id; diff --git a/mod/fetch.php b/mod/fetch.php index 4e7d8c751..9336c1404 100644 --- a/mod/fetch.php +++ b/mod/fetch.php @@ -10,6 +10,7 @@ use Friendica\Core\System; use Friendica\Protocol\Diaspora; use Friendica\Model\Item; use Friendica\Model\User; +use Friendica\Util\Strings; use Friendica\Util\XML; use Friendica\Database\DBA; @@ -35,7 +36,7 @@ function fetch_init(App $a) $parts = parse_url($item["author-link"]); $host = $parts["scheme"]."://".$parts["host"]; - if (normalise_link($host) != normalise_link(System::baseUrl())) { + if (Strings::normaliseLink($host) != Strings::normaliseLink(System::baseUrl())) { $location = $host."/fetch/".$a->argv[1]."/".urlencode($guid); header("HTTP/1.1 301 Moved Permanently"); diff --git a/mod/follow.php b/mod/follow.php index 5c6c6d9d3..08f664d39 100644 --- a/mod/follow.php +++ b/mod/follow.php @@ -13,6 +13,7 @@ use Friendica\Model\Profile; use Friendica\Network\Probe; use Friendica\Database\DBA; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; function follow_post(App $a) { @@ -25,7 +26,7 @@ function follow_post(App $a) } $uid = local_user(); - $url = notags(trim($_REQUEST['url'])); + $url = Strings::escapeTags(trim($_REQUEST['url'])); $return_path = 'contacts'; // Makes the connection request for friendica contacts easier @@ -60,7 +61,7 @@ function follow_content(App $a) } $uid = local_user(); - $url = notags(trim($_REQUEST['url'])); + $url = Strings::escapeTags(trim($_REQUEST['url'])); $submit = L10n::t('Submit Request'); @@ -68,8 +69,8 @@ function follow_content(App $a) $r = q("SELECT `pending` FROM `contact` WHERE `uid` = %d AND ((`rel` != %d) OR (`network` = '%s')) AND (`nurl` = '%s' OR `alias` = '%s' OR `alias` = '%s') AND `network` != '%s' LIMIT 1", - intval(local_user()), DBA::escape(Contact::FOLLOWER), DBA::escape(Protocol::DFRN), DBA::escape(normalise_link($url)), - DBA::escape(normalise_link($url)), DBA::escape($url), DBA::escape(Protocol::STATUSNET)); + intval(local_user()), DBA::escape(Contact::FOLLOWER), DBA::escape(Protocol::DFRN), DBA::escape(Strings::normaliseLink($url)), + DBA::escape(Strings::normaliseLink($url)), DBA::escape($url), DBA::escape(Protocol::STATUSNET)); if ($r) { if ($r[0]['pending']) { @@ -130,7 +131,7 @@ function follow_content(App $a) $_SESSION['fastlane'] = $ret['url']; $r = q("SELECT `id`, `location`, `about`, `keywords` FROM `gcontact` WHERE `nurl` = '%s'", - normalise_link($ret['url'])); + Strings::normaliseLink($ret['url'])); if (!$r) { $r = [['location' => '', 'about' => '', 'keywords' => '']]; diff --git a/mod/fsuggest.php b/mod/fsuggest.php index 35710bb33..2195f455a 100644 --- a/mod/fsuggest.php +++ b/mod/fsuggest.php @@ -9,6 +9,7 @@ use Friendica\Core\L10n; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Strings; function fsuggest_post(App $a) { @@ -34,9 +35,9 @@ function fsuggest_post(App $a) $new_contact = intval($_POST['suggest']); - $hash = random_string(); + $hash = Strings::getRandomHex(); - $note = escape_tags(trim(defaults($_POST, 'note', ''))); + $note = Strings::escapeHtml(trim(defaults($_POST, 'note', ''))); if ($new_contact) { $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1", diff --git a/mod/group.php b/mod/group.php index 8b2ce9ca1..51fa2493e 100644 --- a/mod/group.php +++ b/mod/group.php @@ -16,6 +16,7 @@ use Friendica\Database\DBA; use Friendica\Model; use Friendica\Module; use Friendica\Util\Security; +use Friendica\Util\Strings; function group_init(App $a) { if (local_user()) { @@ -33,7 +34,7 @@ function group_post(App $a) { if (($a->argc == 2) && ($a->argv[1] === 'new')) { BaseModule::checkFormSecurityTokenRedirectOnError('/group/new', 'group_edit'); - $name = notags(trim($_POST['groupname'])); + $name = Strings::escapeTags(trim($_POST['groupname'])); $r = Model\Group::create(local_user(), $name); if ($r) { info(L10n::t('Group created.') . EOL); @@ -61,7 +62,7 @@ function group_post(App $a) { return; // NOTREACHED } $group = $r[0]; - $groupname = notags(trim($_POST['groupname'])); + $groupname = Strings::escapeTags(trim($_POST['groupname'])); if (strlen($groupname) && ($groupname != $group['name'])) { $r = q("UPDATE `group` SET `name` = '%s' WHERE `uid` = %d AND `id` = %d", DBA::escape($groupname), diff --git a/mod/help.php b/mod/help.php index 2c8f68ff3..3a21695b0 100644 --- a/mod/help.php +++ b/mod/help.php @@ -10,6 +10,7 @@ use Friendica\Core\Config; use Friendica\Core\L10n; use Friendica\Core\Renderer; use Friendica\Core\System; +use Friendica\Util\Strings; function load_doc_file($s) { @@ -47,7 +48,7 @@ function help_content(App $a) $title = basename($path); $filename = $path; $text = load_doc_file('doc/' . $path . '.md'); - $a->page['title'] = L10n::t('Help:') . ' ' . str_replace('-', ' ', notags($title)); + $a->page['title'] = L10n::t('Help:') . ' ' . str_replace('-', ' ', Strings::escapeTags($title)); } $home = load_doc_file('doc/Home.md'); diff --git a/mod/hovercard.php b/mod/hovercard.php index 1e2e14afb..f5ad3ef02 100644 --- a/mod/hovercard.php +++ b/mod/hovercard.php @@ -16,6 +16,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\GContact; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; function hovercard_init(App $a) { @@ -55,7 +56,7 @@ function hovercard_content() $contact = []; // if it's the url containing https it should be converted to http - $nurl = normalise_link(GContact::cleanContactUrl($profileurl)); + $nurl = Strings::normaliseLink(GContact::cleanContactUrl($profileurl)); if (!$nurl) { return; } @@ -73,12 +74,12 @@ function hovercard_content() // Feeds url could have been destroyed through "cleanContactUrl", so we now use the original url if (!count($contact) && local_user()) { - $nurl = normalise_link($profileurl); + $nurl = Strings::normaliseLink($profileurl); $contact = Contact::getDetailsByURL($nurl, local_user()); } if (!count($contact)) { - $nurl = normalise_link($profileurl); + $nurl = Strings::normaliseLink($profileurl); $contact = Contact::getDetailsByURL($nurl); } @@ -104,7 +105,7 @@ function hovercard_content() 'location' => $contact['location'], 'gender' => $contact['gender'], 'about' => $contact['about'], - 'network' => format_network_name($contact['network'], $contact['url']), + 'network' => Strings::formatNetworkName($contact['network'], $contact['url']), 'tags' => $contact['keywords'], 'bd' => $contact['birthday'] <= '0001-01-01' ? '' : $contact['birthday'], 'account_type' => Contact::getAccountType($contact), diff --git a/mod/invite.php b/mod/invite.php index 1e02ae9ca..460a3461d 100644 --- a/mod/invite.php +++ b/mod/invite.php @@ -17,6 +17,7 @@ use Friendica\Database\DBA; use Friendica\Protocol\Email; use Friendica\Util\DateTimeFormat; use Friendica\Util\Security; +use Friendica\Util\Strings; function invite_post(App $a) { @@ -40,7 +41,7 @@ function invite_post(App $a) $recipients = !empty($_POST['recipients']) ? explode("\n", $_POST['recipients']) : []; - $message = !empty($_POST['message']) ? notags(trim($_POST['message'])) : ''; + $message = !empty($_POST['message']) ? Strings::escapeTags(trim($_POST['message'])) : ''; $total = 0; @@ -55,7 +56,7 @@ function invite_post(App $a) foreach ($recipients as $recipient) { $recipient = trim($recipient); - if (! valid_email($recipient)) { + if (!filter_var($recipient, FILTER_VALIDATE_EMAIL)) { notice(L10n::t('%s : Not a valid email address.', $recipient) . EOL); continue; } diff --git a/mod/item.php b/mod/item.php index 739e09ab0..507185e7c 100644 --- a/mod/item.php +++ b/mod/item.php @@ -36,6 +36,7 @@ use Friendica\Protocol\Email; use Friendica\Util\DateTimeFormat; use Friendica\Util\Emailer; use Friendica\Util\Security; +use Friendica\Util\Strings; require_once 'include/enotify.php'; require_once 'include/text.php'; @@ -203,8 +204,8 @@ function item_post(App $a) { $objecttype = $orig_post['object-type']; $app = $orig_post['app']; $categories = $orig_post['file']; - $title = notags(trim($_REQUEST['title'])); - $body = escape_tags(trim($_REQUEST['body'])); + $title = Strings::escapeTags(trim($_REQUEST['title'])); + $body = Strings::escapeHtml(trim($_REQUEST['body'])); $private = $orig_post['private']; $pubmail_enabled = $orig_post['pubmail']; $network = $orig_post['network']; @@ -235,14 +236,14 @@ function item_post(App $a) { $str_contact_deny = perms2str(defaults($_REQUEST, 'contact_deny', '')); } - $title = notags(trim(defaults($_REQUEST, 'title' , ''))); - $location = notags(trim(defaults($_REQUEST, 'location', ''))); - $coord = notags(trim(defaults($_REQUEST, 'coord' , ''))); - $verb = notags(trim(defaults($_REQUEST, 'verb' , ''))); - $emailcc = notags(trim(defaults($_REQUEST, 'emailcc' , ''))); - $body = escape_tags(trim(defaults($_REQUEST, 'body' , ''))); - $network = notags(trim(defaults($_REQUEST, 'network' , Protocol::DFRN))); - $guid = System::createUUID(); + $title = Strings::escapeTags(trim(defaults($_REQUEST, 'title' , ''))); + $location = Strings::escapeTags(trim(defaults($_REQUEST, 'location', ''))); + $coord = Strings::escapeTags(trim(defaults($_REQUEST, 'coord' , ''))); + $verb = Strings::escapeTags(trim(defaults($_REQUEST, 'verb' , ''))); + $emailcc = Strings::escapeTags(trim(defaults($_REQUEST, 'emailcc' , ''))); + $body = Strings::escapeHtml(trim(defaults($_REQUEST, 'body' , ''))); + $network = Strings::escapeTags(trim(defaults($_REQUEST, 'network' , Protocol::DFRN))); + $guid = System::createUUID(); $postopts = defaults($_REQUEST, 'postopts', ''); @@ -347,7 +348,7 @@ function item_post(App $a) { $str_tags = ''; $inform = ''; - $tags = get_tags($body); + $tags = BBCode::getTags($body); // Add a tag if the parent contact is from ActivityPub or OStatus (This will notify them) if ($parent && in_array($thr_parent_contact['network'], [Protocol::OSTATUS, Protocol::ACTIVITYPUB])) { @@ -697,11 +698,10 @@ function item_post(App $a) { killme(); } - if ($orig_post) { - + if ($orig_post) { // Fill the cache field // This could be done in Item::update as well - but we have to check for the existance of some fields. - put_item_in_cache($datarray); + Item::putInCache($datarray); $fields = [ 'title' => $datarray['title'], @@ -817,7 +817,7 @@ function item_post(App $a) { $subject = Email::encodeHeader('[Friendica]' . ' ' . L10n::t('%s posted an update.', $a->user['username']), 'UTF-8'); } $link = '
'; - $html = prepare_body($datarray); + $html = Item::prepareBody($datarray); $message = '' . $link . $html . $disclaimer . ''; $params = [ 'fromName' => $a->user['username'], diff --git a/mod/like.php b/mod/like.php index 296e563bf..97eaca163 100644 --- a/mod/like.php +++ b/mod/like.php @@ -3,6 +3,7 @@ use Friendica\App; use Friendica\Core\System; use Friendica\Model\Item; +use Friendica\Util\Strings; require_once 'include/items.php'; @@ -12,13 +13,13 @@ function like_content(App $a) { } - $verb = notags(trim($_GET['verb'])); + $verb = Strings::escapeTags(trim($_GET['verb'])); if (!$verb) { $verb = 'like'; } - $item_id = (($a->argc > 1) ? notags(trim($a->argv[1])) : 0); + $item_id = (($a->argc > 1) ? Strings::escapeTags(trim($a->argv[1])) : 0); $r = Item::performLike($item_id, $verb); if (!$r) { diff --git a/mod/lostpass.php b/mod/lostpass.php index ae94fbbbe..42a1764bf 100644 --- a/mod/lostpass.php +++ b/mod/lostpass.php @@ -11,6 +11,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model\User; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Strings; require_once 'boot.php'; require_once 'include/enotify.php'; @@ -18,7 +19,7 @@ require_once 'include/text.php'; function lostpass_post(App $a) { - $loginame = notags(trim($_POST['login-name'])); + $loginame = Strings::escapeTags(trim($_POST['login-name'])); if (!$loginame) { $a->internalRedirect(); } @@ -30,7 +31,7 @@ function lostpass_post(App $a) $a->internalRedirect(); } - $pwdreset_token = autoname(12) . mt_rand(1000, 9999); + $pwdreset_token = Strings::getRandomName(12) . mt_rand(1000, 9999); $fields = [ 'pwdreset' => $pwdreset_token, @@ -44,7 +45,7 @@ function lostpass_post(App $a) $sitename = Config::get('config', 'sitename'); $resetlink = System::baseUrl() . '/lostpass/' . $pwdreset_token; - $preamble = deindent(L10n::t(' + $preamble = Strings::deindent(L10n::t(' Dear %1$s, A request was recently received at "%2$s" to reset your account password. In order to confirm this request, please select the verification link @@ -55,7 +56,7 @@ function lostpass_post(App $a) Your password will not be changed unless we can verify that you issued this request.', $user['username'], $sitename)); - $body = deindent(L10n::t(' + $body = Strings::deindent(L10n::t(' Follow this link soon to verify your identity: %1$s @@ -150,13 +151,13 @@ function lostpass_generate_password($user) info("Your password has been reset." . EOL); $sitename = Config::get('config', 'sitename'); - $preamble = deindent(L10n::t(' + $preamble = Strings::deindent(L10n::t(' Dear %1$s, Your password has been changed as requested. Please retain this information for your records ' . "\x28" . 'or change your password immediately to something that you will remember' . "\x29" . '. ', $user['username'])); - $body = deindent(L10n::t(' + $body = Strings::deindent(L10n::t(' Your login details are as follows: Site Location: %1$s diff --git a/mod/maintenance.php b/mod/maintenance.php index a1b032a61..8e0197b86 100644 --- a/mod/maintenance.php +++ b/mod/maintenance.php @@ -6,12 +6,13 @@ use Friendica\App; use Friendica\Core\Config; use Friendica\Core\L10n; use Friendica\Core\Renderer; +use Friendica\Util\Strings; function maintenance_content(App $a) { $reason = Config::get('system', 'maintenance_reason'); - if (substr(normalise_link($reason), 0, 7) == 'http://') { + if (substr(Strings::normaliseLink($reason), 0, 7) == 'http://') { header("HTTP/1.1 307 Temporary Redirect"); header("Location:".$reason); return; diff --git a/mod/match.php b/mod/match.php index e924722aa..0ec753466 100644 --- a/mod/match.php +++ b/mod/match.php @@ -14,6 +14,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Util\Network; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; require_once 'include/text.php'; @@ -76,7 +77,7 @@ function match_content(App $a) $id = 0; foreach ($j->results as $jj) { - $match_nurl = normalise_link($jj->url); + $match_nurl = Strings::normaliseLink($jj->url); $match = q( "SELECT `nurl` FROM `contact` WHERE `uid` = '%d' AND nurl='%s' LIMIT 1", intval(local_user()), diff --git a/mod/message.php b/mod/message.php index 23c08f5a3..7491cd1bc 100644 --- a/mod/message.php +++ b/mod/message.php @@ -18,6 +18,7 @@ use Friendica\Model\Mail; use Friendica\Module\Login; use Friendica\Util\DateTimeFormat; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; use Friendica\Util\Temporal; require_once 'include/conversation.php'; @@ -58,9 +59,9 @@ function message_post(App $a) return; } - $replyto = x($_REQUEST, 'replyto') ? notags(trim($_REQUEST['replyto'])) : ''; - $subject = x($_REQUEST, 'subject') ? notags(trim($_REQUEST['subject'])) : ''; - $body = x($_REQUEST, 'body') ? escape_tags(trim($_REQUEST['body'])) : ''; + $replyto = x($_REQUEST, 'replyto') ? Strings::escapeTags(trim($_REQUEST['replyto'])) : ''; + $subject = x($_REQUEST, 'subject') ? Strings::escapeTags(trim($_REQUEST['subject'])) : ''; + $body = x($_REQUEST, 'body') ? Strings::escapeHtml(trim($_REQUEST['body'])) : ''; $recipient = x($_REQUEST, 'messageto') ? intval($_REQUEST['messageto']) : 0; $ret = Mail::send($recipient, $body, $subject, $replyto); @@ -218,7 +219,7 @@ function message_content(App $a) if (!DBA::isResult($r)) { $r = q("SELECT `name`, `url`, `id` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' LIMIT 1", intval(local_user()), - DBA::escape(normalise_link(base64_decode($a->argv[2]))) + DBA::escape(Strings::normaliseLink(base64_decode($a->argv[2]))) ); } @@ -253,7 +254,7 @@ function message_content(App $a) '$preid' => $preid, '$subject' => L10n::t('Subject:'), '$subjtxt' => x($_REQUEST, 'subject') ? strip_tags($_REQUEST['subject']) : '', - '$text' => x($_REQUEST, 'body') ? escape_tags(htmlspecialchars($_REQUEST['body'])) : '', + '$text' => x($_REQUEST, 'body') ? Strings::escapeHtml(htmlspecialchars($_REQUEST['body'])) : '', '$readonly' => '', '$yourmessage' => L10n::t('Your message:'), '$select' => $select, @@ -462,7 +463,7 @@ function render_messages(array $msg, $t) foreach ($msg as $rr) { if ($rr['unknown']) { $participants = L10n::t("Unknown sender - %s", $rr['from-name']); - } elseif (link_compare($rr['from-url'], $myprofile)) { + } elseif (Strings::compareLink($rr['from-url'], $myprofile)) { $participants = L10n::t("You and %s", $rr['name']); } else { $participants = L10n::t("%s and You", $rr['from-name']); diff --git a/mod/network.php b/mod/network.php index 26458a7a0..81a2f2b2b 100644 --- a/mod/network.php +++ b/mod/network.php @@ -28,6 +28,7 @@ use Friendica\Model\Profile; use Friendica\Module\Login; use Friendica\Util\DateTimeFormat; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; require_once 'include/conversation.php'; require_once 'include/items.php'; @@ -41,7 +42,7 @@ function network_init(App $a) Hook::add('head', __FILE__, 'network_infinite_scroll_head'); - $search = (x($_GET, 'search') ? escape_tags($_GET['search']) : ''); + $search = (x($_GET, 'search') ? Strings::escapeHtml($_GET['search']) : ''); if (($search != '') && !empty($_GET['submit'])) { $a->internalRedirect('search?search=' . urlencode($search)); @@ -518,9 +519,9 @@ function networkThreadedView(App $a, $update, $parent) for ($x = 1; $x < $a->argc; $x ++) { if (is_a_date_arg($a->argv[$x])) { if ($datequery) { - $datequery2 = escape_tags($a->argv[$x]); + $datequery2 = Strings::escapeHtml($a->argv[$x]); } else { - $datequery = escape_tags($a->argv[$x]); + $datequery = Strings::escapeHtml($a->argv[$x]); $_GET['order'] = 'post'; } } elseif (intval($a->argv[$x])) { @@ -536,7 +537,7 @@ function networkThreadedView(App $a, $update, $parent) $star = intval(defaults($_GET, 'star' , 0)); $bmark = intval(defaults($_GET, 'bmark', 0)); $conv = intval(defaults($_GET, 'conv' , 0)); - $order = notags(defaults($_GET, 'order', 'comment')); + $order = Strings::escapeTags(defaults($_GET, 'order', 'comment')); $nets = defaults($_GET, 'nets' , ''); if ($cid) { @@ -649,7 +650,7 @@ function networkThreadedView(App $a, $update, $parent) $sql_post_table .= " INNER JOIN `item` AS `temp1` ON `temp1`.`id` = " . $sql_table . "." . $sql_parent; $sql_extra3 .= " AND (`thread`.`contact-id` IN ($contact_str) "; - $sql_extra3 .= " OR (`thread`.`contact-id` = '$contact_str_self' AND `temp1`.`allow_gid` LIKE '" . protect_sprintf('%<' . intval($gid) . '>%') . "' AND `temp1`.`private`))"; + $sql_extra3 .= " OR (`thread`.`contact-id` = '$contact_str_self' AND `temp1`.`allow_gid` LIKE '" . Strings::protectSprintf('%<' . intval($gid) . '>%') . "' AND `temp1`.`private`))"; } else { $sql_extra3 .= " AND false "; info(L10n::t('Group is empty')); @@ -697,11 +698,11 @@ function networkThreadedView(App $a, $update, $parent) } if ($datequery) { - $sql_extra3 .= protect_sprintf(sprintf(" AND $sql_table.created <= '%s' ", + $sql_extra3 .= Strings::protectSprintf(sprintf(" AND $sql_table.created <= '%s' ", DBA::escape(DateTimeFormat::convert($datequery, 'UTC', date_default_timezone_get())))); } if ($datequery2) { - $sql_extra3 .= protect_sprintf(sprintf(" AND $sql_table.created >= '%s' ", + $sql_extra3 .= Strings::protectSprintf(sprintf(" AND $sql_table.created >= '%s' ", DBA::escape(DateTimeFormat::convert($datequery2, 'UTC', date_default_timezone_get())))); } @@ -882,7 +883,7 @@ function networkThreadedView(App $a, $update, $parent) foreach ($data as $item) { // Don't show hash tag posts from blocked or ignored contacts $condition = ["`nurl` = ? AND `uid` = ? AND (`blocked` OR `readonly`)", - normalise_link($item['author-link']), local_user()]; + Strings::normaliseLink($item['author-link']), local_user()]; if (!DBA::exists('contact', $condition)) { $s[$item['uri']] = $item; } diff --git a/mod/oexchange.php b/mod/oexchange.php index 296869aac..62d0bba07 100644 --- a/mod/oexchange.php +++ b/mod/oexchange.php @@ -8,6 +8,7 @@ use Friendica\Core\Renderer; use Friendica\Core\System; use Friendica\Module\Login; use Friendica\Util\Network; +use Friendica\Util\Strings; function oexchange_init(App $a) { @@ -33,13 +34,13 @@ function oexchange_content(App $a) { } $url = ((x($_REQUEST,'url') && strlen($_REQUEST['url'])) - ? urlencode(notags(trim($_REQUEST['url']))) : ''); + ? urlencode(Strings::escapeTags(trim($_REQUEST['url']))) : ''); $title = ((x($_REQUEST,'title') && strlen($_REQUEST['title'])) - ? '&title=' . urlencode(notags(trim($_REQUEST['title']))) : ''); + ? '&title=' . urlencode(Strings::escapeTags(trim($_REQUEST['title']))) : ''); $description = ((x($_REQUEST,'description') && strlen($_REQUEST['description'])) - ? '&description=' . urlencode(notags(trim($_REQUEST['description']))) : ''); + ? '&description=' . urlencode(Strings::escapeTags(trim($_REQUEST['description']))) : ''); $tags = ((x($_REQUEST,'tags') && strlen($_REQUEST['tags'])) - ? '&tags=' . urlencode(notags(trim($_REQUEST['tags']))) : ''); + ? '&tags=' . urlencode(Strings::escapeTags(trim($_REQUEST['tags']))) : ''); $s = Network::fetchUrl(System::baseUrl() . '/parse_url?f=&url=' . $url . $title . $description . $tags); diff --git a/mod/openid.php b/mod/openid.php index d1404ba80..209960ee5 100644 --- a/mod/openid.php +++ b/mod/openid.php @@ -10,6 +10,7 @@ use Friendica\Core\L10n; use Friendica\Core\Logger; use Friendica\Core\System; use Friendica\Database\DBA; +use Friendica\Util\Strings; function openid_content(App $a) { @@ -43,7 +44,7 @@ function openid_content(App $a) { AND `blocked` = 0 AND `account_expired` = 0 AND `account_removed` = 0 AND `verified` = 1 LIMIT 1", - DBA::escape($authid), DBA::escape(normalise_openid($authid)) + DBA::escape($authid), DBA::escape(Strings::normaliseOpenID($authid)) ); if (DBA::isResult($r)) { @@ -74,16 +75,16 @@ function openid_content(App $a) { if (is_array($attr) && count($attr)) { foreach ($attr as $k => $v) { if ($k === 'namePerson/friendly') { - $nick = notags(trim($v)); + $nick = Strings::escapeTags(trim($v)); } if($k === 'namePerson/first') { - $first = notags(trim($v)); + $first = Strings::escapeTags(trim($v)); } if($k === 'namePerson') { - $args .= '&username=' . urlencode(notags(trim($v))); + $args .= '&username=' . urlencode(Strings::escapeTags(trim($v))); } if ($k === 'contact/email') { - $args .= '&email=' . urlencode(notags(trim($v))); + $args .= '&email=' . urlencode(Strings::escapeTags(trim($v))); } if ($k === 'media/image/aspect11') { $photosq = bin2hex(trim($v)); @@ -107,7 +108,7 @@ function openid_content(App $a) { $args .= '&photo=' . urlencode($photo); } - $args .= '&openid_url=' . urlencode(notags(trim($authid))); + $args .= '&openid_url=' . urlencode(Strings::escapeTags(trim($authid))); $a->internalRedirect('register?' . $args); diff --git a/mod/photos.php b/mod/photos.php index 7a49f061a..f07815c25 100644 --- a/mod/photos.php +++ b/mod/photos.php @@ -31,6 +31,7 @@ use Friendica\Util\DateTimeFormat; use Friendica\Util\Map; use Friendica\Util\Security; use Friendica\Util\Temporal; +use Friendica\Util\Strings; use Friendica\Util\XML; require_once 'include/items.php'; @@ -222,7 +223,7 @@ function photos_post(App $a) } // RENAME photo album - $newalbum = notags(trim($_POST['albumname'])); + $newalbum = Strings::escapeTags(trim($_POST['albumname'])); if ($newalbum != $album) { q("UPDATE `photo` SET `album` = '%s' WHERE `album` = '%s' AND `uid` = %d", DBA::escape($newalbum), @@ -365,11 +366,11 @@ function photos_post(App $a) } if ($a->argc > 2 && (!empty($_POST['desc']) || !empty($_POST['newtag']) || !empty($_POST['albname']) !== false)) { - $desc = !empty($_POST['desc']) ? notags(trim($_POST['desc'])) : ''; - $rawtags = !empty($_POST['newtag']) ? notags(trim($_POST['newtag'])) : ''; + $desc = !empty($_POST['desc']) ? Strings::escapeTags(trim($_POST['desc'])) : ''; + $rawtags = !empty($_POST['newtag']) ? Strings::escapeTags(trim($_POST['newtag'])) : ''; $item_id = !empty($_POST['item_id']) ? intval($_POST['item_id']) : 0; - $albname = !empty($_POST['albname']) ? notags(trim($_POST['albname'])) : ''; - $origaname = !empty($_POST['origaname']) ? notags(trim($_POST['origaname'])) : ''; + $albname = !empty($_POST['albname']) ? Strings::escapeTags(trim($_POST['albname'])) : ''; + $origaname = !empty($_POST['origaname']) ? Strings::escapeTags(trim($_POST['origaname'])) : ''; $str_group_allow = !empty($_POST['group_allow']) ? perms2str($_POST['group_allow']) : ''; $str_contact_allow = !empty($_POST['contact_allow']) ? perms2str($_POST['contact_allow']) : ''; @@ -524,7 +525,7 @@ function photos_post(App $a) } $taginfo = []; - $tags = get_tags($rawtags); + $tags = BBCode::getTags($rawtags); if (count($tags)) { foreach ($tags as $tag) { @@ -707,8 +708,8 @@ function photos_post(App $a) Addon::callHooks('photo_post_init', $_POST); // Determine the album to use - $album = !empty($_REQUEST['album']) ? notags(trim($_REQUEST['album'])) : ''; - $newalbum = !empty($_REQUEST['newalbum']) ? notags(trim($_REQUEST['newalbum'])) : ''; + $album = !empty($_REQUEST['album']) ? Strings::escapeTags(trim($_REQUEST['album'])) : ''; + $newalbum = !empty($_REQUEST['newalbum']) ? Strings::escapeTags(trim($_REQUEST['newalbum'])) : ''; Logger::log('mod/photos.php: photos_post(): album= ' . $album . ' newalbum= ' . $newalbum , Logger::DEBUG); @@ -779,7 +780,7 @@ function photos_post(App $a) notice(L10n::t('Image exceeds size limit of %s', ini_get('upload_max_filesize')) . EOL); break; case UPLOAD_ERR_FORM_SIZE: - notice(L10n::t('Image exceeds size limit of %s', formatBytes(defaults($_REQUEST, 'MAX_FILE_SIZE', 0))) . EOL); + notice(L10n::t('Image exceeds size limit of %s', Strings::formatBytes(defaults($_REQUEST, 'MAX_FILE_SIZE', 0))) . EOL); break; case UPLOAD_ERR_PARTIAL: notice(L10n::t('Image upload didn\'t complete, please try again') . EOL); @@ -808,7 +809,7 @@ function photos_post(App $a) $maximagesize = Config::get('system', 'maximagesize'); if ($maximagesize && ($filesize > $maximagesize)) { - notice(L10n::t('Image exceeds size limit of %s', formatBytes($maximagesize)) . EOL); + notice(L10n::t('Image exceeds size limit of %s', Strings::formatBytes($maximagesize)) . EOL); @unlink($src); $foo = 0; Addon::callHooks('photo_post_end', $foo); diff --git a/mod/poco.php b/mod/poco.php index 08677ef8d..cc2493c08 100644 --- a/mod/poco.php +++ b/mod/poco.php @@ -15,6 +15,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Protocol\PortableContact; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Strings; use Friendica\Util\XML; function poco_init(App $a) { @@ -25,7 +26,7 @@ function poco_init(App $a) { } if ($a->argc > 1) { - $user = notags(trim($a->argv[1])); + $user = Strings::escapeTags(trim($a->argv[1])); } if (empty($user)) { $c = q("SELECT * FROM `pconfig` WHERE `cat` = 'system' AND `k` = 'suggestme' AND `v` = 1"); diff --git a/mod/poke.php b/mod/poke.php index e8c43213a..6f09b348c 100644 --- a/mod/poke.php +++ b/mod/poke.php @@ -22,6 +22,7 @@ use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\Item; +use Friendica\Util\Strings; use Friendica\Util\XML; require_once 'include/items.php'; @@ -38,7 +39,7 @@ function poke_init(App $a) return; } - $verb = notags(trim($_GET['verb'])); + $verb = Strings::escapeTags(trim($_GET['verb'])); $verbs = L10n::getPokeVerbs(); diff --git a/mod/profile.php b/mod/profile.php index cfbe07dad..59f3bb5ae 100644 --- a/mod/profile.php +++ b/mod/profile.php @@ -24,6 +24,7 @@ use Friendica\Protocol\ActivityPub; use Friendica\Protocol\DFRN; use Friendica\Util\DateTimeFormat; use Friendica\Util\Security; +use Friendica\Util\Strings; use Friendica\Util\XML; function profile_init(App $a) @@ -114,9 +115,9 @@ function profile_content(App $a, $update = 0) for ($x = 2; $x < $a->argc; $x ++) { if (is_a_date_arg($a->argv[$x])) { if ($datequery) { - $datequery2 = escape_tags($a->argv[$x]); + $datequery2 = Strings::escapeHtml($a->argv[$x]); } else { - $datequery = escape_tags($a->argv[$x]); + $datequery = Strings::escapeHtml($a->argv[$x]); } } else { $category = $a->argv[$x]; @@ -193,7 +194,7 @@ function profile_content(App $a, $update = 0) if (!$update) { $tab = false; if (!empty($_GET['tab'])) { - $tab = notags(trim($_GET['tab'])); + $tab = Strings::escapeTags(trim($_GET['tab'])); } $o .= Profile::getTabs($a, $is_owner, $a->profile['nickname']); @@ -272,19 +273,19 @@ function profile_content(App $a, $update = 0) if (!empty($category)) { $sql_post_table = sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", - DBA::escape(protect_sprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($a->profile['profile_uid'])); + DBA::escape(Strings::protectSprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($a->profile['profile_uid'])); } if (!empty($hashtags)) { $sql_post_table .= sprintf("INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", - DBA::escape(protect_sprintf($hashtags)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), intval($a->profile['profile_uid'])); + DBA::escape(Strings::protectSprintf($hashtags)), intval(TERM_OBJ_POST), intval(TERM_HASHTAG), intval($a->profile['profile_uid'])); } if (!empty($datequery)) { - $sql_extra2 .= protect_sprintf(sprintf(" AND `thread`.`created` <= '%s' ", DBA::escape(DateTimeFormat::convert($datequery, 'UTC', date_default_timezone_get())))); + $sql_extra2 .= Strings::protectSprintf(sprintf(" AND `thread`.`created` <= '%s' ", DBA::escape(DateTimeFormat::convert($datequery, 'UTC', date_default_timezone_get())))); } if (!empty($datequery2)) { - $sql_extra2 .= protect_sprintf(sprintf(" AND `thread`.`created` >= '%s' ", DBA::escape(DateTimeFormat::convert($datequery2, 'UTC', date_default_timezone_get())))); + $sql_extra2 .= Strings::protectSprintf(sprintf(" AND `thread`.`created` >= '%s' ", DBA::escape(DateTimeFormat::convert($datequery2, 'UTC', date_default_timezone_get())))); } // Does the profile page belong to a forum? diff --git a/mod/profile_photo.php b/mod/profile_photo.php index 3304e3cab..d8e236a73 100644 --- a/mod/profile_photo.php +++ b/mod/profile_photo.php @@ -16,6 +16,7 @@ use Friendica\Model\Photo; use Friendica\Model\Profile; use Friendica\Object\Image; use Friendica\Util\Security; +use Friendica\Util\Strings; function profile_photo_init(App $a) { @@ -151,7 +152,7 @@ function profile_photo_post(App $a) $maximagesize = Config::get('system', 'maximagesize'); if (($maximagesize) && ($filesize > $maximagesize)) { - notice(L10n::t('Image exceeds size limit of %s', formatBytes($maximagesize)) . EOL); + notice(L10n::t('Image exceeds size limit of %s', Strings::formatBytes($maximagesize)) . EOL); @unlink($src); return; } diff --git a/mod/profiles.php b/mod/profiles.php index a535f2fc2..459a1c5e7 100644 --- a/mod/profiles.php +++ b/mod/profiles.php @@ -22,6 +22,7 @@ use Friendica\Model\Profile; use Friendica\Module\Login; use Friendica\Network\Probe; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Strings; use Friendica\Util\Temporal; function profiles_init(App $a) { @@ -201,13 +202,13 @@ function profiles_post(App $a) { $is_default = (($orig[0]['is-default']) ? 1 : 0); - $profile_name = notags(trim($_POST['profile_name'])); + $profile_name = Strings::escapeTags(trim($_POST['profile_name'])); if (! strlen($profile_name)) { notice(L10n::t('Profile Name is required.') . EOL); return; } - $dob = $_POST['dob'] ? escape_tags(trim($_POST['dob'])) : '0000-00-00'; + $dob = $_POST['dob'] ? Strings::escapeHtml(trim($_POST['dob'])) : '0000-00-00'; $y = substr($dob, 0, 4); if ((! ctype_digit($y)) || ($y < 1900)) { @@ -228,7 +229,7 @@ function profiles_post(App $a) { } } - $name = notags(trim($_POST['name'])); + $name = Strings::escapeTags(trim($_POST['name'])); if (! strlen($name)) { $name = '[No Name]'; @@ -238,19 +239,19 @@ function profiles_post(App $a) { $namechanged = true; } - $pdesc = notags(trim($_POST['pdesc'])); - $gender = notags(trim($_POST['gender'])); - $address = notags(trim($_POST['address'])); - $locality = notags(trim($_POST['locality'])); - $region = notags(trim($_POST['region'])); - $postal_code = notags(trim($_POST['postal_code'])); - $country_name = notags(trim($_POST['country_name'])); - $pub_keywords = profile_clean_keywords(notags(trim($_POST['pub_keywords']))); - $prv_keywords = profile_clean_keywords(notags(trim($_POST['prv_keywords']))); - $marital = notags(trim($_POST['marital'])); - $howlong = notags(trim($_POST['howlong'])); + $pdesc = Strings::escapeTags(trim($_POST['pdesc'])); + $gender = Strings::escapeTags(trim($_POST['gender'])); + $address = Strings::escapeTags(trim($_POST['address'])); + $locality = Strings::escapeTags(trim($_POST['locality'])); + $region = Strings::escapeTags(trim($_POST['region'])); + $postal_code = Strings::escapeTags(trim($_POST['postal_code'])); + $country_name = Strings::escapeTags(trim($_POST['country_name'])); + $pub_keywords = profile_clean_keywords(Strings::escapeTags(trim($_POST['pub_keywords']))); + $prv_keywords = profile_clean_keywords(Strings::escapeTags(trim($_POST['prv_keywords']))); + $marital = Strings::escapeTags(trim($_POST['marital'])); + $howlong = Strings::escapeTags(trim($_POST['howlong'])); - $with = ((x($_POST,'with')) ? notags(trim($_POST['with'])) : ''); + $with = ((x($_POST,'with')) ? Strings::escapeTags(trim($_POST['with'])) : ''); if (! strlen($howlong)) { $howlong = DBA::NULL_DATETIME; @@ -311,30 +312,30 @@ function profiles_post(App $a) { } /// @TODO Not flexible enough for later expansion, let's have more OOP here - $sexual = notags(trim($_POST['sexual'])); - $xmpp = notags(trim($_POST['xmpp'])); - $homepage = notags(trim($_POST['homepage'])); + $sexual = Strings::escapeTags(trim($_POST['sexual'])); + $xmpp = Strings::escapeTags(trim($_POST['xmpp'])); + $homepage = Strings::escapeTags(trim($_POST['homepage'])); if ((strpos($homepage, 'http') !== 0) && (strlen($homepage))) { // neither http nor https in URL, add them $homepage = 'http://'.$homepage; } - $hometown = notags(trim($_POST['hometown'])); - $politic = notags(trim($_POST['politic'])); - $religion = notags(trim($_POST['religion'])); + $hometown = Strings::escapeTags(trim($_POST['hometown'])); + $politic = Strings::escapeTags(trim($_POST['politic'])); + $religion = Strings::escapeTags(trim($_POST['religion'])); - $likes = escape_tags(trim($_POST['likes'])); - $dislikes = escape_tags(trim($_POST['dislikes'])); + $likes = Strings::escapeHtml(trim($_POST['likes'])); + $dislikes = Strings::escapeHtml(trim($_POST['dislikes'])); - $about = escape_tags(trim($_POST['about'])); - $interest = escape_tags(trim($_POST['interest'])); - $contact = escape_tags(trim($_POST['contact'])); - $music = escape_tags(trim($_POST['music'])); - $book = escape_tags(trim($_POST['book'])); - $tv = escape_tags(trim($_POST['tv'])); - $film = escape_tags(trim($_POST['film'])); - $romance = escape_tags(trim($_POST['romance'])); - $work = escape_tags(trim($_POST['work'])); - $education = escape_tags(trim($_POST['education'])); + $about = Strings::escapeHtml(trim($_POST['about'])); + $interest = Strings::escapeHtml(trim($_POST['interest'])); + $contact = Strings::escapeHtml(trim($_POST['contact'])); + $music = Strings::escapeHtml(trim($_POST['music'])); + $book = Strings::escapeHtml(trim($_POST['book'])); + $tv = Strings::escapeHtml(trim($_POST['tv'])); + $film = Strings::escapeHtml(trim($_POST['film'])); + $romance = Strings::escapeHtml(trim($_POST['romance'])); + $work = Strings::escapeHtml(trim($_POST['work'])); + $education = Strings::escapeHtml(trim($_POST['education'])); $hide_friends = (($_POST['hide-friends'] == 1) ? 1: 0); diff --git a/mod/pubsub.php b/mod/pubsub.php index e14d50086..f0a8d463c 100644 --- a/mod/pubsub.php +++ b/mod/pubsub.php @@ -6,6 +6,7 @@ use Friendica\Core\Protocol; use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Protocol\OStatus; +use Friendica\Util\Strings; require_once 'include/items.php'; @@ -30,15 +31,15 @@ function hub_post_return() function pubsub_init(App $a) { - $nick = (($a->argc > 1) ? notags(trim($a->argv[1])) : ''); + $nick = (($a->argc > 1) ? Strings::escapeTags(trim($a->argv[1])) : ''); $contact_id = (($a->argc > 2) ? intval($a->argv[2]) : 0 ); if ($_SERVER['REQUEST_METHOD'] === 'GET') { - $hub_mode = notags(trim(defaults($_GET, 'hub_mode', ''))); - $hub_topic = notags(trim(defaults($_GET, 'hub_topic', ''))); - $hub_challenge = notags(trim(defaults($_GET, 'hub_challenge', ''))); - $hub_lease = notags(trim(defaults($_GET, 'hub_lease_seconds', ''))); - $hub_verify = notags(trim(defaults($_GET, 'hub_verify_token', ''))); + $hub_mode = Strings::escapeTags(trim(defaults($_GET, 'hub_mode', ''))); + $hub_topic = Strings::escapeTags(trim(defaults($_GET, 'hub_topic', ''))); + $hub_challenge = Strings::escapeTags(trim(defaults($_GET, 'hub_challenge', ''))); + $hub_lease = Strings::escapeTags(trim(defaults($_GET, 'hub_lease_seconds', ''))); + $hub_verify = Strings::escapeTags(trim(defaults($_GET, 'hub_verify_token', ''))); Logger::log('Subscription from ' . $_SERVER['REMOTE_ADDR'] . ' Mode: ' . $hub_mode . ' Nick: ' . $nick); Logger::log('Data: ' . print_r($_GET,true), Logger::DATA); @@ -63,7 +64,7 @@ function pubsub_init(App $a) hub_return(false, ''); } - if (!empty($hub_topic) && !link_compare($hub_topic, $contact['poll'])) { + if (!empty($hub_topic) && !Strings::compareLink($hub_topic, $contact['poll'])) { Logger::log('Hub topic ' . $hub_topic . ' != ' . $contact['poll']); hub_return(false, ''); } @@ -91,7 +92,7 @@ function pubsub_post(App $a) Logger::log('Feed arrived from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $a->cmd . ' with user-agent: ' . $_SERVER['HTTP_USER_AGENT']); Logger::log('Data: ' . $xml, Logger::DATA); - $nick = (($a->argc > 1) ? notags(trim($a->argv[1])) : ''); + $nick = (($a->argc > 1) ? Strings::escapeTags(trim($a->argv[1])) : ''); $contact_id = (($a->argc > 2) ? intval($a->argv[2]) : 0 ); $importer = DBA::selectFirst('user', [], ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false]); diff --git a/mod/pubsubhubbub.php b/mod/pubsubhubbub.php index ea27f0482..d38cbe227 100644 --- a/mod/pubsubhubbub.php +++ b/mod/pubsubhubbub.php @@ -7,9 +7,10 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model\PushSubscriber; use Friendica\Util\Network; +use Friendica\Util\Strings; function post_var($name) { - return (x($_POST, $name)) ? notags(trim($_POST[$name])) : ''; + return (x($_POST, $name)) ? Strings::escapeTags(trim($_POST[$name])) : ''; } function pubsubhubbub_init(App $a) { @@ -87,13 +88,13 @@ function pubsubhubbub_init(App $a) { // sanity check that topic URLs are the same $hub_topic2 = str_replace('/feed/', '/dfrn_poll/', $hub_topic); - if (!link_compare($hub_topic, $contact['poll']) && !link_compare($hub_topic2, $contact['poll'])) { + if (!Strings::compareLink($hub_topic, $contact['poll']) && !Strings::compareLink($hub_topic2, $contact['poll'])) { Logger::log('Hub topic ' . $hub_topic . ' != ' . $contact['poll']); System::httpExit(404); } // do subscriber verification according to the PuSH protocol - $hub_challenge = random_string(40); + $hub_challenge = Strings::getRandomHex(40); $params = 'hub.mode=' . ($subscribe == 1 ? 'subscribe' : 'unsubscribe') . '&hub.topic=' . urlencode($hub_topic) . diff --git a/mod/redir.php b/mod/redir.php index 088a5f55e..f22af545f 100644 --- a/mod/redir.php +++ b/mod/redir.php @@ -8,6 +8,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\Profile; +use Friendica\Util\Strings; function redir_init(App $a) { @@ -93,7 +94,7 @@ function redir_init(App $a) { $dfrn_id = '0:' . $orig_id; } - $sec = random_string(); + $sec = Strings::getRandomHex(); $fields = ['uid' => local_user(), 'cid' => $cid, 'dfrn_id' => $dfrn_id, 'sec' => $sec, 'expire' => time() + 45]; @@ -115,7 +116,7 @@ function redir_init(App $a) { if (!empty($url)) { $my_profile = Profile::getMyURL(); - if (!empty($my_profile) && !link_compare($my_profile, $url)) { + if (!empty($my_profile) && !Strings::compareLink($my_profile, $url)) { $separator = strpos($url, '?') ? '&' : '?'; $url .= $separator . 'zrl=' . urlencode($my_profile); diff --git a/mod/register.php b/mod/register.php index d8231bd21..2b0d87ca9 100644 --- a/mod/register.php +++ b/mod/register.php @@ -16,6 +16,7 @@ use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Model; use Friendica\Module\Tos; +use Friendica\Util\Strings; require_once 'include/enotify.php'; @@ -83,7 +84,7 @@ function register_post(App $a) $using_invites = Config::get('system', 'invitation_only'); $num_invites = Config::get('system', 'number_invites'); - $invite_id = ((x($_POST, 'invite_id')) ? notags(trim($_POST['invite_id'])) : ''); + $invite_id = ((x($_POST, 'invite_id')) ? Strings::escapeTags(trim($_POST['invite_id'])) : ''); if (intval(Config::get('config', 'register_policy')) === REGISTER_OPEN) { if ($using_invites && $invite_id) { diff --git a/mod/removeme.php b/mod/removeme.php index c2ceb7d4c..44671ef07 100644 --- a/mod/removeme.php +++ b/mod/removeme.php @@ -68,7 +68,7 @@ function removeme_content(App $a) $a->internalRedirect(); } - $hash = random_string(); + $hash = Strings::getRandomHex(); require_once("mod/settings.php"); settings_init($a); diff --git a/mod/salmon.php b/mod/salmon.php index 23e4e8884..02339c777 100644 --- a/mod/salmon.php +++ b/mod/salmon.php @@ -12,6 +12,7 @@ use Friendica\Model\Contact; use Friendica\Protocol\OStatus; use Friendica\Protocol\Salmon; use Friendica\Util\Crypto; +use Friendica\Util\Strings; require_once 'include/items.php'; @@ -23,7 +24,7 @@ function salmon_post(App $a, $xml = '') { Logger::log('new salmon ' . $xml, Logger::DATA); - $nick = (($a->argc > 1) ? notags(trim($a->argv[1])) : ''); + $nick = (($a->argc > 1) ? Strings::escapeTags(trim($a->argv[1])) : ''); $mentions = (($a->argc > 2 && $a->argv[2] === 'mention') ? true : false); $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1", @@ -57,7 +58,7 @@ function salmon_post(App $a, $xml = '') { // Stash the signature away for now. We have to find their key or it won't be good for anything. - $signature = base64url_decode($base->sig); + $signature = Strings::base64UrlDecode($base->sig); // unpack the data @@ -76,13 +77,13 @@ function salmon_post(App $a, $xml = '') { $stnet_signed_data = $data; - $signed_data = $data . '.' . base64url_encode($type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($alg); + $signed_data = $data . '.' . Strings::base64UrlEncode($type) . '.' . Strings::base64UrlEncode($encoding) . '.' . Strings::base64UrlEncode($alg); $compliant_format = str_replace('=', '', $signed_data); // decode the data - $data = base64url_decode($data); + $data = Strings::base64UrlDecode($data); $author = OStatus::salmonAuthor($data, $importer); $author_link = $author["author-link"]; @@ -105,8 +106,8 @@ function salmon_post(App $a, $xml = '') { $key_info = explode('.',$key); - $m = base64url_decode($key_info[1]); - $e = base64url_decode($key_info[2]); + $m = Strings::base64UrlDecode($key_info[1]); + $e = Strings::base64UrlDecode($key_info[2]); Logger::log('key details: ' . print_r($key_info,true), Logger::DEBUG); @@ -149,9 +150,9 @@ function salmon_post(App $a, $xml = '') { AND `uid` = %d LIMIT 1", DBA::escape(Protocol::OSTATUS), DBA::escape(Protocol::DFRN), - DBA::escape(normalise_link($author_link)), + DBA::escape(Strings::normaliseLink($author_link)), DBA::escape($author_link), - DBA::escape(normalise_link($author_link)), + DBA::escape(Strings::normaliseLink($author_link)), intval($importer['uid']) ); diff --git a/mod/search.php b/mod/search.php index 809a6f7e8..f552ad43c 100644 --- a/mod/search.php +++ b/mod/search.php @@ -16,6 +16,7 @@ use Friendica\Core\Renderer; use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model\Item; +use Friendica\Util\Strings; require_once 'include/conversation.php'; require_once 'mod/dirfind.php'; @@ -23,7 +24,7 @@ require_once 'mod/dirfind.php'; function search_saved_searches() { $o = ''; - $search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); + $search = ((x($_GET,'search')) ? Strings::escapeTags(trim(rawurldecode($_GET['search']))) : ''); if (!Feature::isEnabled(local_user(),'savedsearch')) return $o; @@ -62,7 +63,7 @@ function search_saved_searches() { function search_init(App $a) { - $search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); + $search = ((x($_GET,'search')) ? Strings::escapeTags(trim(rawurldecode($_GET['search']))) : ''); if (local_user()) { if (x($_GET,'save') && $search) { @@ -149,14 +150,14 @@ function search_content(App $a) { $search = ''; if (x($a->data,'search')) - $search = notags(trim($a->data['search'])); + $search = Strings::escapeTags(trim($a->data['search'])); else - $search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); + $search = ((x($_GET,'search')) ? Strings::escapeTags(trim(rawurldecode($_GET['search']))) : ''); $tag = false; if (x($_GET,'tag')) { $tag = true; - $search = (x($_GET,'tag') ? '#' . notags(trim(rawurldecode($_GET['tag']))) : ''); + $search = (x($_GET,'tag') ? '#' . Strings::escapeTags(trim(rawurldecode($_GET['tag']))) : ''); } // contruct a wrapper for the search header diff --git a/mod/settings.php b/mod/settings.php index d88628840..857012048 100644 --- a/mod/settings.php +++ b/mod/settings.php @@ -25,6 +25,7 @@ use Friendica\Model\User; use Friendica\Module\Login; use Friendica\Protocol\Email; use Friendica\Util\Network; +use Friendica\Util\Strings; use Friendica\Util\Temporal; function get_theme_config_file($theme) @@ -314,8 +315,8 @@ function settings_post(App $a) if (($a->argc > 1) && ($a->argv[1] === 'display')) { BaseModule::checkFormSecurityTokenRedirectOnError('/settings/display', 'settings_display'); - $theme = x($_POST, 'theme') ? notags(trim($_POST['theme'])) : $a->user['theme']; - $mobile_theme = x($_POST, 'mobile_theme') ? notags(trim($_POST['mobile_theme'])) : ''; + $theme = x($_POST, 'theme') ? Strings::escapeTags(trim($_POST['theme'])) : $a->user['theme']; + $mobile_theme = x($_POST, 'mobile_theme') ? Strings::escapeTags(trim($_POST['mobile_theme'])) : ''; $nosmile = x($_POST, 'nosmile') ? intval($_POST['nosmile']) : 0; $first_day_of_week = x($_POST, 'first_day_of_week') ? intval($_POST['first_day_of_week']) : 0; $noinfo = x($_POST, 'noinfo') ? intval($_POST['noinfo']) : 0; @@ -422,13 +423,13 @@ function settings_post(App $a) } } - $username = ((x($_POST, 'username')) ? notags(trim($_POST['username'])) : ''); - $email = ((x($_POST, 'email')) ? notags(trim($_POST['email'])) : ''); - $timezone = ((x($_POST, 'timezone')) ? notags(trim($_POST['timezone'])) : ''); - $language = ((x($_POST, 'language')) ? notags(trim($_POST['language'])) : ''); + $username = ((x($_POST, 'username')) ? Strings::escapeTags(trim($_POST['username'])) : ''); + $email = ((x($_POST, 'email')) ? Strings::escapeTags(trim($_POST['email'])) : ''); + $timezone = ((x($_POST, 'timezone')) ? Strings::escapeTags(trim($_POST['timezone'])) : ''); + $language = ((x($_POST, 'language')) ? Strings::escapeTags(trim($_POST['language'])) : ''); - $defloc = ((x($_POST, 'defloc')) ? notags(trim($_POST['defloc'])) : ''); - $openid = ((x($_POST, 'openid_url')) ? notags(trim($_POST['openid_url'])) : ''); + $defloc = ((x($_POST, 'defloc')) ? Strings::escapeTags(trim($_POST['defloc'])) : ''); + $openid = ((x($_POST, 'openid_url')) ? Strings::escapeTags(trim($_POST['openid_url'])) : ''); $maxreq = ((x($_POST, 'maxreq')) ? intval($_POST['maxreq']) : 0); $expire = ((x($_POST, 'expire')) ? intval($_POST['expire']) : 0); $def_gid = ((x($_POST, 'group-selection')) ? intval($_POST['group-selection']) : 0); @@ -516,7 +517,7 @@ function settings_post(App $a) $email = $a->user['email']; } // check the email is valid - if (!valid_email($email)) { + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $err .= L10n::t('Invalid email.'); } // ensure new email is not the admin mail @@ -544,7 +545,7 @@ function settings_post(App $a) $str_contact_deny = !empty($_POST['contact_deny']) ? perms2str($_POST['contact_deny']) : ''; $openidserver = $a->user['openidserver']; - //$openid = normalise_openid($openid); + //$openid = Strings::normaliseOpenID($openid); // If openid has changed or if there's an openid but no openidserver, try and discover it. if ($openid != $a->user['openid'] || (strlen($openid) && (!strlen($openidserver)))) { diff --git a/mod/subthread.php b/mod/subthread.php index 425306b6f..b287957b2 100644 --- a/mod/subthread.php +++ b/mod/subthread.php @@ -10,6 +10,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model\Item; use Friendica\Util\Security; +use Friendica\Util\Strings; use Friendica\Util\XML; require_once 'include/items.php'; @@ -22,7 +23,7 @@ function subthread_content(App $a) { $activity = ACTIVITY_FOLLOW; - $item_id = (($a->argc > 1) ? notags(trim($a->argv[1])) : 0); + $item_id = (($a->argc > 1) ? Strings::escapeTags(trim($a->argv[1])) : 0); $condition = ["`parent` = ? OR `parent-uri` = ? AND `parent` = `id`", $item_id, $item_id]; $item = Item::selectFirst([], $condition); diff --git a/mod/tagger.php b/mod/tagger.php index dd859e61c..6c3c6157a 100644 --- a/mod/tagger.php +++ b/mod/tagger.php @@ -10,6 +10,7 @@ use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\Item; +use Friendica\Util\Strings; use Friendica\Util\XML; require_once 'include/items.php'; @@ -20,7 +21,7 @@ function tagger_content(App $a) { return; } - $term = notags(trim($_GET['term'])); + $term = Strings::escapeTags(trim($_GET['term'])); // no commas allowed $term = str_replace([',',' '],['','_'],$term); @@ -28,7 +29,7 @@ function tagger_content(App $a) { return; } - $item_id = (($a->argc > 1) ? notags(trim($a->argv[1])) : 0); + $item_id = (($a->argc > 1) ? Strings::escapeTags(trim($a->argv[1])) : 0); Logger::log('tagger: tag ' . $term . ' item ' . $item_id); diff --git a/mod/tagrm.php b/mod/tagrm.php index 2678748de..3785d8750 100644 --- a/mod/tagrm.php +++ b/mod/tagrm.php @@ -9,6 +9,7 @@ use Friendica\Core\L10n; use Friendica\Database\DBA; use Friendica\Model\Item; use Friendica\Model\Term; +use Friendica\Util\Strings; function tagrm_post(App $a) { @@ -22,7 +23,7 @@ function tagrm_post(App $a) $tags = []; foreach (defaults($_POST, 'tag', []) as $tag) { - $tags[] = hex2bin(notags(trim($tag))); + $tags[] = hex2bin(Strings::escapeTags(trim($tag))); } $item_id = defaults($_POST,'item', 0); @@ -73,7 +74,7 @@ function tagrm_content(App $a) } if ($a->argc == 3) { - update_tags($a->argv[1], [notags(trim(hex2bin($a->argv[2])))]); + update_tags($a->argv[1], [Strings::escapeTags(trim(hex2bin($a->argv[2])))]); $a->internalRedirect($_SESSION['photo_return']); } diff --git a/mod/unfollow.php b/mod/unfollow.php index 372364810..9b1049286 100644 --- a/mod/unfollow.php +++ b/mod/unfollow.php @@ -12,6 +12,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\Profile; use Friendica\Model\User; +use Friendica\Util\Strings; function unfollow_post(App $a) { @@ -24,11 +25,11 @@ function unfollow_post(App $a) } $uid = local_user(); - $url = notags(trim(defaults($_REQUEST, 'url', ''))); + $url = Strings::escapeTags(trim(defaults($_REQUEST, 'url', ''))); $condition = ["`uid` = ? AND (`rel` = ? OR `rel` = ?) AND (`nurl` = ? OR `alias` = ? OR `alias` = ?)", - $uid, Contact::SHARING, Contact::FRIEND, normalise_link($url), - normalise_link($url), $url]; + $uid, Contact::SHARING, Contact::FRIEND, Strings::normaliseLink($url), + Strings::normaliseLink($url), $url]; $contact = DBA::selectFirst('contact', [], $condition); if (!DBA::isResult($contact)) { @@ -79,11 +80,11 @@ function unfollow_content(App $a) } $uid = local_user(); - $url = notags(trim($_REQUEST['url'])); + $url = Strings::escapeTags(trim($_REQUEST['url'])); $condition = ["`uid` = ? AND (`rel` = ? OR `rel` = ?) AND (`nurl` = ? OR `alias` = ? OR `alias` = ?)", - local_user(), Contact::SHARING, Contact::FRIEND, normalise_link($url), - normalise_link($url), $url]; + local_user(), Contact::SHARING, Contact::FRIEND, Strings::normaliseLink($url), + Strings::normaliseLink($url), $url]; $contact = DBA::selectFirst('contact', ['url', 'network', 'addr', 'name'], $condition); diff --git a/mod/wall_attach.php b/mod/wall_attach.php index 2a3038e8f..b4254ba64 100644 --- a/mod/wall_attach.php +++ b/mod/wall_attach.php @@ -11,6 +11,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Util\DateTimeFormat; use Friendica\Util\Mimetype; +use Friendica\Util\Strings; function wall_attach_post(App $a) { @@ -115,7 +116,7 @@ function wall_attach_post(App $a) { } if ($maxfilesize && $filesize > $maxfilesize) { - $msg = L10n::t('File exceeds size limit of %s', formatBytes($maxfilesize)); + $msg = L10n::t('File exceeds size limit of %s', Strings::formatBytes($maxfilesize)); if ($r_json) { echo json_encode(['error' => $msg]); } else { diff --git a/mod/wall_upload.php b/mod/wall_upload.php index 84e40d3b5..3358433da 100644 --- a/mod/wall_upload.php +++ b/mod/wall_upload.php @@ -17,13 +17,14 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\Photo; use Friendica\Object\Image; +use Friendica\Util\Strings; function wall_upload_post(App $a, $desktopmode = true) { Logger::log("wall upload: starting new upload", Logger::DEBUG); $r_json = (x($_GET, 'response') && $_GET['response'] == 'json'); - $album = (x($_GET, 'album') ? notags(trim($_GET['album'])) : ''); + $album = (x($_GET, 'album') ? Strings::escapeTags(trim($_GET['album'])) : ''); if ($a->argc > 1) { if (!x($_FILES, 'media')) { @@ -193,7 +194,7 @@ function wall_upload_post(App $a, $desktopmode = true) $maximagesize = Config::get('system', 'maximagesize'); if (($maximagesize) && ($filesize > $maximagesize)) { - $msg = L10n::t('Image exceeds size limit of %s', formatBytes($maximagesize)); + $msg = L10n::t('Image exceeds size limit of %s', Strings::formatBytes($maximagesize)); if ($r_json) { echo json_encode(['error' => $msg]); } else { diff --git a/mod/wallmessage.php b/mod/wallmessage.php index 78cdd5a55..b7a62b3ad 100644 --- a/mod/wallmessage.php +++ b/mod/wallmessage.php @@ -10,6 +10,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model\Mail; use Friendica\Model\Profile; +use Friendica\Util\Strings; function wallmessage_post(App $a) { @@ -19,10 +20,10 @@ function wallmessage_post(App $a) { return; } - $subject = ((x($_REQUEST,'subject')) ? notags(trim($_REQUEST['subject'])) : ''); - $body = ((x($_REQUEST,'body')) ? escape_tags(trim($_REQUEST['body'])) : ''); + $subject = ((x($_REQUEST,'subject')) ? Strings::escapeTags(trim($_REQUEST['subject'])) : ''); + $body = ((x($_REQUEST,'body')) ? Strings::escapeHtml(trim($_REQUEST['body'])) : ''); - $recipient = (($a->argc > 1) ? notags($a->argv[1]) : ''); + $recipient = (($a->argc > 1) ? Strings::escapeTags($a->argv[1]) : ''); if ((! $recipient) || (! $body)) { return; } @@ -131,7 +132,7 @@ function wallmessage_content(App $a) { '$recipname' => $user['username'], '$nickname' => $user['nickname'], '$subjtxt' => ((x($_REQUEST, 'subject')) ? strip_tags($_REQUEST['subject']) : ''), - '$text' => ((x($_REQUEST, 'body')) ? escape_tags(htmlspecialchars($_REQUEST['body'])) : ''), + '$text' => ((x($_REQUEST, 'body')) ? Strings::escapeHtml(htmlspecialchars($_REQUEST['body'])) : ''), '$readonly' => '', '$yourmessage' => L10n::t('Your message:'), '$parent' => '', diff --git a/mod/xrd.php b/mod/xrd.php index 83f069d14..4b9b0ee8f 100644 --- a/mod/xrd.php +++ b/mod/xrd.php @@ -9,6 +9,7 @@ use Friendica\Core\Renderer; use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Protocol\Salmon; +use Friendica\Util\Strings; function xrd_init(App $a) { @@ -17,7 +18,7 @@ function xrd_init(App $a) System::httpExit(404); } - $uri = urldecode(notags(trim($_GET['uri']))); + $uri = urldecode(Strings::escapeTags(trim($_GET['uri']))); if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/jrd+json') { $mode = 'json'; } else { @@ -28,7 +29,7 @@ function xrd_init(App $a) System::httpExit(404); } - $uri = urldecode(notags(trim($_GET['resource']))); + $uri = urldecode(Strings::escapeTags(trim($_GET['resource']))); if (defaults($_SERVER, 'HTTP_ACCEPT', '') == 'application/xrd+xml') { $mode = 'xml'; } else { diff --git a/spec/dfrn2_contact_request.svg b/spec/dfrn2_contact_request.svg index cc78be55c..34de340f3 100644 --- a/spec/dfrn2_contact_request.svg +++ b/spec/dfrn2_contact_request.svg @@ -38,7 +38,7 @@ text { font:12px Dialog; }where self = 0 to look if this contact is already there (if issued-id or rel is already available return here because it seems that we are already connected) -- create a issued-id with $issued_id = random_string(); +- create a issued-id with $issued_id = Strings::getRandomHex(); - if we already found a contact record above update the issued-id with the one we have created - otherwise if Bob is not already in the contact table scrape diff --git a/spec/zot-2012.txt b/spec/zot-2012.txt index 2e1f3c3c4..3d939bab7 100644 --- a/spec/zot-2012.txt +++ b/spec/zot-2012.txt @@ -11,12 +11,12 @@ First create a global unique userid Site userid: https://macgirvin.com/1 -$guuid = base64url_encode(hash('whirlpool','https://macgirvin.com/1.' . mt_rand(1000000,9999999),1); +$guuid = Strings::base64UrlEncode(hash('whirlpool','https://macgirvin.com/1.' . mt_rand(1000000,9999999),1); Then create a hashed site destination. -$gduid = base64url_encode(hash('whirlpool', $guuid . 'https://macgirvin.com',1); +$gduid = Strings::base64UrlEncode(hash('whirlpool', $guuid . 'https://macgirvin.com',1); These two keys will identify you as a person+site pair in the future. You will also obtain a password upon introducing yourself to a site. diff --git a/src/App.php b/src/App.php index cf8fc7abe..12f302f06 100644 --- a/src/App.php +++ b/src/App.php @@ -816,12 +816,12 @@ class App public function removeBaseURL($origURL) { // Remove the hostname from the url if it is an internal link - $nurl = normalise_link($origURL); - $base = normalise_link($this->getBaseURL()); + $nurl = Util\Strings::normaliseLink($origURL); + $base = Util\Strings::normaliseLink($this->getBaseURL()); $url = str_replace($base . '/', '', $nurl); // if it is an external link return the orignal value - if ($url == normalise_link($origURL)) { + if ($url == Util\Strings::normaliseLink($origURL)) { return $origURL; } else { return $url; @@ -1443,7 +1443,7 @@ class App // and www.example.com vs example.com. // We will only change the url to an ip address if there is no existing setting - if (empty($url) || (!link_compare($url, $this->getBaseURL())) && (!preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $this->getHostName()))) { + if (empty($url) || (!Util\Strings::compareLink($url, $this->getBaseURL())) && (!preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $this->getHostName()))) { Core\Config::set('system', 'url', $this->getBaseURL()); } } diff --git a/src/Content/ContactSelector.php b/src/Content/ContactSelector.php index 298f2512e..a23acecc5 100644 --- a/src/Content/ContactSelector.php +++ b/src/Content/ContactSelector.php @@ -10,6 +10,7 @@ use Friendica\Core\Protocol; use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Util\Network; +use Friendica\Util\Strings; /** * @brief ContactSelector class @@ -106,12 +107,12 @@ class ContactSelector // Create the server url out of the profile url $parts = parse_url($profile); unset($parts['path']); - $server_url = [normalise_link(Network::unparseURL($parts))]; + $server_url = [Strings::normaliseLink(Network::unparseURL($parts))]; // Fetch the server url - $gcontact = DBA::selectFirst('gcontact', ['server_url'], ['nurl' => normalise_link($profile)]); + $gcontact = DBA::selectFirst('gcontact', ['server_url'], ['nurl' => Strings::normaliseLink($profile)]); if (!empty($gcontact) && !empty($gcontact['server_url'])) { - $server_url[] = normalise_link($gcontact['server_url']); + $server_url[] = Strings::normaliseLink($gcontact['server_url']); } // Now query the GServer for the platform name diff --git a/src/Content/OEmbed.php b/src/Content/OEmbed.php index 943b91e1f..c77db3827 100644 --- a/src/Content/OEmbed.php +++ b/src/Content/OEmbed.php @@ -21,6 +21,7 @@ use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\ParseUrl; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; require_once 'include/dba.php'; @@ -61,7 +62,7 @@ class OEmbed $cache_key = 'oembed:' . $a->videowidth . ':' . $embedurl; - $condition = ['url' => normalise_link($embedurl), 'maxwidth' => $a->videowidth]; + $condition = ['url' => Strings::normaliseLink($embedurl), 'maxwidth' => $a->videowidth]; $oembed_record = DBA::selectFirst('oembed', ['content'], $condition); if (DBA::isResult($oembed_record)) { $json_string = $oembed_record['content']; @@ -116,7 +117,7 @@ class OEmbed if (!empty($oembed->type) && $oembed->type != 'error') { DBA::insert('oembed', [ - 'url' => normalise_link($embedurl), + 'url' => Strings::normaliseLink($embedurl), 'maxwidth' => $a->videowidth, 'content' => $json_string, 'created' => DateTimeFormat::utcNow() @@ -373,7 +374,7 @@ class OEmbed } $width = '100%'; - $src = System::baseUrl() . '/oembed/' . base64url_encode($src); + $src = System::baseUrl() . '/oembed/' . Strings::base64UrlEncode($src); return ''; } diff --git a/src/Content/Smilies.php b/src/Content/Smilies.php index 39de3c20e..292841361 100644 --- a/src/Content/Smilies.php +++ b/src/Content/Smilies.php @@ -19,6 +19,7 @@ use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\PConfig; use Friendica\Core\System; +use Friendica\Util\Strings; /** * This class contains functions to handle smiles @@ -241,7 +242,7 @@ class Smilies */ private static function encode($m) { - return(str_replace($m[1], base64url_encode($m[1]), $m[0])); + return(str_replace($m[1], Strings::base64UrlEncode($m[1]), $m[0])); } /** @@ -251,7 +252,7 @@ class Smilies */ private static function decode($m) { - return(str_replace($m[1], base64url_decode($m[1]), $m[0])); + return(str_replace($m[1], Strings::base64UrlDecode($m[1]), $m[0])); } diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 3592059d0..9c9adec0f 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -27,6 +27,7 @@ use Friendica\Util\Map; use Friendica\Util\Network; use Friendica\Util\ParseUrl; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; class BBCode extends BaseObject { @@ -943,7 +944,7 @@ class BBCode extends BaseObject case 3: // Diaspora $headline = '' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . $mention . ':
' . "\n"; - if (stripos(normalise_link($attributes['link']), 'http://twitter.com/') === 0) { + if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0) { $text = ($is_quote_share? '
' : '') . '' . "\n"; } else { $text = ($is_quote_share? '
' : '') . $headline . '' . trim($content) . '' . "\n"; @@ -978,7 +979,7 @@ class BBCode extends BaseObject break; default: // Transforms quoted tweets in rich attachments to avoid nested tweets - if (stripos(normalise_link($attributes['link']), 'http://twitter.com/') === 0 && OEmbed::isAllowedURL($attributes['link'])) { + if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0 && OEmbed::isAllowedURL($attributes['link'])) { try { $text = ($is_quote_share? '
' : '') . OEmbed::getHTML($attributes['link']); } catch (Exception $e) { @@ -1363,7 +1364,7 @@ class BBCode extends BaseObject $text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '$2', $text); // leave open the posibility of [map=something] - // this is replaced in prepare_body() which has knowledge of the item location + // this is replaced in Item::prepareBody() which has knowledge of the item location if (strpos($text, '[/map]') !== false) { $text = preg_replace_callback( @@ -1474,7 +1475,7 @@ class BBCode extends BaseObject $text = str_replace('[hr]', '
', $text); - // This is actually executed in prepare_body() + // This is actually executed in Item::prepareBody() $text = str_replace('[nosmile]', '', $text); @@ -1910,4 +1911,78 @@ class BBCode extends BaseObject return $text; } + + /** + * @brief Pull out all #hashtags and @person tags from $string. + * + * We also get @person@domain.com - which would make + * the regex quite complicated as tags can also + * end a sentence. So we'll run through our results + * and strip the period from any tags which end with one. + * Returns array of tags found, or empty array. + * + * @param string $string Post content + * + * @return array List of tag and person names + */ + public static function getTags($string) + { + $ret = []; + + // Convert hashtag links to hashtags + $string = preg_replace('/#\[url\=([^\[\]]*)\](.*?)\[\/url\]/ism', '#$2', $string); + + // ignore anything in a code block + $string = preg_replace('/\[code\](.*?)\[\/code\]/sm', '', $string); + + // Force line feeds at bbtags + $string = str_replace(['[', ']'], ["\n[", "]\n"], $string); + + // ignore anything in a bbtag + $string = preg_replace('/\[(.*?)\]/sm', '', $string); + + // Match full names against @tags including the space between first and last + // We will look these up afterward to see if they are full names or not recognisable. + + if (preg_match_all('/(@[^ \x0D\x0A,:?]+ [^ \x0D\x0A@,:?]+)([ \x0D\x0A@,:?]|$)/', $string, $matches)) { + foreach ($matches[1] as $match) { + if (strstr($match, ']')) { + // we might be inside a bbcode color tag - leave it alone + continue; + } + + if (substr($match, -1, 1) === '.') { + $ret[] = substr($match, 0, -1); + } else { + $ret[] = $match; + } + } + } + + // Otherwise pull out single word tags. These can be @nickname, @first_last + // and #hash tags. + + if (preg_match_all('/([!#@][^\^ \x0D\x0A,;:?]+)([ \x0D\x0A,;:?]|$)/', $string, $matches)) { + foreach ($matches[1] as $match) { + if (strstr($match, ']')) { + // we might be inside a bbcode color tag - leave it alone + continue; + } + if (substr($match, -1, 1) === '.') { + $match = substr($match,0,-1); + } + // ignore strictly numeric tags like #1 + if ((strpos($match, '#') === 0) && ctype_digit(substr($match, 1))) { + continue; + } + // try not to catch url fragments + if (strpos($string, $match) && preg_match('/[a-zA-z0-9\/]/', substr($string, strpos($string, $match) - 1, 1))) { + continue; + } + $ret[] = $match; + } + } + + return $ret; + } } diff --git a/src/Content/Text/HTML.php b/src/Content/Text/HTML.php index cdfd41c11..9b73da56d 100644 --- a/src/Content/Text/HTML.php +++ b/src/Content/Text/HTML.php @@ -7,6 +7,7 @@ namespace Friendica\Content\Text; use DOMDocument; use DOMXPath; +use Friendica\Content\Feature; use Friendica\Core\Addon; use Friendica\Core\L10n; use Friendica\Core\Config; @@ -17,9 +18,9 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Util\Network; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; use Friendica\Util\XML; use League\HTMLToMarkdown\HtmlConverter; -use Friendica\Content\Feature; class HTML { @@ -1011,7 +1012,7 @@ class HTML $tpl = Renderer::getMarkupTemplate('wall/content_filter.tpl'); $html = Renderer::replaceMacros($tpl, [ '$reasons' => $reasons, - '$rnd' => random_string(8), + '$rnd' => Strings::getRandomHex(8), '$openclose' => L10n::t('Click to open/close'), '$html' => $html ]); diff --git a/src/Content/Widget.php b/src/Content/Widget.php index 397a1863d..0ea539dec 100644 --- a/src/Content/Widget.php +++ b/src/Content/Widget.php @@ -18,6 +18,7 @@ use Friendica\Model\Contact; use Friendica\Model\FileTag; use Friendica\Model\GContact; use Friendica\Model\Profile; +use Friendica\Util\Strings; use Friendica\Util\XML; require_once 'boot.php'; @@ -270,11 +271,11 @@ class Widget if (!$cid) { if (Profile::getMyURL()) { $contact = DBA::selectFirst('contact', ['id'], - ['nurl' => normalise_link(Profile::getMyURL()), 'uid' => $profile_uid]); + ['nurl' => Strings::normaliseLink(Profile::getMyURL()), 'uid' => $profile_uid]); if (DBA::isResult($contact)) { $cid = $contact['id']; } else { - $gcontact = DBA::selectFirst('gcontact', ['id'], ['nurl' => normalise_link(Profile::getMyURL())]); + $gcontact = DBA::selectFirst('gcontact', ['id'], ['nurl' => Strings::normaliseLink(Profile::getMyURL())]); if (DBA::isResult($gcontact)) { $zcid = $gcontact['id']; } diff --git a/src/Core/Authentication.php b/src/Core/Authentication.php index 4d227c271..50825c525 100644 --- a/src/Core/Authentication.php +++ b/src/Core/Authentication.php @@ -12,6 +12,7 @@ use Friendica\Core\L10n; use Friendica\Core\Logger; use Friendica\Core\PConfig; use Friendica\Database\DBA; +use Friendica\Model\User; use Friendica\Util\DateTimeFormat; /** @@ -103,55 +104,16 @@ class Authentication extends BaseObject $a->timezone = $a->user['timezone']; } - $master_record = $a->user; + $masterUid = $user_record['uid']; if ((x($_SESSION, 'submanage')) && intval($_SESSION['submanage'])) { - $user = DBA::selectFirst('user', [], ['uid' => $_SESSION['submanage']]); + $user = DBA::selectFirst('user', ['uid'], ['uid' => $_SESSION['submanage']]); if (DBA::isResult($user)) { - $master_record = $user; + $masterUid = $user['uid']; } } - if ($master_record['parent-uid'] == 0) { - // First add our own entry - $a->identities = [['uid' => $master_record['uid'], - 'username' => $master_record['username'], - 'nickname' => $master_record['nickname']]]; - - // Then add all the children - $r = DBA::select('user', ['uid', 'username', 'nickname'], - ['parent-uid' => $master_record['uid'], 'account_removed' => false]); - if (DBA::isResult($r)) { - $a->identities = array_merge($a->identities, DBA::toArray($r)); - } - } else { - // Just ensure that the array is always defined - $a->identities = []; - - // First entry is our parent - $r = DBA::select('user', ['uid', 'username', 'nickname'], - ['uid' => $master_record['parent-uid'], 'account_removed' => false]); - if (DBA::isResult($r)) { - $a->identities = DBA::toArray($r); - } - - // Then add all siblings - $r = DBA::select('user', ['uid', 'username', 'nickname'], - ['parent-uid' => $master_record['parent-uid'], 'account_removed' => false]); - if (DBA::isResult($r)) { - $a->identities = array_merge($a->identities, DBA::toArray($r)); - } - } - - $r = DBA::p("SELECT `user`.`uid`, `user`.`username`, `user`.`nickname` - FROM `manage` - INNER JOIN `user` ON `manage`.`mid` = `user`.`uid` - WHERE `user`.`account_removed` = 0 AND `manage`.`uid` = ?", - $master_record['uid'] - ); - if (DBA::isResult($r)) { - $a->identities = array_merge($a->identities, DBA::toArray($r)); - } + $a->identities = User::identities($masterUid); if ($login_initial) { Logger::log('auth_identities: ' . print_r($a->identities, true), Logger::DEBUG); @@ -174,7 +136,7 @@ class Authentication extends BaseObject // Set the login date for all identities of the user DBA::update('user', ['login_date' => DateTimeFormat::utcNow()], - ['parent-uid' => $master_record['uid'], 'account_removed' => false]); + ['parent-uid' => $masterUid, 'account_removed' => false]); } if ($login_initial) { diff --git a/src/Core/Console/ArchiveContact.php b/src/Core/Console/ArchiveContact.php index 481037a5f..ffcd5a165 100644 --- a/src/Core/Console/ArchiveContact.php +++ b/src/Core/Console/ArchiveContact.php @@ -5,6 +5,7 @@ namespace Friendica\Core\Console; use Friendica\App; use Friendica\Core\L10n; use Friendica\Database\DBA; +use Friendica\Util\Strings; use RuntimeException; /** @@ -60,7 +61,7 @@ HELP; throw new RuntimeException('Friendica isn\'t properly installed yet.'); } - $nurl = normalise_link($this->getArgument(0)); + $nurl = Strings::normaliseLink($this->getArgument(0)); if (!DBA::exists('contact', ['nurl' => $nurl, 'archive' => false])) { throw new RuntimeException(L10n::t('Could not find any unarchived contact entry for this URL (%s)', $nurl)); } diff --git a/src/Core/Console/GlobalCommunitySilence.php b/src/Core/Console/GlobalCommunitySilence.php index 3ea6b4155..01413cab1 100644 --- a/src/Core/Console/GlobalCommunitySilence.php +++ b/src/Core/Console/GlobalCommunitySilence.php @@ -5,6 +5,7 @@ namespace Friendica\Core\Console; use Friendica\Core\Protocol; use Friendica\Database\DBA; use Friendica\Network\Probe; +use Friendica\Util\Strings; use RuntimeException; require_once 'include/text.php'; @@ -79,7 +80,7 @@ HELP; throw new RuntimeException('This account seems not to exist.'); } - $nurl = normalise_link($net['url']); + $nurl = Strings::normaliseLink($net['url']); $contact = DBA::selectFirst("contact", ["id"], ["nurl" => $nurl, "uid" => 0]); if (DBA::isResult($contact)) { DBA::update("contact", ["hidden" => true], ["id" => $contact["id"]]); diff --git a/src/Core/Installer.php b/src/Core/Installer.php index d2b5c4f05..f7190b2f8 100644 --- a/src/Core/Installer.php +++ b/src/Core/Installer.php @@ -11,6 +11,7 @@ use Friendica\Database\DBA; use Friendica\Database\DBStructure; use Friendica\Object\Image; use Friendica\Util\Network; +use Friendica\Util\Strings; /** * Contains methods for installation purpose of Friendica @@ -264,7 +265,7 @@ class Installer } if ($passed2) { - $str = autoname(8); + $str = Strings::getRandomName(8); $cmd = "$phppath util/testargs.php $str"; $result = trim(shell_exec($cmd)); $passed3 = $result == $str; @@ -510,7 +511,7 @@ class Installer if (function_exists('curl_init')) { $fetchResult = Network::fetchUrlFull($baseurl . "/install/testrewrite"); - $url = normalise_link($baseurl . "/install/testrewrite"); + $url = Strings::normaliseLink($baseurl . "/install/testrewrite"); if ($fetchResult->getReturnCode() != 204) { $fetchResult = Network::fetchUrlFull($url); } diff --git a/src/Core/Update.php b/src/Core/Update.php index 139688335..252ea8ef3 100644 --- a/src/Core/Update.php +++ b/src/Core/Update.php @@ -4,6 +4,7 @@ namespace Friendica\Core; use Friendica\Database\DBA; use Friendica\Database\DBStructure; +use Friendica\Util\Strings; class Update { @@ -209,7 +210,7 @@ class Update $lang = (($admin['language'])?$admin['language']:'en'); L10n::pushLang($lang); - $preamble = deindent(L10n::t(" + $preamble = Strings::deindent(L10n::t(" The friendica developers released update %s recently, but when I tried to install it, something went terribly wrong. This needs to be fixed soon and I can't do it alone. Please contact a @@ -244,7 +245,7 @@ class Update $lang = (($admin['language']) ? $admin['language'] : 'en'); L10n::pushLang($lang); - $preamble = deindent(L10n::t(" + $preamble = Strings::deindent(L10n::t(" The friendica database was successfully updated from %s to %s.", $from_build, $to_build)); diff --git a/src/Core/UserImport.php b/src/Core/UserImport.php index 7ccb6f80c..5488fe43f 100644 --- a/src/Core/UserImport.php +++ b/src/Core/UserImport.php @@ -10,6 +10,7 @@ use Friendica\Core\Protocol; use Friendica\Database\DBA; use Friendica\Model\Photo; use Friendica\Object\Image; +use Friendica\Util\Strings; require_once "include/dba.php"; @@ -119,8 +120,8 @@ class UserImport $oldbaseurl = $account['baseurl']; $newbaseurl = System::baseUrl(); - $oldaddr = str_replace('http://', '@', normalise_link($oldbaseurl)); - $newaddr = str_replace('http://', '@', normalise_link($newbaseurl)); + $oldaddr = str_replace('http://', '@', Strings::normaliseLink($oldbaseurl)); + $newaddr = str_replace('http://', '@', Strings::normaliseLink($newbaseurl)); if (!empty($account['profile']['addr'])) { $old_handle = $account['profile']['addr']; diff --git a/src/Model/APContact.php b/src/Model/APContact.php index 917e0895d..c306b3e00 100644 --- a/src/Model/APContact.php +++ b/src/Model/APContact.php @@ -7,13 +7,14 @@ namespace Friendica\Model; use Friendica\BaseObject; +use Friendica\Content\Text\HTML; use Friendica\Core\Logger; use Friendica\Database\DBA; use Friendica\Protocol\ActivityPub; use Friendica\Util\Network; use Friendica\Util\JsonLD; use Friendica\Util\DateTimeFormat; -use Friendica\Content\Text\HTML; +use Friendica\Util\Strings; require_once 'boot.php'; @@ -186,16 +187,16 @@ class APContact extends BaseObject // Update some data in the contact table with various ways to catch them all $contact_fields = ['name' => $apcontact['name'], 'about' => $apcontact['about']]; - DBA::update('contact', $contact_fields, ['nurl' => normalise_link($url)]); + DBA::update('contact', $contact_fields, ['nurl' => Strings::normaliseLink($url)]); - $contacts = DBA::select('contact', ['uid', 'id'], ['nurl' => normalise_link($url)]); + $contacts = DBA::select('contact', ['uid', 'id'], ['nurl' => Strings::normaliseLink($url)]); while ($contact = DBA::fetch($contacts)) { Contact::updateAvatar($apcontact['photo'], $contact['uid'], $contact['id']); } DBA::close($contacts); // Update the gcontact table - DBA::update('gcontact', $contact_fields, ['nurl' => normalise_link($url)]); + DBA::update('gcontact', $contact_fields, ['nurl' => Strings::normaliseLink($url)]); Logger::log('Updated profile for ' . $url, Logger::DEBUG); diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 5d571e30e..8e150b506 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -25,6 +25,7 @@ use Friendica\Protocol\PortableContact; use Friendica\Protocol\Salmon; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Strings; require_once 'boot.php'; require_once 'include/dba.php'; @@ -392,7 +393,7 @@ class Contact extends BaseObject 'blocked' => 0, 'pending' => 0, 'url' => System::baseUrl() . '/profile/' . $user['nickname'], - 'nurl' => normalise_link(System::baseUrl() . '/profile/' . $user['nickname']), + 'nurl' => Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname']), 'addr' => $user['nickname'] . '@' . substr(System::baseUrl(), strpos(System::baseUrl(), '://') + 3), 'request' => System::baseUrl() . '/dfrn_request/' . $user['nickname'], 'notify' => System::baseUrl() . '/dfrn_notify/' . $user['nickname'], @@ -477,7 +478,7 @@ class Contact extends BaseObject // it seems as if ported accounts can have wrong values, so we make sure that now everything is fine. $fields['url'] = System::baseUrl() . '/profile/' . $user['nickname']; - $fields['nurl'] = normalise_link($fields['url']); + $fields['nurl'] = Strings::normaliseLink($fields['url']); $fields['addr'] = $user['nickname'] . '@' . substr(System::baseUrl(), strpos(System::baseUrl(), '://') + 3); $fields['request'] = System::baseUrl() . '/dfrn_request/' . $user['nickname']; $fields['notify'] = System::baseUrl() . '/dfrn_notify/' . $user['nickname']; @@ -597,7 +598,7 @@ class Contact extends BaseObject if ($contact['term-date'] <= DBA::NULL_DATETIME) { DBA::update('contact', ['term-date' => DateTimeFormat::utcNow()], ['id' => $contact['id']]); - DBA::update('contact', ['term-date' => DateTimeFormat::utcNow()], ['`nurl` = ? AND `term-date` <= ? AND NOT `self`', normalise_link($contact['url']), DBA::NULL_DATETIME]); + DBA::update('contact', ['term-date' => DateTimeFormat::utcNow()], ['`nurl` = ? AND `term-date` <= ? AND NOT `self`', Strings::normaliseLink($contact['url']), DBA::NULL_DATETIME]); } else { /* @todo * We really should send a notification to the owner after 2-3 weeks @@ -615,7 +616,7 @@ class Contact extends BaseObject * the whole process over again. */ DBA::update('contact', ['archive' => 1], ['id' => $contact['id']]); - DBA::update('contact', ['archive' => 1], ['nurl' => normalise_link($contact['url']), 'self' => false]); + DBA::update('contact', ['archive' => 1], ['nurl' => Strings::normaliseLink($contact['url']), 'self' => false]); } } } @@ -649,7 +650,7 @@ class Contact extends BaseObject // It's a miracle. Our dead contact has inexplicably come back to life. $fields = ['term-date' => DBA::NULL_DATETIME, 'archive' => false]; DBA::update('contact', $fields, ['id' => $contact['id']]); - DBA::update('contact', $fields, ['nurl' => normalise_link($contact['url'])]); + DBA::update('contact', $fields, ['nurl' => Strings::normaliseLink($contact['url'])]); if (!empty($contact['batch'])) { $condition = ['batch' => $contact['batch'], 'contact-type' => self::ACCOUNT_TYPE_RELAY]; @@ -690,14 +691,14 @@ class Contact extends BaseObject // Fetch contact data from the contact table for the given user $s = DBA::p("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`, `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self` - FROM `contact` WHERE `nurl` = ? AND `uid` = ?", normalise_link($url), $uid); + FROM `contact` WHERE `nurl` = ? AND `uid` = ?", Strings::normaliseLink($url), $uid); $r = DBA::toArray($s); // Fetch contact data from the contact table for the given user, checking with the alias if (!DBA::isResult($r)) { $s = DBA::p("SELECT `id`, `id` AS `cid`, 0 AS `gid`, 0 AS `zid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`, `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, `self` - FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = ?", normalise_link($url), $url, $ssl_url, $uid); + FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = ?", Strings::normaliseLink($url), $url, $ssl_url, $uid); $r = DBA::toArray($s); } @@ -705,7 +706,7 @@ class Contact extends BaseObject if (!DBA::isResult($r)) { $s = DBA::p("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`, `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self` - FROM `contact` WHERE `nurl` = ? AND `uid` = 0", normalise_link($url)); + FROM `contact` WHERE `nurl` = ? AND `uid` = 0", Strings::normaliseLink($url)); $r = DBA::toArray($s); } @@ -713,7 +714,7 @@ class Contact extends BaseObject if (!DBA::isResult($r)) { $s = DBA::p("SELECT `id`, 0 AS `cid`, `id` AS `zid`, 0 AS `gid`, `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, `xmpp`, `keywords`, `gender`, `photo`, `thumb`, `micro`, `forum`, `prv`, (`forum` | `prv`) AS `community`, `contact-type`, `bd` AS `birthday`, 0 AS `self` - FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = 0", normalise_link($url), $url, $ssl_url); + FROM `contact` WHERE `alias` IN (?, ?, ?) AND `uid` = 0", Strings::normaliseLink($url), $url, $ssl_url); $r = DBA::toArray($s); } @@ -721,7 +722,7 @@ class Contact extends BaseObject if (!DBA::isResult($r)) { $s = DBA::p("SELECT 0 AS `id`, 0 AS `cid`, `id` AS `gid`, 0 AS `zid`, 0 AS `uid`, `url`, `nurl`, `alias`, `network`, `name`, `nick`, `addr`, `location`, `about`, '' AS `xmpp`, `keywords`, `gender`, `photo`, `photo` AS `thumb`, `photo` AS `micro`, 0 AS `forum`, 0 AS `prv`, `community`, `contact-type`, `birthday`, 0 AS `self` - FROM `gcontact` WHERE `nurl` = ?", normalise_link($url)); + FROM `gcontact` WHERE `nurl` = ?", Strings::normaliseLink($url)); $r = DBA::toArray($s); } @@ -1038,7 +1039,7 @@ class Contact extends BaseObject /// @todo Verify if we can't use Contact::getDetailsByUrl instead of the following // We first try the nurl (http://server.tld/nick), most common case - $contact = DBA::selectFirst('contact', ['id', 'avatar', 'avatar-date'], ['nurl' => normalise_link($url), 'uid' => $uid, 'deleted' => false]); + $contact = DBA::selectFirst('contact', ['id', 'avatar', 'avatar-date'], ['nurl' => Strings::normaliseLink($url), 'uid' => $uid, 'deleted' => false]); // Then the addr (nick@server.tld) if (!DBA::isResult($contact)) { @@ -1049,7 +1050,7 @@ class Contact extends BaseObject if (!DBA::isResult($contact)) { // The link could be provided as http although we stored it as https $ssl_url = str_replace('http://', 'https://', $url); - $condition = ['`alias` IN (?, ?, ?) AND `uid` = ? AND NOT `deleted`', $url, normalise_link($url), $ssl_url, $uid]; + $condition = ['`alias` IN (?, ?, ?) AND `uid` = ? AND NOT `deleted`', $url, Strings::normaliseLink($url), $ssl_url, $uid]; $contact = DBA::selectFirst('contact', ['id', 'avatar', 'avatar-date'], $condition); } @@ -1076,7 +1077,7 @@ class Contact extends BaseObject $fields = ['url', 'addr', 'alias', 'notify', 'poll', 'name', 'nick', 'photo', 'keywords', 'location', 'about', 'network', 'priority', 'batch', 'request', 'confirm', 'poco']; - $data = DBA::selectFirst('contact', $fields, ['nurl' => normalise_link($url)]); + $data = DBA::selectFirst('contact', $fields, ['nurl' => Strings::normaliseLink($url)]); if (DBA::isResult($data)) { // For security reasons we don't fetch key data from our users @@ -1103,9 +1104,9 @@ class Contact extends BaseObject // Get data from the gcontact table $fields = ['name', 'nick', 'url', 'photo', 'addr', 'alias', 'network']; - $contact = DBA::selectFirst('gcontact', $fields, ['nurl' => normalise_link($url)]); + $contact = DBA::selectFirst('gcontact', $fields, ['nurl' => Strings::normaliseLink($url)]); if (!DBA::isResult($contact)) { - $contact = DBA::selectFirst('contact', $fields, ['nurl' => normalise_link($url)]); + $contact = DBA::selectFirst('contact', $fields, ['nurl' => Strings::normaliseLink($url)]); } if (!DBA::isResult($contact)) { @@ -1118,14 +1119,14 @@ class Contact extends BaseObject if (!DBA::isResult($contact)) { // The link could be provided as http although we stored it as https $ssl_url = str_replace('http://', 'https://', $url); - $condition = ['alias' => [$url, normalise_link($url), $ssl_url]]; + $condition = ['alias' => [$url, Strings::normaliseLink($url), $ssl_url]]; $contact = DBA::selectFirst('contact', $fields, $condition); } if (!DBA::isResult($contact)) { $fields = ['url', 'addr', 'alias', 'notify', 'poll', 'name', 'nick', 'photo', 'network', 'priority', 'batch', 'request', 'confirm']; - $condition = ['url' => [$url, normalise_link($url), $ssl_url]]; + $condition = ['url' => [$url, Strings::normaliseLink($url), $ssl_url]]; $contact = DBA::selectFirst('fcontact', $fields, $condition); } @@ -1150,7 +1151,7 @@ class Contact extends BaseObject 'uid' => $uid, 'created' => DateTimeFormat::utcNow(), 'url' => $data["url"], - 'nurl' => normalise_link($data["url"]), + 'nurl' => Strings::normaliseLink($data["url"]), 'addr' => $data["addr"], 'alias' => $data["alias"], 'notify' => $data["notify"], @@ -1178,7 +1179,7 @@ class Contact extends BaseObject 'pending' => 0] ); - $s = DBA::select('contact', ['id'], ['nurl' => normalise_link($data["url"]), 'uid' => $uid], ['order' => ['id'], 'limit' => 2]); + $s = DBA::select('contact', ['id'], ['nurl' => Strings::normaliseLink($data["url"]), 'uid' => $uid], ['order' => ['id'], 'limit' => 2]); $contacts = DBA::toArray($s); if (!DBA::isResult($contacts)) { return 0; @@ -1187,7 +1188,7 @@ class Contact extends BaseObject $contact_id = $contacts[0]["id"]; // Update the newly created contact from data in the gcontact table - $gcontact = DBA::selectFirst('gcontact', ['location', 'about', 'keywords', 'gender'], ['nurl' => normalise_link($data["url"])]); + $gcontact = DBA::selectFirst('gcontact', ['location', 'about', 'keywords', 'gender'], ['nurl' => Strings::normaliseLink($data["url"])]); if (DBA::isResult($gcontact)) { // Only use the information when the probing hadn't fetched these values if ($data['keywords'] != '') { @@ -1204,7 +1205,7 @@ class Contact extends BaseObject if (count($contacts) > 1 && $uid == 0 && $contact_id != 0 && $data["url"] != "") { DBA::delete('contact', ["`nurl` = ? AND `uid` = 0 AND `id` != ? AND NOT `self`", - normalise_link($data["url"]), $contact_id]); + Strings::normaliseLink($data["url"]), $contact_id]); } } @@ -1221,7 +1222,7 @@ class Contact extends BaseObject $updated = ['addr' => $data['addr'], 'alias' => $data['alias'], 'url' => $data['url'], - 'nurl' => normalise_link($data['url']), + 'nurl' => Strings::normaliseLink($data['url']), 'name' => $data['name'], 'nick' => $data['nick']]; @@ -1543,7 +1544,7 @@ class Contact extends BaseObject DBA::update( 'contact', [ 'url' => $ret['url'], - 'nurl' => normalise_link($ret['url']), + 'nurl' => Strings::normaliseLink($ret['url']), 'network' => $ret['network'], 'addr' => $ret['addr'], 'alias' => $ret['alias'], @@ -1627,10 +1628,10 @@ class Contact extends BaseObject // the poll url is more reliable than the profile url, as we may have // indirect links or webfinger links - $condition = ['uid' => $uid, 'poll' => [$ret['poll'], normalise_link($ret['poll'])], 'network' => $ret['network'], 'pending' => false]; + $condition = ['uid' => $uid, 'poll' => [$ret['poll'], Strings::normaliseLink($ret['poll'])], 'network' => $ret['network'], 'pending' => false]; $contact = DBA::selectFirst('contact', ['id', 'rel'], $condition); if (!DBA::isResult($contact)) { - $condition = ['uid' => $uid, 'nurl' => normalise_link($url), 'network' => $ret['network'], 'pending' => false]; + $condition = ['uid' => $uid, 'nurl' => Strings::normaliseLink($url), 'network' => $ret['network'], 'pending' => false]; $contact = DBA::selectFirst('contact', ['id', 'rel'], $condition); } @@ -1710,7 +1711,7 @@ class Contact extends BaseObject 'uid' => $uid, 'created' => DateTimeFormat::utcNow(), 'url' => $ret['url'], - 'nurl' => normalise_link($ret['url']), + 'nurl' => Strings::normaliseLink($ret['url']), 'addr' => $ret['addr'], 'alias' => $ret['alias'], 'batch' => $ret['batch'], @@ -1855,7 +1856,7 @@ class Contact extends BaseObject // send email notification to owner? } else { - if (DBA::exists('contact', ['nurl' => normalise_link($url), 'uid' => $importer['uid'], 'pending' => true])) { + if (DBA::exists('contact', ['nurl' => Strings::normaliseLink($url), 'uid' => $importer['uid'], 'pending' => true])) { Logger::log('ignoring duplicated connection request from pending contact ' . $url); return; } @@ -1866,7 +1867,7 @@ class Contact extends BaseObject intval($importer['uid']), DBA::escape(DateTimeFormat::utcNow()), DBA::escape($url), - DBA::escape(normalise_link($url)), + DBA::escape(Strings::normaliseLink($url)), DBA::escape($name), DBA::escape($nick), DBA::escape($photo), @@ -1889,7 +1890,7 @@ class Contact extends BaseObject $user = DBA::selectFirst('user', $fields, ['uid' => $importer['uid']]); if (DBA::isResult($user) && !in_array($user['page-flags'], [self::PAGE_SOAPBOX, self::PAGE_FREELOVE, self::PAGE_COMMUNITY])) { // create notification - $hash = random_string(); + $hash = Strings::getRandomHex(); if (is_array($contact_record)) { DBA::insert('intro', ['uid' => $importer['uid'], 'contact-id' => $contact_record['id'], diff --git a/src/Model/GContact.php b/src/Model/GContact.php index 398fc7758..6e2e520c8 100644 --- a/src/Model/GContact.php +++ b/src/Model/GContact.php @@ -17,6 +17,7 @@ use Friendica\Network\Probe; use Friendica\Protocol\PortableContact; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Strings; require_once 'include/dba.php'; @@ -146,13 +147,13 @@ class GContact $alternate = PortableContact::alternateOStatusUrl($gcontact['url']); // The global contacts should contain the original picture, not the cached one - if (($gcontact['generation'] != 1) && stristr(normalise_link($gcontact['photo']), normalise_link(System::baseUrl()."/photo/"))) { + if (($gcontact['generation'] != 1) && stristr(Strings::normaliseLink($gcontact['photo']), Strings::normaliseLink(System::baseUrl()."/photo/"))) { $gcontact['photo'] = ""; } if (!isset($gcontact['network'])) { $condition = ["`uid` = 0 AND `nurl` = ? AND `network` != '' AND `network` != ?", - normalise_link($gcontact['url']), Protocol::STATUSNET]; + Strings::normaliseLink($gcontact['url']), Protocol::STATUSNET]; $contact = DBA::selectFirst('contact', ['network'], $condition); if (DBA::isResult($contact)) { $gcontact['network'] = $contact["network"]; @@ -160,7 +161,7 @@ class GContact if (($gcontact['network'] == "") || ($gcontact['network'] == Protocol::OSTATUS)) { $condition = ["`uid` = 0 AND `alias` IN (?, ?) AND `network` != '' AND `network` != ?", - $gcontact['url'], normalise_link($gcontact['url']), Protocol::STATUSNET]; + $gcontact['url'], Strings::normaliseLink($gcontact['url']), Protocol::STATUSNET]; $contact = DBA::selectFirst('contact', ['network'], $condition); if (DBA::isResult($contact)) { $gcontact['network'] = $contact["network"]; @@ -172,7 +173,7 @@ class GContact $gcontact['network'] = ''; $fields = ['network', 'updated', 'server_url', 'url', 'addr']; - $gcnt = DBA::selectFirst('gcontact', $fields, ['nurl' => normalise_link($gcontact['url'])]); + $gcnt = DBA::selectFirst('gcontact', $fields, ['nurl' => Strings::normaliseLink($gcontact['url'])]); if (DBA::isResult($gcnt)) { if (!isset($gcontact['network']) && ($gcnt["network"] != Protocol::STATUSNET)) { $gcontact['network'] = $gcnt["network"]; @@ -180,7 +181,7 @@ class GContact if ($gcontact['updated'] <= DBA::NULL_DATETIME) { $gcontact['updated'] = $gcnt["updated"]; } - if (!isset($gcontact['server_url']) && (normalise_link($gcnt["server_url"]) != normalise_link($gcnt["url"]))) { + if (!isset($gcontact['server_url']) && (Strings::normaliseLink($gcnt["server_url"]) != Strings::normaliseLink($gcnt["url"]))) { $gcontact['server_url'] = $gcnt["server_url"]; } if (!isset($gcontact['addr'])) { @@ -205,8 +206,8 @@ class GContact if ($alternate && ($gcontact['network'] == Protocol::OSTATUS)) { // Delete the old entry - if it exists - if (DBA::exists('gcontact', ['nurl' => normalise_link($orig_profile)])) { - DBA::delete('gcontact', ['nurl' => normalise_link($orig_profile)]); + if (DBA::exists('gcontact', ['nurl' => Strings::normaliseLink($orig_profile)])) { + DBA::delete('gcontact', ['nurl' => Strings::normaliseLink($orig_profile)]); } } } @@ -658,7 +659,7 @@ class GContact DBA::lock('gcontact'); $fields = ['id', 'last_contact', 'last_failure', 'network']; - $gcnt = DBA::selectFirst('gcontact', $fields, ['nurl' => normalise_link($contact["url"])]); + $gcnt = DBA::selectFirst('gcontact', $fields, ['nurl' => Strings::normaliseLink($contact["url"])]); if (DBA::isResult($gcnt)) { $gcontact_id = $gcnt["id"]; @@ -683,7 +684,7 @@ class GContact DBA::escape($contact["addr"]), DBA::escape($contact["network"]), DBA::escape($contact["url"]), - DBA::escape(normalise_link($contact["url"])), + DBA::escape(Strings::normaliseLink($contact["url"])), DBA::escape($contact["photo"]), DBA::escape(DateTimeFormat::utcNow()), DBA::escape(DateTimeFormat::utcNow()), @@ -693,7 +694,7 @@ class GContact intval($contact["generation"]) ); - $condition = ['nurl' => normalise_link($contact["url"])]; + $condition = ['nurl' => Strings::normaliseLink($contact["url"])]; $cnt = DBA::selectFirst('gcontact', ['id', 'network'], $condition, ['order' => ['id']]); if (DBA::isResult($cnt)) { $gcontact_id = $cnt["id"]; @@ -793,7 +794,7 @@ class GContact $contact["server_url"] = $data['baseurl']; } } else { - $contact["server_url"] = normalise_link($contact["server_url"]); + $contact["server_url"] = Strings::normaliseLink($contact["server_url"]); } if (($contact["addr"] == "") && ($contact["server_url"] != "") && ($contact["nick"] != "")) { @@ -822,7 +823,7 @@ class GContact if ($update) { Logger::log("Update gcontact for ".$contact["url"], Logger::DEBUG); $condition = ['`nurl` = ? AND (`generation` = 0 OR `generation` >= ?)', - normalise_link($contact["url"]), $contact["generation"]]; + Strings::normaliseLink($contact["url"]), $contact["generation"]]; $contact["updated"] = DateTimeFormat::utc($contact["updated"]); $updated = ['photo' => $contact['photo'], 'name' => $contact['name'], @@ -842,7 +843,7 @@ class GContact // This is used for the shadow copies of public items. /// @todo Check if we really should do this. // The quality of the gcontact table is mostly lower than the public contact - $public_contact = DBA::selectFirst('contact', ['id'], ['nurl' => normalise_link($contact["url"]), 'uid' => 0]); + $public_contact = DBA::selectFirst('contact', ['id'], ['nurl' => Strings::normaliseLink($contact["url"]), 'uid' => 0]); if (DBA::isResult($public_contact)) { Logger::log("Update public contact ".$public_contact["id"], Logger::DEBUG); diff --git a/src/Model/Item.php b/src/Model/Item.php index 8e0a397e2..30c29e151 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -8,25 +8,32 @@ namespace Friendica\Model; use Friendica\BaseObject; use Friendica\Content\Text\BBCode; +use Friendica\Content\Text\HTML; use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\Lock; use Friendica\Core\Logger; +use Friendica\Core\L10n; use Friendica\Core\PConfig; use Friendica\Core\Protocol; +use Friendica\Core\Renderer; use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\Model\Contact; +use Friendica\Model\Event; use Friendica\Model\FileTag; use Friendica\Model\PermissionSet; +use Friendica\Model\Term; use Friendica\Model\ItemURI; use Friendica\Object\Image; use Friendica\Protocol\Diaspora; use Friendica\Protocol\OStatus; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Map; use Friendica\Util\XML; use Friendica\Util\Security; +use Friendica\Util\Strings; use Text_LanguageDetect; require_once 'boot.php'; @@ -1143,7 +1150,7 @@ class Item extends BaseObject private static function guid($item, $notify) { if (!empty($item['guid'])) { - return notags(trim($item['guid'])); + return Strings::escapeTags(trim($item['guid'])); } if ($notify) { @@ -1258,7 +1265,7 @@ class Item extends BaseObject } $item['guid'] = self::guid($item, $notify); - $item['uri'] = notags(trim(defaults($item, 'uri', self::newURI($item['uid'], $item['guid'])))); + $item['uri'] = Strings::escapeTags(trim(defaults($item, 'uri', self::newURI($item['uid'], $item['guid'])))); // Store URI data $item['uri-id'] = ItemURI::insert(['uri' => $item['uri'], 'guid' => $item['guid']]); @@ -1528,7 +1535,7 @@ class Item extends BaseObject Logger::log("Checking if parent ".$parent_id." has to be tagged as mention for user ".$item['uid'], Logger::DEBUG); $user = DBA::selectFirst('user', ['nickname'], ['uid' => $item['uid']]); if (DBA::isResult($user)) { - $self = normalise_link(System::baseUrl() . '/profile/' . $user['nickname']); + $self = Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname']); $self_id = Contact::getIdForURL($self, 0, true); Logger::log("'myself' is ".$self_id." for parent ".$parent_id." checking against ".$item['author-id']." and ".$item['owner-id'], Logger::DEBUG); if (($item['author-id'] == $self_id) || ($item['owner-id'] == $self_id)) { @@ -1607,7 +1614,7 @@ class Item extends BaseObject $item["deleted"] = $parent_deleted; // Fill the cache field - put_item_in_cache($item); + self::putInCache($item); if ($notify) { $item['edit'] = false; @@ -2396,7 +2403,7 @@ class Item extends BaseObject public static function setHashtags(&$item) { - $tags = get_tags($item["body"]); + $tags = BBCode::getTags($item["body"]); // No hashtags? if (!count($tags)) { @@ -2538,18 +2545,18 @@ class Item extends BaseObject return; } - $link = normalise_link(System::baseUrl() . '/profile/' . $user['nickname']); + $link = Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname']); /* * Diaspora uses their own hardwired link URL in @-tags * instead of the one we supply with webfinger */ - $dlink = normalise_link(System::baseUrl() . '/u/' . $user['nickname']); + $dlink = Strings::normaliseLink(System::baseUrl() . '/u/' . $user['nickname']); $cnt = preg_match_all('/[\@\!]\[url\=(.*?)\](.*?)\[\/url\]/ism', $item['body'], $matches, PREG_SET_ORDER); if ($cnt) { foreach ($matches as $mtch) { - if (link_compare($link, $mtch[1]) || link_compare($dlink, $mtch[1])) { + if (Strings::compareLink($link, $mtch[1]) || Strings::compareLink($dlink, $mtch[1])) { $mention = true; Logger::log('mention found: ' . $mtch[2]); } @@ -3247,4 +3254,295 @@ class Item extends BaseObject return $sql; } + + /** + * get translated item type + * + * @param array $itme + * @return string + */ + public static function postType($item) + { + if (!empty($item['event-id'])) { + return L10n::t('event'); + } elseif (!empty($item['resource-id'])) { + return L10n::t('photo'); + } elseif (!empty($item['verb']) && $item['verb'] !== ACTIVITY_POST) { + return L10n::t('activity'); + } elseif ($item['id'] != $item['parent']) { + return L10n::t('comment'); + } + + return L10n::t('post'); + } + + /** + * Sets the "rendered-html" field of the provided item + * + * Body is preserved to avoid side-effects as we modify it just-in-time for spoilers and private image links + * + * @param array $item + * @param bool $update + * + * @todo Remove reference, simply return "rendered-html" and "rendered-hash" + */ + public static function putInCache(&$item, $update = false) + { + $body = $item["body"]; + + $rendered_hash = defaults($item, 'rendered-hash', ''); + $rendered_html = defaults($item, 'rendered-html', ''); + + if ($rendered_hash == '' + || $rendered_html == "" + || $rendered_hash != hash("md5", $item["body"]) + || Config::get("system", "ignore_cache") + ) { + $a = self::getApp(); + redir_private_images($a, $item); + + $item["rendered-html"] = prepare_text($item["body"]); + $item["rendered-hash"] = hash("md5", $item["body"]); + + $hook_data = ['item' => $item, 'rendered-html' => $item['rendered-html'], 'rendered-hash' => $item['rendered-hash']]; + Addon::callHooks('put_item_in_cache', $hook_data); + $item['rendered-html'] = $hook_data['rendered-html']; + $item['rendered-hash'] = $hook_data['rendered-hash']; + unset($hook_data); + + // Force an update if the generated values differ from the existing ones + if ($rendered_hash != $item["rendered-hash"]) { + $update = true; + } + + // Only compare the HTML when we forcefully ignore the cache + if (Config::get("system", "ignore_cache") && ($rendered_html != $item["rendered-html"])) { + $update = true; + } + + if ($update && !empty($item["id"])) { + self::update( + [ + 'rendered-html' => $item["rendered-html"], + 'rendered-hash' => $item["rendered-hash"] + ], + ['id' => $item["id"]] + ); + } + } + + $item["body"] = $body; + } + + /** + * @brief Given an item array, convert the body element from bbcode to html and add smilie icons. + * If attach is true, also add icons for item attachments. + * + * @param array $item + * @param boolean $attach + * @param boolean $is_preview + * @return string item body html + * @hook prepare_body_init item array before any work + * @hook prepare_body_content_filter ('item'=>item array, 'filter_reasons'=>string array) before first bbcode to html + * @hook prepare_body ('item'=>item array, 'html'=>body string, 'is_preview'=>boolean, 'filter_reasons'=>string array) after first bbcode to html + * @hook prepare_body_final ('item'=>item array, 'html'=>body string) after attach icons and blockquote special case handling (spoiler, author) + */ + public static function prepareBody(array &$item, $attach = false, $is_preview = false) + { + $a = self::getApp(); + Addon::callHooks('prepare_body_init', $item); + + // In order to provide theme developers more possibilities, event items + // are treated differently. + if ($item['object-type'] === ACTIVITY_OBJ_EVENT && isset($item['event-id'])) { + $ev = Event::getItemHTML($item); + return $ev; + } + + $tags = Term::populateTagsFromItem($item); + + $item['tags'] = $tags['tags']; + $item['hashtags'] = $tags['hashtags']; + $item['mentions'] = $tags['mentions']; + + // Compile eventual content filter reasons + $filter_reasons = []; + if (!$is_preview && public_contact() != $item['author-id']) { + if (!empty($item['content-warning']) && (!local_user() || !PConfig::get(local_user(), 'system', 'disable_cw', false))) { + $filter_reasons[] = L10n::t('Content warning: %s', $item['content-warning']); + } + + $hook_data = [ + 'item' => $item, + 'filter_reasons' => $filter_reasons + ]; + Addon::callHooks('prepare_body_content_filter', $hook_data); + $filter_reasons = $hook_data['filter_reasons']; + unset($hook_data); + } + + // Update the cached values if there is no "zrl=..." on the links. + $update = (!local_user() && !remote_user() && ($item["uid"] == 0)); + + // Or update it if the current viewer is the intented viewer. + if (($item["uid"] == local_user()) && ($item["uid"] != 0)) { + $update = true; + } + + self::putInCache($item, $update); + $s = $item["rendered-html"]; + + $hook_data = [ + 'item' => $item, + 'html' => $s, + 'preview' => $is_preview, + 'filter_reasons' => $filter_reasons + ]; + Addon::callHooks('prepare_body', $hook_data); + $s = $hook_data['html']; + unset($hook_data); + + if (!$attach) { + // Replace the blockquotes with quotes that are used in mails. + $mailquote = ''; + $s = str_replace(['', '', ''], [$mailquote, $mailquote, $mailquote], $s); + return $s; + } + + $as = ''; + $vhead = false; + $matches = []; + preg_match_all('|\[attach\]href=\"(.*?)\" length=\"(.*?)\" type=\"(.*?)\"(?: title=\"(.*?)\")?|', $item['attach'], $matches, PREG_SET_ORDER); + foreach ($matches as $mtch) { + $mime = $mtch[3]; + + $the_url = Contact::magicLinkById($item['author-id'], $mtch[1]); + + if (strpos($mime, 'video') !== false) { + if (!$vhead) { + $vhead = true; + $a->page['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('videos_head.tpl'), [ + '$baseurl' => System::baseUrl(), + ]); + } + + $url_parts = explode('/', $the_url); + $id = end($url_parts); + $as .= Renderer::replaceMacros(Renderer::getMarkupTemplate('video_top.tpl'), [ + '$video' => [ + 'id' => $id, + 'title' => L10n::t('View Video'), + 'src' => $the_url, + 'mime' => $mime, + ], + ]); + } + + $filetype = strtolower(substr($mime, 0, strpos($mime, '/'))); + if ($filetype) { + $filesubtype = strtolower(substr($mime, strpos($mime, '/') + 1)); + $filesubtype = str_replace('.', '-', $filesubtype); + } else { + $filetype = 'unkn'; + $filesubtype = 'unkn'; + } + + $title = Strings::escapeHtml(trim(!empty($mtch[4]) ? $mtch[4] : $mtch[1])); + $title .= ' ' . $mtch[2] . ' ' . L10n::t('bytes'); + + $icon = ''; + $as .= '' . $icon . ''; + } + + if ($as != '') { + $s .= ''.$as.''; + } + + // Map. + if (strpos($s, '') !== false && x($item, 'coord')) { + $x = Map::byCoordinates(trim($item['coord'])); + if ($x) { + $s = preg_replace('/\/', '$0' . $x, $s); + } + } + + + // Look for spoiler. + $spoilersearch = ''; + + // Remove line breaks before the spoiler. + while ((strpos($s, "\n" . $spoilersearch) !== false)) { + $s = str_replace("\n" . $spoilersearch, $spoilersearch, $s); + } + while ((strpos($s, "
" . $spoilersearch) !== false)) { + $s = str_replace("
" . $spoilersearch, $spoilersearch, $s); + } + + while ((strpos($s, $spoilersearch) !== false)) { + $pos = strpos($s, $spoilersearch); + $rnd = Strings::getRandomHex(8); + $spoilerreplace = '
' . L10n::t('Click to open/close') . ''. + ''; + $s = substr($s, 0, $pos) . $spoilerreplace . substr($s, $pos + strlen($spoilersearch)); + } + + // Look for quote with author. + $authorsearch = ''; + + while ((strpos($s, $authorsearch) !== false)) { + $pos = strpos($s, $authorsearch); + $rnd = Strings::getRandomHex(8); + $authorreplace = '
' . L10n::t('Click to open/close') . ''. + ''; + $s = substr($s, 0, $pos) . $authorreplace . substr($s, $pos + strlen($authorsearch)); + } + + // Replace friendica image url size with theme preference. + if (!empty($a->theme_info['item_image_size'])) { + $ps = $a->theme_info['item_image_size']; + $s = preg_replace('|(]+src="[^"]+/photo/[0-9a-f]+)-[0-9]|', "$1-" . $ps, $s); + } + + $s = HTML::applyContentFilter($s, $filter_reasons); + + $hook_data = ['item' => $item, 'html' => $s]; + Addon::callHooks('prepare_body_final', $hook_data); + + return $hook_data['html']; + } + + /** + * get private link for item + * @param array $item + * @return boolean|array False if item has not plink, otherwise array('href'=>plink url, 'title'=>translated title) + */ + public static function getPlink($item) + { + $a = self::getApp(); + + if ($a->user['nickname'] != "") { + $ret = [ + 'href' => "display/" . $item['guid'], + 'orig' => "display/" . $item['guid'], + 'title' => L10n::t('View on separate page'), + 'orig_title' => L10n::t('view on separate page'), + ]; + + if (!empty($item['plink'])) { + $ret["href"] = $a->removeBaseURL($item['plink']); + $ret["title"] = L10n::t('link to source'); + } + + } elseif (!empty($item['plink']) && ($item['private'] != 1)) { + $ret = [ + 'href' => $item['plink'], + 'orig' => $item['plink'], + 'title' => L10n::t('link to source'), + ]; + } else { + $ret = []; + } + + return $ret; + } } diff --git a/src/Model/Profile.php b/src/Model/Profile.php index 95a6bd35b..c45bcdb84 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -25,6 +25,7 @@ use Friendica\Protocol\Diaspora; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; use Friendica\Util\Temporal; require_once 'include/dba.php'; @@ -296,7 +297,7 @@ class Profile $profile['picdate'] = urlencode(defaults($profile, 'picdate', '')); if (($profile['network'] != '') && ($profile['network'] != Protocol::DFRN)) { - $profile['network_name'] = format_network_name($profile['network'], $profile['url']); + $profile['network_name'] = Strings::formatNetworkName($profile['network'], $profile['url']); } else { $profile['network_name'] = ''; } @@ -326,9 +327,9 @@ class Profile // Is the local user already connected to that user? if ($connect && local_user()) { if (isset($profile['url'])) { - $profile_url = normalise_link($profile['url']); + $profile_url = Strings::normaliseLink($profile['url']); } else { - $profile_url = normalise_link(System::baseUrl() . '/profile/' . $profile['nickname']); + $profile_url = Strings::normaliseLink(System::baseUrl() . '/profile/' . $profile['nickname']); } if (DBA::exists('contact', ['pending' => false, 'uid' => local_user(), 'nurl' => $profile_url])) { @@ -370,7 +371,7 @@ class Profile $r = q( "SELECT `url` FROM `contact` WHERE `uid` = %d AND `nurl` = '%s' AND `rel` = %d", intval($profile['uid']), - DBA::escape(normalise_link(self::getMyURL())), + DBA::escape(Strings::normaliseLink(self::getMyURL())), intval(Contact::FRIEND) ); } @@ -881,7 +882,7 @@ class Profile $tab = false; if (x($_GET, 'tab')) { - $tab = notags(trim($_GET['tab'])); + $tab = Strings::escapeTags(trim($_GET['tab'])); } $url = System::baseUrl() . '/profile/' . $nickname; @@ -1140,7 +1141,7 @@ class Profile } $achar = strpos($s, '?') ? '&' : '?'; $mine = self::getMyURL(); - if ($mine && !link_compare($mine, $s)) { + if ($mine && !Strings::compareLink($mine, $s)) { return $s . $achar . 'zrl=' . urlencode($mine); } return $s; diff --git a/src/Model/Register.php b/src/Model/Register.php index e54db87a6..66f19133b 100644 --- a/src/Model/Register.php +++ b/src/Model/Register.php @@ -7,6 +7,7 @@ namespace Friendica\Model; use Friendica\Database\DBA; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Strings; /** * Class interacting with the register database table @@ -77,7 +78,7 @@ class Register */ public static function createForInvitation() { - $code = autoname(8) . srand(1000, 9999); + $code = Strings::getRandomName(8) . srand(1000, 9999); $fields = [ 'hash' => $code, @@ -100,7 +101,7 @@ class Register */ public static function createForApproval($uid, $language, $note = '') { - $hash = random_string(); + $hash = Strings::getRandomHex(); if (!User::exists($uid)) { return false; diff --git a/src/Model/User.php b/src/Model/User.php index 43992cc5f..0f397aadc 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -20,6 +20,7 @@ use Friendica\Object\Image; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Strings; use LightOpenID; require_once 'boot.php'; @@ -60,7 +61,7 @@ class User */ public static function getIdForURL($url) { - $self = DBA::selectFirst('contact', ['uid'], ['nurl' => normalise_link($url), 'self' => true]); + $self = DBA::selectFirst('contact', ['uid'], ['nurl' => Strings::normaliseLink($url), 'self' => true]); if (!DBA::isResult($self)) { return false; } else { @@ -269,7 +270,7 @@ class User */ public static function generateNewPassword() { - return autoname(6) . mt_rand(100, 9999); + return Strings::getRandomName(6) . mt_rand(100, 9999); } /** @@ -401,18 +402,18 @@ class User $using_invites = Config::get('system', 'invitation_only'); $num_invites = Config::get('system', 'number_invites'); - $invite_id = !empty($data['invite_id']) ? notags(trim($data['invite_id'])) : ''; - $username = !empty($data['username']) ? notags(trim($data['username'])) : ''; - $nickname = !empty($data['nickname']) ? notags(trim($data['nickname'])) : ''; - $email = !empty($data['email']) ? notags(trim($data['email'])) : ''; - $openid_url = !empty($data['openid_url']) ? notags(trim($data['openid_url'])) : ''; - $photo = !empty($data['photo']) ? notags(trim($data['photo'])) : ''; + $invite_id = !empty($data['invite_id']) ? Strings::escapeTags(trim($data['invite_id'])) : ''; + $username = !empty($data['username']) ? Strings::escapeTags(trim($data['username'])) : ''; + $nickname = !empty($data['nickname']) ? Strings::escapeTags(trim($data['nickname'])) : ''; + $email = !empty($data['email']) ? Strings::escapeTags(trim($data['email'])) : ''; + $openid_url = !empty($data['openid_url']) ? Strings::escapeTags(trim($data['openid_url'])) : ''; + $photo = !empty($data['photo']) ? Strings::escapeTags(trim($data['photo'])) : ''; $password = !empty($data['password']) ? trim($data['password']) : ''; $password1 = !empty($data['password1']) ? trim($data['password1']) : ''; $confirm = !empty($data['confirm']) ? trim($data['confirm']) : ''; $blocked = !empty($data['blocked']) ? intval($data['blocked']) : 0; $verified = !empty($data['verified']) ? intval($data['verified']) : 0; - $language = !empty($data['language']) ? notags(trim($data['language'])) : 'en'; + $language = !empty($data['language']) ? Strings::escapeTags(trim($data['language'])) : 'en'; $publish = !empty($data['profile_publish_reg']) && intval($data['profile_publish_reg']) ? 1 : 0; $netpublish = strlen(Config::get('system', 'directory')) ? $publish : 0; @@ -498,7 +499,7 @@ class User throw new Exception(L10n::t('Your email domain is not among those allowed on this site.')); } - if (!valid_email($email) || !Network::isEmailDomainValid($email)) { + if (!filter_var($email, FILTER_VALIDATE_EMAIL) || !Network::isEmailDomainValid($email)) { throw new Exception(L10n::t('Not a valid email address.')); } if (self::isNicknameBlocked($nickname)) { @@ -692,7 +693,7 @@ class User */ public static function sendRegisterPendingEmail($user, $sitename, $siteurl, $password) { - $body = deindent(L10n::t(' + $body = Strings::deindent(L10n::t(' Dear %1$s, Thank you for registering at %2$s. Your account is pending for approval by the administrator. @@ -727,13 +728,13 @@ class User */ public static function sendRegisterOpenEmail($user, $sitename, $siteurl, $password) { - $preamble = deindent(L10n::t(' + $preamble = Strings::deindent(L10n::t(' Dear %1$s, Thank you for registering at %2$s. Your account has been created. ', $preamble, $user['username'], $sitename )); - $body = deindent(L10n::t(' + $body = Strings::deindent(L10n::t(' The login details are as follows: Site Location: %3$s @@ -813,4 +814,74 @@ class User $a->internalRedirect(); } } + + /** + * Return all identities to a user + * + * @param int $uid The user id + * @return array All identities for this user + * + * Example for a return: + * [ + * [ + * 'uid' => 1, + * 'username' => 'maxmuster', + * 'nickname' => 'Max Mustermann' + * ], + * [ + * 'uid' => 2, + * 'username' => 'johndoe', + * 'nickname' => 'John Doe' + * ] + * ] + */ + public static function identities($uid) + { + $identities = []; + + $user = DBA::selectFirst('user', ['uid', 'nickname', 'username', 'parent-uid'], ['uid' => $uid]); + if (!DBA::isResult($user)) { + return $identities; + } + + if ($user['parent-uid'] == 0) { + // First add our own entry + $identities = [['uid' => $user['uid'], + 'username' => $user['username'], + 'nickname' => $user['nickname']]]; + + // Then add all the children + $r = DBA::select('user', ['uid', 'username', 'nickname'], + ['parent-uid' => $user['uid'], 'account_removed' => false]); + if (DBA::isResult($r)) { + $identities = array_merge($identities, DBA::toArray($r)); + } + } else { + // First entry is our parent + $r = DBA::select('user', ['uid', 'username', 'nickname'], + ['uid' => $user['parent-uid'], 'account_removed' => false]); + if (DBA::isResult($r)) { + $identities = DBA::toArray($r); + } + + // Then add all siblings + $r = DBA::select('user', ['uid', 'username', 'nickname'], + ['parent-uid' => $user['parent-uid'], 'account_removed' => false]); + if (DBA::isResult($r)) { + $identities = array_merge($identities, DBA::toArray($r)); + } + } + + $r = DBA::p("SELECT `user`.`uid`, `user`.`username`, `user`.`nickname` + FROM `manage` + INNER JOIN `user` ON `manage`.`mid` = `user`.`uid` + WHERE `user`.`account_removed` = 0 AND `manage`.`uid` = ?", + $user['uid'] + ); + if (DBA::isResult($r)) { + $identities = array_merge($identities, DBA::toArray($r)); + } + + return $identities; + } } diff --git a/src/Module/Contact.php b/src/Module/Contact.php index db3007598..b7e182dc1 100644 --- a/src/Module/Contact.php +++ b/src/Module/Contact.php @@ -22,6 +22,7 @@ use Friendica\Module\Login; use Friendica\Network\Probe; use Friendica\Util\DateTimeFormat; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; /** * Manages and show Contacts and their content @@ -77,7 +78,7 @@ class Contact extends BaseModule $a->data['contact'] = $contact; if (($contact['network'] != '') && ($contact['network'] != Protocol::DFRN)) { - $networkname = format_network_name($contact['network'], $contact['url']); + $networkname = Strings::formatNetworkName($contact['network'], $contact['url']); } else { $networkname = ''; } @@ -213,14 +214,14 @@ class Contact extends BaseModule $fetch_further_information = intval(defaults($_POST, 'fetch_further_information', 0)); - $ffi_keyword_blacklist = escape_tags(trim(defaults($_POST, 'ffi_keyword_blacklist', ''))); + $ffi_keyword_blacklist = Strings::escapeHtml(trim(defaults($_POST, 'ffi_keyword_blacklist', ''))); $priority = intval(defaults($_POST, 'poll', 0)); if ($priority > 5 || $priority < 0) { $priority = 0; } - $info = escape_tags(trim($_POST['info'])); + $info = Strings::escapeHtml(trim($_POST['info'])); $r = DBA::update('contact', [ 'profile-id' => $profile_id, @@ -303,7 +304,7 @@ class Contact extends BaseModule } } - $fields['nurl'] = normalise_link($data['url']); + $fields['nurl'] = Strings::normaliseLink($data['url']); if (!empty($data['priority'])) { $fields['priority'] = intval($data['priority']); @@ -601,7 +602,7 @@ class Contact extends BaseModule '$lbl_vis2' => L10n::t('Please choose the profile you would like to display to %s when viewing your profile securely.', $contact['name']), '$lbl_info1' => $lbl_info1, '$lbl_info2' => L10n::t('Their personal note'), - '$reason' => trim(notags($contact['reason'])), + '$reason' => trim(Strings::escapeTags($contact['reason'])), '$infedit' => L10n::t('Edit contact notes'), '$common_link' => 'common/loc/' . local_user() . '/' . $contact['id'], '$relation_text' => $relation_text, @@ -694,8 +695,8 @@ class Contact extends BaseModule $sql_extra .= sprintf(" AND `network` != '%s' ", Protocol::PHANTOM); - $search = notags(trim(defaults($_GET, 'search', ''))); - $nets = notags(trim(defaults($_GET, 'nets' , ''))); + $search = Strings::escapeTags(trim(defaults($_GET, 'search', ''))); + $nets = Strings::escapeTags(trim(defaults($_GET, 'nets' , ''))); $tabs = [ [ @@ -765,7 +766,7 @@ class Contact extends BaseModule if ($search) { $searching = true; $search_hdr = $search; - $search_txt = DBA::escape(protect_sprintf(preg_quote($search))); + $search_txt = DBA::escape(Strings::protectSprintf(preg_quote($search))); $sql_extra .= " AND (name REGEXP '$search_txt' OR url REGEXP '$search_txt' OR nick REGEXP '$search_txt') "; } diff --git a/src/Module/Hashtag.php b/src/Module/Hashtag.php index bfe1eee7d..4d0918352 100644 --- a/src/Module/Hashtag.php +++ b/src/Module/Hashtag.php @@ -7,6 +7,7 @@ namespace Friendica\Module; use Friendica\BaseModule; use Friendica\Core\System; use Friendica\Database\DBA; +use Friendica\Util\Strings; require_once 'include/dba.php'; require_once 'include/text.php'; @@ -21,7 +22,7 @@ class Hashtag extends BaseModule { $result = []; - $t = escape_tags($_REQUEST['t']); + $t = Strings::escapeHtml($_REQUEST['t']); if (empty($t)) { System::jsonExit($result); } diff --git a/src/Module/Install.php b/src/Module/Install.php index 2defe24ad..2e0f16c4e 100644 --- a/src/Module/Install.php +++ b/src/Module/Install.php @@ -9,6 +9,7 @@ use Friendica\Database\DBStructure; use Friendica\Core; use Friendica\Core\L10n; use Friendica\Core\Renderer; +use Friendica\Util\Strings; use Friendica\Util\Temporal; class Install extends BaseModule @@ -70,10 +71,10 @@ class Install extends BaseModule break; case self::SITE_SETTINGS: - $dbhost = notags(trim(defaults($_POST, 'dbhost', Core\Installer::DEFAULT_HOST))); - $dbuser = notags(trim(defaults($_POST, 'dbuser', ''))); - $dbpass = notags(trim(defaults($_POST, 'dbpass', ''))); - $dbdata = notags(trim(defaults($_POST, 'dbdata', ''))); + $dbhost = Strings::escapeTags(trim(defaults($_POST, 'dbhost', Core\Installer::DEFAULT_HOST))); + $dbuser = Strings::escapeTags(trim(defaults($_POST, 'dbuser', ''))); + $dbpass = Strings::escapeTags(trim(defaults($_POST, 'dbpass', ''))); + $dbdata = Strings::escapeTags(trim(defaults($_POST, 'dbdata', ''))); // If we cannot connect to the database, return to the previous step if (!self::$installer->checkDB($dbhost, $dbuser, $dbpass, $dbdata)) { @@ -84,13 +85,13 @@ class Install extends BaseModule case self::FINISHED: $urlpath = $a->getURLPath(); - $dbhost = notags(trim(defaults($_POST, 'dbhost', Core\Installer::DEFAULT_HOST))); - $dbuser = notags(trim(defaults($_POST, 'dbuser', ''))); - $dbpass = notags(trim(defaults($_POST, 'dbpass', ''))); - $dbdata = notags(trim(defaults($_POST, 'dbdata', ''))); - $timezone = notags(trim(defaults($_POST, 'timezone', Core\Installer::DEFAULT_TZ))); - $language = notags(trim(defaults($_POST, 'language', Core\Installer::DEFAULT_LANG))); - $adminmail = notags(trim(defaults($_POST, 'adminmail', ''))); + $dbhost = Strings::escapeTags(trim(defaults($_POST, 'dbhost', Core\Installer::DEFAULT_HOST))); + $dbuser = Strings::escapeTags(trim(defaults($_POST, 'dbuser', ''))); + $dbpass = Strings::escapeTags(trim(defaults($_POST, 'dbpass', ''))); + $dbdata = Strings::escapeTags(trim(defaults($_POST, 'dbdata', ''))); + $timezone = Strings::escapeTags(trim(defaults($_POST, 'timezone', Core\Installer::DEFAULT_TZ))); + $language = Strings::escapeTags(trim(defaults($_POST, 'language', Core\Installer::DEFAULT_LANG))); + $adminmail = Strings::escapeTags(trim(defaults($_POST, 'adminmail', ''))); // If we cannot connect to the database, return to the Database config wizard if (!self::$installer->checkDB($dbhost, $dbuser, $dbpass, $dbdata)) { @@ -139,12 +140,12 @@ class Install extends BaseModule break; case self::DATABASE_CONFIG: - $dbhost = notags(trim(defaults($_POST, 'dbhost' , Core\Installer::DEFAULT_HOST))); - $dbuser = notags(trim(defaults($_POST, 'dbuser' , '' ))); - $dbpass = notags(trim(defaults($_POST, 'dbpass' , '' ))); - $dbdata = notags(trim(defaults($_POST, 'dbdata' , '' ))); - $phpath = notags(trim(defaults($_POST, 'phpath' , '' ))); - $adminmail = notags(trim(defaults($_POST, 'adminmail', '' ))); + $dbhost = Strings::escapeTags(trim(defaults($_POST, 'dbhost' , Core\Installer::DEFAULT_HOST))); + $dbuser = Strings::escapeTags(trim(defaults($_POST, 'dbuser' , '' ))); + $dbpass = Strings::escapeTags(trim(defaults($_POST, 'dbpass' , '' ))); + $dbdata = Strings::escapeTags(trim(defaults($_POST, 'dbdata' , '' ))); + $phpath = Strings::escapeTags(trim(defaults($_POST, 'phpath' , '' ))); + $adminmail = Strings::escapeTags(trim(defaults($_POST, 'adminmail', '' ))); $tpl = Renderer::getMarkupTemplate('install_db.tpl'); $output .= Renderer::replaceMacros($tpl, [ @@ -190,13 +191,13 @@ class Install extends BaseModule break; case self::SITE_SETTINGS: - $dbhost = notags(trim(defaults($_POST, 'dbhost', Core\Installer::DEFAULT_HOST))); - $dbuser = notags(trim(defaults($_POST, 'dbuser', '' ))); - $dbpass = notags(trim(defaults($_POST, 'dbpass', '' ))); - $dbdata = notags(trim(defaults($_POST, 'dbdata', '' ))); - $phpath = notags(trim(defaults($_POST, 'phpath', '' ))); + $dbhost = Strings::escapeTags(trim(defaults($_POST, 'dbhost', Core\Installer::DEFAULT_HOST))); + $dbuser = Strings::escapeTags(trim(defaults($_POST, 'dbuser', '' ))); + $dbpass = Strings::escapeTags(trim(defaults($_POST, 'dbpass', '' ))); + $dbdata = Strings::escapeTags(trim(defaults($_POST, 'dbdata', '' ))); + $phpath = Strings::escapeTags(trim(defaults($_POST, 'phpath', '' ))); - $adminmail = notags(trim(defaults($_POST, 'adminmail', ''))); + $adminmail = Strings::escapeTags(trim(defaults($_POST, 'adminmail', ''))); $timezone = defaults($_POST, 'timezone', Core\Installer::DEFAULT_TZ); /* Installed langs */ diff --git a/src/Module/Login.php b/src/Module/Login.php index 751d4d4cc..0cc65c3c3 100644 --- a/src/Module/Login.php +++ b/src/Module/Login.php @@ -17,6 +17,7 @@ use Friendica\Database\DBA; use Friendica\Model\User; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Strings; use LightOpenID; require_once 'boot.php'; @@ -148,7 +149,7 @@ class Login extends BaseModule ); } } catch (Exception $e) { - Logger::log('authenticate: failed login attempt: ' . notags($username) . ' from IP ' . $_SERVER['REMOTE_ADDR']); + Logger::log('authenticate: failed login attempt: ' . Strings::escapeTags($username) . ' from IP ' . $_SERVER['REMOTE_ADDR']); info('Login failed. Please check your credentials.' . EOL); $a->internalRedirect(); } diff --git a/src/Module/Magic.php b/src/Module/Magic.php index b8af1f961..ecfe18e59 100644 --- a/src/Module/Magic.php +++ b/src/Module/Magic.php @@ -11,6 +11,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Util\HTTPSignature; use Friendica\Util\Network; +use Friendica\Util\Strings; /** * Magic Auth (remote authentication) module. @@ -49,7 +50,7 @@ class Magic extends BaseModule $contact = DBA::selectFirst('contact', ['id', 'nurl', 'url'], ['id' => $cid]); // Redirect if the contact is already authenticated on this site. - if (!empty($a->contact) && array_key_exists('id', $a->contact) && strpos($contact['nurl'], normalise_link(self::getApp()->getBaseURL())) !== false) { + if (!empty($a->contact) && array_key_exists('id', $a->contact) && strpos($contact['nurl'], Strings::normaliseLink(self::getApp()->getBaseURL())) !== false) { if ($test) { $ret['success'] = true; $ret['message'] .= 'Local site - you are already authenticated.' . EOL; @@ -74,7 +75,7 @@ class Magic extends BaseModule $headers = []; $headers['Accept'] = 'application/x-dfrn+json'; - $headers['X-Open-Web-Auth'] = random_string(); + $headers['X-Open-Web-Auth'] = Strings::getRandomHex(); // Create a header that is signed with the local users private key. $headers = HTTPSignature::createSig( @@ -94,7 +95,7 @@ class Magic extends BaseModule if ($j['encrypted_token']) { // The token is encrypted. If the local user is really the one the other instance // thinks he/she is, the token can be decrypted with the local users public key. - openssl_private_decrypt(base64url_decode($j['encrypted_token']), $token, $user['prvkey']); + openssl_private_decrypt(Strings::base64UrlDecode($j['encrypted_token']), $token, $user['prvkey']); } else { $token = $j['token']; } diff --git a/src/Module/Oembed.php b/src/Module/Oembed.php index 452162ff2..9ca4530d8 100644 --- a/src/Module/Oembed.php +++ b/src/Module/Oembed.php @@ -4,6 +4,7 @@ namespace Friendica\Module; use Friendica\BaseModule; use Friendica\Content; +use Friendica\Util\Strings; /** * Oembed module @@ -36,7 +37,7 @@ class Oembed extends BaseModule if ($a->argc == 2) { echo ''; - $url = base64url_decode($a->argv[1]); + $url = Strings::base64UrlDecode($a->argv[1]); $j = Content\OEmbed::fetchURL($url); // workaround for media.ccc.de (and any other endpoint that return size 0) diff --git a/src/Module/Owa.php b/src/Module/Owa.php index a1dbfa2f3..bfe108c84 100644 --- a/src/Module/Owa.php +++ b/src/Module/Owa.php @@ -11,6 +11,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\OpenWebAuthToken; use Friendica\Util\HTTPSignature; +use Friendica\Util\Strings; /** * @brief OpenWebAuth verifier and token generator @@ -62,7 +63,7 @@ class Owa extends BaseModule Logger::log('OWA success: ' . $contact['addr'], Logger::DATA); $ret['success'] = true; - $token = random_string(32); + $token = Strings::getRandomHex(32); // Store the generated token in the databe. OpenWebAuthToken::create('owt', 0, $token, $contact['addr']); @@ -74,7 +75,7 @@ class Owa extends BaseModule // At a later time, we will compare weather the token we're getting // is really the same token we have stored in the database. openssl_public_encrypt($token, $result, $contact['pubkey']); - $ret['encrypted_token'] = base64url_encode($result); + $ret['encrypted_token'] = Strings::base64UrlEncode($result); } else { Logger::log('OWA fail: ' . $contact['id'] . ' ' . $contact['addr'] . ' ' . $contact['url'], Logger::DEBUG); } diff --git a/src/Network/Probe.php b/src/Network/Probe.php index fc93524bf..d870e06f9 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -24,6 +24,7 @@ use Friendica\Protocol\ActivityPub; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Strings; use Friendica\Util\XML; use DomXPath; @@ -347,7 +348,7 @@ class Probe } if (x($data, "photo")) { - $data["baseurl"] = Network::getUrlMatch(normalise_link(defaults($data, "baseurl", "")), normalise_link($data["photo"])); + $data["baseurl"] = Network::getUrlMatch(Strings::normaliseLink(defaults($data, "baseurl", "")), Strings::normaliseLink($data["photo"])); } else { $data["photo"] = System::baseUrl().'/images/person-300.jpg'; } @@ -426,7 +427,7 @@ class Probe $fields['updated'] = DateTimeFormat::utcNow(); - $condition = ['nurl' => normalise_link($data["url"])]; + $condition = ['nurl' => Strings::normaliseLink($data["url"])]; $old_fields = DBA::selectFirst('gcontact', $fieldnames, $condition); @@ -473,7 +474,7 @@ class Probe } } - $condition = ['nurl' => normalise_link($data["url"]), 'self' => false, 'uid' => 0]; + $condition = ['nurl' => Strings::normaliseLink($data["url"]), 'self' => false, 'uid' => 0]; // "$old_fields" will return a "false" when the contact doesn't exist. // This won't trigger an insert. This is intended, since we only need @@ -1009,7 +1010,7 @@ class Probe foreach ($webfinger["aliases"] as $alias) { if (empty($data["url"]) && !strstr($alias, "@")) { $data["url"] = $alias; - } elseif (!strstr($alias, "@") && normalise_link($alias) != normalise_link($data["url"])) { + } elseif (!strstr($alias, "@") && Strings::normaliseLink($alias) != Strings::normaliseLink($data["url"])) { $data["alias"] = $alias; } elseif (substr($alias, 0, 5) == 'acct:') { $data["addr"] = substr($alias, 5); @@ -1212,7 +1213,7 @@ class Probe if (!empty($webfinger["aliases"]) && is_array($webfinger["aliases"])) { foreach ($webfinger["aliases"] as $alias) { - if (normalise_link($alias) != normalise_link($data["url"]) && ! strstr($alias, "@")) { + if (Strings::normaliseLink($alias) != Strings::normaliseLink($data["url"]) && ! strstr($alias, "@")) { $data["alias"] = $alias; } elseif (substr($alias, 0, 5) == 'acct:') { $data["addr"] = substr($alias, 5); @@ -1268,14 +1269,14 @@ class Probe if (!empty($webfinger["aliases"]) && is_array($webfinger["aliases"])) { foreach ($webfinger["aliases"] as $alias) { - if (strstr($alias, "@") && !strstr(normalise_link($alias), "http://")) { + if (strstr($alias, "@") && !strstr(Strings::normaliseLink($alias), "http://")) { $data["addr"] = str_replace('acct:', '', $alias); } } } if (!empty($webfinger["subject"]) && strstr($webfinger["subject"], "@") - && !strstr(normalise_link($webfinger["subject"]), "http://") + && !strstr(Strings::normaliseLink($webfinger["subject"]), "http://") ) { $data["addr"] = str_replace('acct:', '', $webfinger["subject"]); } @@ -1301,7 +1302,7 @@ class Probe } else { $pubkey = substr($pubkey, 5); } - } elseif (normalise_link($pubkey) == 'http://') { + } elseif (Strings::normaliseLink($pubkey) == 'http://') { $curlResult = Network::curl($pubkey); if ($curlResult->isTimeout()) { return false; @@ -1312,8 +1313,8 @@ class Probe $key = explode(".", $pubkey); if (sizeof($key) >= 3) { - $m = base64url_decode($key[1]); - $e = base64url_decode($key[2]); + $m = Strings::base64UrlDecode($key[1]); + $e = Strings::base64UrlDecode($key[2]); $data["pubkey"] = Crypto::meToPem($m, $e); } } @@ -1648,8 +1649,8 @@ class Probe $data["nick"] = $data["name"]; $data["photo"] = Network::lookupAvatarByEmail($uri); $data["url"] = 'mailto:'.$uri; - $data["notify"] = 'smtp '.random_string(); - $data["poll"] = 'email '.random_string(); + $data["notify"] = 'smtp ' . Strings::getRandomHex(); + $data["poll"] = 'email ' . Strings::getRandomHex(); $x = Email::messageMeta($mbox, $msgs[0]); if (stristr($x[0]->from, $uri)) { @@ -1673,7 +1674,7 @@ class Probe } } - $data["name"] = notags($data["name"]); + $data["name"] = Strings::escapeTags($data["name"]); } } } diff --git a/src/Object/Post.php b/src/Object/Post.php index 644d53e25..220168343 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -21,6 +21,7 @@ use Friendica\Model\Term; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; use Friendica\Util\Temporal; require_once 'include/dba.php'; @@ -156,7 +157,7 @@ class Post extends BaseObject $shareable = in_array($conv->getProfileOwner(), [0, local_user()]) && $item['private'] != 1; - if (local_user() && link_compare($a->contact['url'], $item['author-link'])) { + if (local_user() && Strings::compareLink($a->contact['url'], $item['author-link'])) { if ($item["event-id"] != 0) { $edpost = ["events/event/" . $item['event-id'], L10n::t("Edit")]; } else { @@ -315,7 +316,7 @@ class Post extends BaseObject localize_item($item); - $body = prepare_body($item, true); + $body = Item::prepareBody($item, true); list($categories, $folders) = get_cats_and_terms($item); @@ -392,7 +393,7 @@ class Post extends BaseObject 'owner_url' => $this->getOwnerUrl(), 'owner_photo' => $a->removeBaseURL(ProxyUtils::proxifyUrl($item['owner-avatar'], false, ProxyUtils::SIZE_THUMB)), 'owner_name' => htmlentities($owner_name_e), - 'plink' => get_plink($item), + 'plink' => Item::getPlink($item), 'edpost' => Feature::isEnabled($conv->getProfileOwner(), 'edit_posts') ? $edpost : '', 'isstarred' => $isstarred, 'star' => Feature::isEnabled($conv->getProfileOwner(), 'star_posts') ? $star : '', @@ -854,8 +855,8 @@ class Post extends BaseObject $this->owner_name = $a->page_contact['name']; $this->wall_to_wall = true; } elseif ($this->getDataValue('owner-link')) { - $owner_linkmatch = (($this->getDataValue('owner-link')) && link_compare($this->getDataValue('owner-link'), $this->getDataValue('author-link'))); - $alias_linkmatch = (($this->getDataValue('alias')) && link_compare($this->getDataValue('alias'), $this->getDataValue('author-link'))); + $owner_linkmatch = (($this->getDataValue('owner-link')) && Strings::compareLink($this->getDataValue('owner-link'), $this->getDataValue('author-link'))); + $alias_linkmatch = (($this->getDataValue('alias')) && Strings::compareLink($this->getDataValue('alias'), $this->getDataValue('author-link'))); $owner_namematch = (($this->getDataValue('owner-name')) && $this->getDataValue('owner-name') == $this->getDataValue('author-name')); if (!$owner_linkmatch && !$alias_linkmatch && !$owner_namematch) { diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index 1e5001010..bff8767f3 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -5,6 +5,8 @@ namespace Friendica\Protocol\ActivityPub; use Friendica\Database\DBA; +use Friendica\Content\Text\HTML; +use Friendica\Core\Config; use Friendica\Core\Logger; use Friendica\Core\Protocol; use Friendica\Model\Conversation; @@ -13,11 +15,10 @@ use Friendica\Model\APContact; use Friendica\Model\Item; use Friendica\Model\Event; use Friendica\Model\User; -use Friendica\Content\Text\HTML; -use Friendica\Util\JsonLD; -use Friendica\Core\Config; use Friendica\Protocol\ActivityPub; use Friendica\Util\DateTimeFormat; +use Friendica\Util\JsonLD; +use Friendica\Util\Strings; /** * ActivityPub Processor Protocol class @@ -39,6 +40,23 @@ class Processor return $body; } + /** + * Replaces emojis in the body + * + * @param array $emojis + * @param string $body + * + * @return string with replaced emojis + */ + public static function replaceEmojis($emojis, $body) + { + foreach ($emojis as $emoji) { + $replace = '[class=emoji mastodon][img=' . $emoji['href'] . ']' . $emoji['name'] . '[/img][/class]'; + $body = str_replace($emoji['name'], $replace, $body); + } + return $body; + } + /** * Constructs a string with tags for a given tag array * @@ -115,7 +133,8 @@ class Processor $item['edited'] = $activity['updated']; $item['title'] = HTML::toBBCode($activity['name']); $item['content-warning'] = HTML::toBBCode($activity['summary']); - $item['body'] = self::convertMentions(HTML::toBBCode($activity['content'])); + $content = self::replaceEmojis($activity['emojis'], HTML::toBBCode($activity['content'])); + $item['body'] = self::convertMentions($content); $item['tag'] = self::constructTagList($activity['tags'], $activity['sensitive']); Item::update($item, ['uri' => $activity['id']]); @@ -250,7 +269,8 @@ class Processor $item['guid'] = $activity['diaspora:guid']; $item['title'] = HTML::toBBCode($activity['name']); $item['content-warning'] = HTML::toBBCode($activity['summary']); - $item['body'] = self::convertMentions(HTML::toBBCode($activity['content'])); + $content = self::replaceEmojis($activity['emojis'], HTML::toBBCode($activity['content'])); + $item['body'] = self::convertMentions($content); if (($activity['object_type'] == 'as:Video') && !empty($activity['alternate-url'])) { $item['body'] .= "\n[video]" . $activity['alternate-url'] . '[/video]'; @@ -398,7 +418,7 @@ class Processor return; } - $contacts = DBA::select('contact', ['id'], ['nurl' => normalise_link($activity['object_id'])]); + $contacts = DBA::select('contact', ['id'], ['nurl' => Strings::normaliseLink($activity['object_id'])]); while ($contact = DBA::fetch($contacts)) { Contact::remove($contact['id']); } diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index 2cc165b23..686ac8be3 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -5,18 +5,19 @@ namespace Friendica\Protocol\ActivityPub; use Friendica\Database\DBA; -use Friendica\Util\HTTPSignature; use Friendica\Core\Logger; use Friendica\Core\Protocol; use Friendica\Model\Contact; use Friendica\Model\APContact; +use Friendica\Model\Conversation; use Friendica\Model\Item; use Friendica\Model\User; +use Friendica\Protocol\ActivityPub; +use Friendica\Util\DateTimeFormat; +use Friendica\Util\HTTPSignature; use Friendica\Util\JsonLD; use Friendica\Util\LDSignature; -use Friendica\Protocol\ActivityPub; -use Friendica\Model\Conversation; -use Friendica\Util\DateTimeFormat; +use Friendica\Util\Strings; /** * @brief ActivityPub Receiver Protocol class @@ -455,7 +456,7 @@ class Receiver if (($receiver == self::PUBLIC_COLLECTION) && !empty($actor)) { // This will most likely catch all OStatus connections to Mastodon - $condition = ['alias' => [$actor, normalise_link($actor)], 'rel' => [Contact::SHARING, Contact::FRIEND] + $condition = ['alias' => [$actor, Strings::normaliseLink($actor)], 'rel' => [Contact::SHARING, Contact::FRIEND] , 'archive' => false, 'pending' => false]; $contacts = DBA::select('contact', ['uid'], $condition); while ($contact = DBA::fetch($contacts)) { @@ -472,7 +473,7 @@ class Receiver } // Fetching all directly addressed receivers - $condition = ['self' => true, 'nurl' => normalise_link($receiver)]; + $condition = ['self' => true, 'nurl' => Strings::normaliseLink($receiver)]; $contact = DBA::selectFirst('contact', ['uid', 'contact-type'], $condition); if (!DBA::isResult($contact)) { continue; @@ -482,7 +483,7 @@ class Receiver // Exception: The receiver is targetted via "to" or this is a comment if ((($element != 'as:to') && empty($replyto)) || ($contact['contact-type'] == Contact::ACCOUNT_TYPE_COMMUNITY)) { $networks = [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS]; - $condition = ['nurl' => normalise_link($actor), 'rel' => [Contact::SHARING, Contact::FRIEND], + $condition = ['nurl' => Strings::normaliseLink($actor), 'rel' => [Contact::SHARING, Contact::FRIEND], 'network' => $networks, 'archive' => false, 'pending' => false, 'uid' => $contact['uid']]; // Forum posts are only accepted from forum contacts @@ -516,7 +517,7 @@ class Receiver { $receivers = []; $networks = [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS]; - $condition = ['nurl' => normalise_link($actor), 'rel' => [Contact::SHARING, Contact::FRIEND, Contact::FOLLOWER], + $condition = ['nurl' => Strings::normaliseLink($actor), 'rel' => [Contact::SHARING, Contact::FRIEND, Contact::FOLLOWER], 'network' => $networks, 'archive' => false, 'pending' => false]; $contacts = DBA::select('contact', ['uid', 'rel'], $condition); while ($contact = DBA::fetch($contacts)) { @@ -589,7 +590,7 @@ class Receiver unset($profile['photo']); unset($profile['baseurl']); - $profile['nurl'] = normalise_link($profile['url']); + $profile['nurl'] = Strings::normaliseLink($profile['url']); DBA::update('contact', $profile, ['id' => $cid]); Contact::updateAvatar($photo, $uid, $cid); @@ -614,12 +615,12 @@ class Receiver } foreach ($receivers as $receiver) { - $contact = DBA::selectFirst('contact', ['id'], ['uid' => $receiver, 'network' => Protocol::OSTATUS, 'nurl' => normalise_link($actor)]); + $contact = DBA::selectFirst('contact', ['id'], ['uid' => $receiver, 'network' => Protocol::OSTATUS, 'nurl' => Strings::normaliseLink($actor)]); if (DBA::isResult($contact)) { self::switchContact($contact['id'], $receiver, $actor); } - $contact = DBA::selectFirst('contact', ['id'], ['uid' => $receiver, 'network' => Protocol::OSTATUS, 'alias' => [normalise_link($actor), $actor]]); + $contact = DBA::selectFirst('contact', ['id'], ['uid' => $receiver, 'network' => Protocol::OSTATUS, 'alias' => [Strings::normaliseLink($actor), $actor]]); if (DBA::isResult($contact)) { self::switchContact($contact['id'], $receiver, $actor); } @@ -727,13 +728,48 @@ class Receiver continue; } - $taglist[] = ['type' => str_replace('as:', '', JsonLD::fetchElement($tag, '@type')), + $element = ['type' => str_replace('as:', '', JsonLD::fetchElement($tag, '@type')), 'href' => JsonLD::fetchElement($tag, 'as:href'), 'name' => JsonLD::fetchElement($tag, 'as:name')]; + + if (empty($element['type'])) { + continue; + } + + $taglist[] = $element; } return $taglist; } + /** + * Convert emojis from JSON-LD format into a simplified format + * + * @param array $tags Tags in JSON-LD format + * + * @return array with emojis in a simplified format + */ + private static function processEmojis($emojis) + { + $emojilist = []; + + if (empty($emojis)) { + return []; + } + + foreach ($emojis as $emoji) { + if (empty($emoji) || (JsonLD::fetchElement($emoji, '@type') != 'toot:Emoji') || empty($emoji['as:icon'])) { + continue; + } + + $url = JsonLD::fetchElement($emoji['as:icon'], 'as:url'); + $element = ['name' => JsonLD::fetchElement($emoji, 'as:name'), + 'href' => $url]; + + $emojilist[] = $element; + } + return $emojilist; + } + /** * Convert attachments from JSON-LD format into a simplified format * @@ -821,6 +857,7 @@ class Receiver $object_data['longitude'] = JsonLD::fetchElement($object_data, 'longitude', '@value'); $object_data['attachments'] = self::processAttachments(JsonLD::fetchElementArray($object, 'as:attachment')); $object_data['tags'] = self::processTags(JsonLD::fetchElementArray($object, 'as:tag')); + $object_data['emojis'] = self::processEmojis(JsonLD::fetchElementArray($object, 'as:tag', 'toot:Emoji')); $object_data['generator'] = JsonLD::fetchElement($object, 'as:generator', 'as:name', '@type', 'as:Application'); $object_data['alternate-url'] = JsonLD::fetchElement($object, 'as:url'); diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 8a2b21745..ff5081183 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -33,6 +33,7 @@ use Friendica\Object\Image; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Strings; use Friendica\Util\XML; use HTMLPurifier; use HTMLPurifier_Config; @@ -240,7 +241,7 @@ class DFRN if (isset($category)) { $sql_post_table = sprintf( "INNER JOIN (SELECT `oid` FROM `term` WHERE `term` = '%s' AND `otype` = %d AND `type` = %d AND `uid` = %d ORDER BY `tid` DESC) AS `term` ON `item`.`id` = `term`.`oid` ", - DBA::escape(protect_sprintf($category)), + DBA::escape(Strings::protectSprintf($category)), intval(TERM_OBJ_POST), intval(TERM_CATEGORY), intval($owner_id) @@ -1001,7 +1002,7 @@ class DFRN XML::addElement($doc, $entry, "updated", DateTimeFormat::utc($item["edited"] . "+00:00", DateTimeFormat::ATOM)); // "dfrn:env" is used to read the content - XML::addElement($doc, $entry, "dfrn:env", base64url_encode($body, true)); + XML::addElement($doc, $entry, "dfrn:env", Strings::base64UrlEncode($body, true)); // The "content" field is not read by the receiver. We could remove it when the type is "text" // We keep it at the moment, maybe there is some old version that doesn't read "dfrn:env" @@ -1096,7 +1097,7 @@ class DFRN } foreach ($mentioned as $mention) { - $condition = ['uid' => $owner["uid"], 'nurl' => normalise_link($mention)]; + $condition = ['uid' => $owner["uid"], 'nurl' => Strings::normaliseLink($mention)]; $contact = DBA::selectFirst('contact', ['forum', 'prv'], $condition); if (DBA::isResult($contact) && ($contact["forum"] || $contact["prv"])) { @@ -1568,7 +1569,7 @@ class DFRN $fields = ['id', 'uid', 'url', 'network', 'avatar-date', 'avatar', 'name-date', 'uri-date', 'addr', 'name', 'nick', 'about', 'location', 'keywords', 'xmpp', 'bdyear', 'bd', 'hidden', 'contact-type']; $condition = ["`uid` = ? AND `nurl` = ? AND `network` != ?", - $importer["importer_uid"], normalise_link($author["link"]), Protocol::STATUSNET]; + $importer["importer_uid"], Strings::normaliseLink($author["link"]), Protocol::STATUSNET]; $contact_old = DBA::selectFirst('contact', $fields, $condition); if (DBA::isResult($contact_old)) { @@ -1959,7 +1960,7 @@ class DFRN * * @see https://github.com/friendica/friendica/pull/3254#discussion_r107315246 */ - $condition = ['name' => $suggest["name"], 'nurl' => normalise_link($suggest["url"]), + $condition = ['name' => $suggest["name"], 'nurl' => Strings::normaliseLink($suggest["url"]), 'uid' => $suggest["uid"]]; if (DBA::exists('contact', $condition)) { return false; @@ -2009,7 +2010,7 @@ class DFRN $fid = $r[0]["id"]; - $hash = random_string(); + $hash = Strings::getRandomHex(); $r = q( "INSERT INTO `intro` (`uid`, `fid`, `contact-id`, `note`, `hash`, `datetime`, `blocked`) @@ -2099,18 +2100,18 @@ class DFRN $relocate["server_url"] = preg_replace("=(https?://)(.*)/profile/(.*)=ism", "$1$2", $relocate["url"]); $fields = ['name' => $relocate["name"], 'photo' => $relocate["avatar"], - 'url' => $relocate["url"], 'nurl' => normalise_link($relocate["url"]), + 'url' => $relocate["url"], 'nurl' => Strings::normaliseLink($relocate["url"]), 'addr' => $relocate["addr"], 'connect' => $relocate["addr"], 'notify' => $relocate["notify"], 'server_url' => $relocate["server_url"]]; - DBA::update('gcontact', $fields, ['nurl' => normalise_link($old["url"])]); + DBA::update('gcontact', $fields, ['nurl' => Strings::normaliseLink($old["url"])]); // Update the contact table. We try to find every entry. $fields = ['name' => $relocate["name"], 'avatar' => $relocate["avatar"], - 'url' => $relocate["url"], 'nurl' => normalise_link($relocate["url"]), + 'url' => $relocate["url"], 'nurl' => Strings::normaliseLink($relocate["url"]), 'addr' => $relocate["addr"], 'request' => $relocate["request"], 'confirm' => $relocate["confirm"], 'notify' => $relocate["notify"], 'poll' => $relocate["poll"], 'site-pubkey' => $relocate["sitepubkey"]]; - $condition = ["(`id` = ?) OR (`nurl` = ?)", $importer["id"], normalise_link($old["url"])]; + $condition = ["(`id` = ?) OR (`nurl` = ?)", $importer["id"], Strings::normaliseLink($old["url"])]; DBA::update('contact', $fields, $condition); @@ -2255,7 +2256,7 @@ class DFRN } } - if ($Blink && link_compare($Blink, System::baseUrl() . "/profile/" . $importer["nickname"])) { + if ($Blink && Strings::compareLink($Blink, System::baseUrl() . "/profile/" . $importer["nickname"])) { $author = DBA::selectFirst('contact', ['name', 'thumb', 'url'], ['id' => $item['author-id']]); $item['id'] = $posted_id; @@ -2493,7 +2494,7 @@ class DFRN $item["body"] = XML::getFirstNodeValue($xpath, "dfrn:env/text()", $entry); $item["body"] = str_replace([' ',"\t","\r","\n"], ['','','',''], $item["body"]); // make sure nobody is trying to sneak some html tags by us - $item["body"] = notags(base64url_decode($item["body"])); + $item["body"] = Strings::escapeTags(Strings::base64UrlDecode($item["body"])); $item["body"] = BBCode::limitBodySize($item["body"]); @@ -2737,7 +2738,7 @@ class DFRN Logger::log("Contact ".$importer["id"]." isn't known to user ".$importer["importer_uid"].". The post will be ignored.", Logger::DEBUG); return; } - if (!link_compare($item["owner-link"], $importer["url"])) { + if (!Strings::compareLink($item["owner-link"], $importer["url"])) { /* * The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, * but otherwise there's a possible data mixup on the sender's system. @@ -2985,7 +2986,7 @@ class DFRN return; } $baseurl = substr($baseurl, $domain_st + 3); - $nurl = normalise_link($baseurl); + $nurl = Strings::normaliseLink($baseurl); /// @todo Why is there a query for "url" *and* "nurl"? Especially this normalising is strange. $r = q("SELECT `id` FROM `contact` WHERE `uid` = (SELECT `uid` FROM `user` WHERE `nickname` = '%s' LIMIT 1) @@ -3030,7 +3031,7 @@ class DFRN return; } - $sec = random_string(); + $sec = Strings::getRandomHex(); DBA::insert('profile_check', ['uid' => local_user(), 'cid' => $cid, 'dfrn_id' => $dfrn_id, 'sec' => $sec, 'expire' => time() + 45]); @@ -3078,18 +3079,18 @@ class DFRN $community_page = ($user['page-flags'] == Contact::PAGE_COMMUNITY); $prvgroup = ($user['page-flags'] == Contact::PAGE_PRVGROUP); - $link = normalise_link(System::baseUrl() . '/profile/' . $user['nickname']); + $link = Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname']); /* * Diaspora uses their own hardwired link URL in @-tags * instead of the one we supply with webfinger */ - $dlink = normalise_link(System::baseUrl() . '/u/' . $user['nickname']); + $dlink = Strings::normaliseLink(System::baseUrl() . '/u/' . $user['nickname']); $cnt = preg_match_all('/[\@\!]\[url\=(.*?)\](.*?)\[\/url\]/ism', $item['body'], $matches, PREG_SET_ORDER); if ($cnt) { foreach ($matches as $mtch) { - if (link_compare($link, $mtch[1]) || link_compare($dlink, $mtch[1])) { + if (Strings::compareLink($link, $mtch[1]) || Strings::compareLink($dlink, $mtch[1])) { $mention = true; Logger::log('mention found: ' . $mtch[2]); } diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 0b5c9c949..d59eb7a0a 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -34,6 +34,7 @@ use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Map; use Friendica\Util\Network; +use Friendica\Util\Strings; use Friendica\Util\XML; use SimpleXMLElement; @@ -112,7 +113,7 @@ class Diaspora // Now we are collecting all relay contacts foreach ($serverlist as $server_url) { // We don't send messages to ourselves - if (link_compare($server_url, System::baseUrl())) { + if (Strings::compareLink($server_url, System::baseUrl())) { continue; } $contact = self::getRelayContact($server_url); @@ -146,7 +147,7 @@ class Diaspora $fields = ['batch', 'id', 'name', 'network', 'archive', 'blocked']; // Fetch the relay contact - $condition = ['uid' => 0, 'nurl' => normalise_link($server_url), + $condition = ['uid' => 0, 'nurl' => Strings::normaliseLink($server_url), 'contact-type' => Contact::ACCOUNT_TYPE_RELAY]; $contact = DBA::selectFirst('contact', $fields, $condition); @@ -185,7 +186,7 @@ class Diaspora $fields = array_merge($fields, $network_fields); - $condition = ['uid' => 0, 'nurl' => normalise_link($server_url), + $condition = ['uid' => 0, 'nurl' => Strings::normaliseLink($server_url), 'contact-type' => Contact::ACCOUNT_TYPE_RELAY]; if (DBA::exists('contact', $condition)) { @@ -297,23 +298,23 @@ class Diaspora $handle = ""; - $data = base64url_decode($children->data); + $data = Strings::base64UrlDecode($children->data); $type = $children->data->attributes()->type[0]; $encoding = $children->encoding; $alg = $children->alg; - $sig = base64url_decode($children->sig); + $sig = Strings::base64UrlDecode($children->sig); $key_id = $children->sig->attributes()->key_id[0]; if ($key_id != "") { - $handle = base64url_decode($key_id); + $handle = Strings::base64UrlDecode($key_id); } - $b64url_data = base64url_encode($data); + $b64url_data = Strings::base64UrlEncode($data); $msg = str_replace(["\n", "\r", " ", "\t"], ["", "", "", ""], $b64url_data); - $signable_data = $msg.".".base64url_encode($type).".".base64url_encode($encoding).".".base64url_encode($alg); + $signable_data = $msg.".".Strings::base64UrlEncode($type).".".Strings::base64UrlEncode($encoding).".".Strings::base64UrlEncode($alg); if ($handle == '') { Logger::log('No author could be decoded. Discarding. Message: ' . $envelope); @@ -425,10 +426,10 @@ class Diaspora $type = $base->data[0]->attributes()->type[0]; $encoding = $base->encoding; $alg = $base->alg; - $signed_data = $data.'.'.base64url_encode($type).'.'.base64url_encode($encoding).'.'.base64url_encode($alg); + $signed_data = $data.'.'.Strings::base64UrlEncode($type).'.'.Strings::base64UrlEncode($encoding).'.'.Strings::base64UrlEncode($alg); // This is the signature - $signature = base64url_decode($base->sig); + $signature = Strings::base64UrlDecode($base->sig); // Get the senders' public key $key_id = $base->sig[0]->attributes()->key_id[0]; @@ -462,7 +463,7 @@ class Diaspora } } - return ['message' => (string)base64url_decode($base->data), + return ['message' => (string)Strings::base64UrlDecode($base->data), 'author' => XML::unescape($author_addr), 'key' => (string)$key]; } @@ -546,7 +547,7 @@ class Diaspora // Stash the signature away for now. We have to find their key or it won't be good for anything. - $signature = base64url_decode($base->sig); + $signature = Strings::base64UrlDecode($base->sig); // unpack the data @@ -562,11 +563,11 @@ class Diaspora $alg = $base->alg; - $signed_data = $data.'.'.base64url_encode($type).'.'.base64url_encode($encoding).'.'.base64url_encode($alg); + $signed_data = $data.'.'.Strings::base64UrlEncode($type).'.'.Strings::base64UrlEncode($encoding).'.'.Strings::base64UrlEncode($alg); // decode the data - $data = base64url_decode($data); + $data = Strings::base64UrlDecode($data); if ($public) { @@ -1433,7 +1434,7 @@ class Diaspora */ private static function authorContactByUrl($def_contact, $person, $uid) { - $condition = ['nurl' => normalise_link($person["url"]), 'uid' => $uid]; + $condition = ['nurl' => Strings::normaliseLink($person["url"]), 'uid' => $uid]; $contact = DBA::selectFirst('contact', ['id', 'network'], $condition); if (DBA::isResult($contact)) { $cid = $contact["id"]; @@ -1505,9 +1506,9 @@ class Diaspora */ private static function receiveAccountMigration(array $importer, $data) { - $old_handle = notags(XML::unescape($data->author)); - $new_handle = notags(XML::unescape($data->profile->author)); - $signature = notags(XML::unescape($data->signature)); + $old_handle = Strings::escapeTags(XML::unescape($data->author)); + $new_handle = Strings::escapeTags(XML::unescape($data->profile->author)); + $signature = Strings::escapeTags(XML::unescape($data->signature)); $contact = self::contactByHandle($importer["uid"], $old_handle); if (!$contact) { @@ -1535,7 +1536,7 @@ class Diaspora return false; } - $fields = ['url' => $data['url'], 'nurl' => normalise_link($data['url']), + $fields = ['url' => $data['url'], 'nurl' => Strings::normaliseLink($data['url']), 'name' => $data['name'], 'nick' => $data['nick'], 'addr' => $data['addr'], 'batch' => $data['batch'], 'notify' => $data['notify'], 'poll' => $data['poll'], @@ -1543,7 +1544,7 @@ class Diaspora DBA::update('contact', $fields, ['addr' => $old_handle]); - $fields = ['url' => $data['url'], 'nurl' => normalise_link($data['url']), + $fields = ['url' => $data['url'], 'nurl' => Strings::normaliseLink($data['url']), 'name' => $data['name'], 'nick' => $data['nick'], 'addr' => $data['addr'], 'connect' => $data['addr'], 'notify' => $data['notify'], 'photo' => $data['photo'], @@ -1565,7 +1566,7 @@ class Diaspora */ private static function receiveAccountDeletion($data) { - $author = notags(XML::unescape($data->author)); + $author = Strings::escapeTags(XML::unescape($data->author)); $contacts = DBA::select('contact', ['id'], ['addr' => $author]); while ($contact = DBA::fetch($contacts)) { @@ -1656,19 +1657,19 @@ class Diaspora */ private static function receiveComment(array $importer, $sender, $data, $xml) { - $author = notags(XML::unescape($data->author)); - $guid = notags(XML::unescape($data->guid)); - $parent_guid = notags(XML::unescape($data->parent_guid)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $parent_guid = Strings::escapeTags(XML::unescape($data->parent_guid)); $text = XML::unescape($data->text); if (isset($data->created_at)) { - $created_at = DateTimeFormat::utc(notags(XML::unescape($data->created_at))); + $created_at = DateTimeFormat::utc(Strings::escapeTags(XML::unescape($data->created_at))); } else { $created_at = DateTimeFormat::utcNow(); } if (isset($data->thread_parent_guid)) { - $thread_parent_guid = notags(XML::unescape($data->thread_parent_guid)); + $thread_parent_guid = Strings::escapeTags(XML::unescape($data->thread_parent_guid)); $thr_uri = self::getUriFromGuid("", $thread_parent_guid, true); } else { $thr_uri = ""; @@ -1773,24 +1774,24 @@ class Diaspora */ private static function receiveConversationMessage(array $importer, array $contact, $data, $msg, $mesg, $conversation) { - $author = notags(XML::unescape($data->author)); - $guid = notags(XML::unescape($data->guid)); - $subject = notags(XML::unescape($data->subject)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $subject = Strings::escapeTags(XML::unescape($data->subject)); // "diaspora_handle" is the element name from the old version // "author" is the element name from the new version if ($mesg->author) { - $msg_author = notags(XML::unescape($mesg->author)); + $msg_author = Strings::escapeTags(XML::unescape($mesg->author)); } elseif ($mesg->diaspora_handle) { - $msg_author = notags(XML::unescape($mesg->diaspora_handle)); + $msg_author = Strings::escapeTags(XML::unescape($mesg->diaspora_handle)); } else { return false; } - $msg_guid = notags(XML::unescape($mesg->guid)); - $msg_conversation_guid = notags(XML::unescape($mesg->conversation_guid)); + $msg_guid = Strings::escapeTags(XML::unescape($mesg->guid)); + $msg_conversation_guid = Strings::escapeTags(XML::unescape($mesg->conversation_guid)); $msg_text = XML::unescape($mesg->text); - $msg_created_at = DateTimeFormat::utc(notags(XML::unescape($mesg->created_at))); + $msg_created_at = DateTimeFormat::utc(Strings::escapeTags(XML::unescape($mesg->created_at))); if ($msg_conversation_guid != $guid) { Logger::log("message conversation guid does not belong to the current conversation."); @@ -1861,11 +1862,11 @@ class Diaspora */ private static function receiveConversation(array $importer, $msg, $data) { - $author = notags(XML::unescape($data->author)); - $guid = notags(XML::unescape($data->guid)); - $subject = notags(XML::unescape($data->subject)); - $created_at = DateTimeFormat::utc(notags(XML::unescape($data->created_at))); - $participants = notags(XML::unescape($data->participants)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $subject = Strings::escapeTags(XML::unescape($data->subject)); + $created_at = DateTimeFormat::utc(Strings::escapeTags(XML::unescape($data->created_at))); + $participants = Strings::escapeTags(XML::unescape($data->participants)); $messages = $data->message; @@ -1919,11 +1920,11 @@ class Diaspora */ private static function receiveLike(array $importer, $sender, $data) { - $author = notags(XML::unescape($data->author)); - $guid = notags(XML::unescape($data->guid)); - $parent_guid = notags(XML::unescape($data->parent_guid)); - $parent_type = notags(XML::unescape($data->parent_type)); - $positive = notags(XML::unescape($data->positive)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $parent_guid = Strings::escapeTags(XML::unescape($data->parent_guid)); + $parent_type = Strings::escapeTags(XML::unescape($data->parent_type)); + $positive = Strings::escapeTags(XML::unescape($data->positive)); // likes on comments aren't supported by Diaspora - only on posts // But maybe this will be supported in the future, so we will accept it. @@ -2028,11 +2029,11 @@ class Diaspora */ private static function receiveMessage(array $importer, $data) { - $author = notags(XML::unescape($data->author)); - $guid = notags(XML::unescape($data->guid)); - $conversation_guid = notags(XML::unescape($data->conversation_guid)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $conversation_guid = Strings::escapeTags(XML::unescape($data->conversation_guid)); $text = XML::unescape($data->text); - $created_at = DateTimeFormat::utc(notags(XML::unescape($data->created_at))); + $created_at = DateTimeFormat::utc(Strings::escapeTags(XML::unescape($data->created_at))); $contact = self::allowedContactByHandle($importer, $author, true); if (!$contact) { @@ -2103,8 +2104,8 @@ class Diaspora */ private static function receiveParticipation(array $importer, $data) { - $author = strtolower(notags(XML::unescape($data->author))); - $parent_guid = notags(XML::unescape($data->parent_guid)); + $author = strtolower(Strings::escapeTags(XML::unescape($data->author))); + $parent_guid = Strings::escapeTags(XML::unescape($data->parent_guid)); $contact_id = Contact::getIdForURL($author); if (!$contact_id) { @@ -2196,7 +2197,7 @@ class Diaspora */ private static function receiveProfile(array $importer, $data) { - $author = strtolower(notags(XML::unescape($data->author))); + $author = strtolower(Strings::escapeTags(XML::unescape($data->author))); $contact = self::contactByHandle($importer["uid"], $author); if (!$contact) { @@ -2391,7 +2392,7 @@ class Diaspora DBA::escape($ret["addr"]), DateTimeFormat::utcNow(), DBA::escape($ret["url"]), - DBA::escape(normalise_link($ret["url"])), + DBA::escape(Strings::normaliseLink($ret["url"])), DBA::escape($batch), DBA::escape($ret["name"]), DBA::escape($ret["nick"]), @@ -2421,7 +2422,7 @@ class Diaspora if (in_array($importer["page-flags"], [Contact::PAGE_NORMAL, Contact::PAGE_PRVGROUP])) { Logger::log("Sending intra message for author ".$author.".", Logger::DEBUG); - $hash = random_string().(string)time(); // Generate a confirm_key + $hash = Strings::getRandomHex().(string)time(); // Generate a confirm_key $ret = q( "INSERT INTO `intro` (`uid`, `contact-id`, `blocked`, `knowyou`, `note`, `hash`, `datetime`) @@ -2573,13 +2574,13 @@ class Diaspora */ private static function receiveReshare(array $importer, $data, $xml) { - $author = notags(XML::unescape($data->author)); - $guid = notags(XML::unescape($data->guid)); - $created_at = DateTimeFormat::utc(notags(XML::unescape($data->created_at))); - $root_author = notags(XML::unescape($data->root_author)); - $root_guid = notags(XML::unescape($data->root_guid)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $created_at = DateTimeFormat::utc(Strings::escapeTags(XML::unescape($data->created_at))); + $root_author = Strings::escapeTags(XML::unescape($data->root_author)); + $root_guid = Strings::escapeTags(XML::unescape($data->root_guid)); /// @todo handle unprocessed property "provider_display_name" - $public = notags(XML::unescape($data->public)); + $public = Strings::escapeTags(XML::unescape($data->public)); $contact = self::allowedContactByHandle($importer, $author, false); if (!$contact) { @@ -2665,9 +2666,9 @@ class Diaspora */ private static function itemRetraction(array $importer, array $contact, $data) { - $author = notags(XML::unescape($data->author)); - $target_guid = notags(XML::unescape($data->target_guid)); - $target_type = notags(XML::unescape($data->target_type)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $target_guid = Strings::escapeTags(XML::unescape($data->target_guid)); + $target_type = Strings::escapeTags(XML::unescape($data->target_type)); $person = self::personByHandle($author); if (!is_array($person)) { @@ -2705,7 +2706,7 @@ class Diaspora $parent = Item::selectFirst(['author-link'], ['id' => $item["parent"]]); // Only delete it if the parent author really fits - if (!link_compare($parent["author-link"], $contact["url"]) && !link_compare($item["author-link"], $contact["url"])) { + if (!Strings::compareLink($parent["author-link"], $contact["url"]) && !Strings::compareLink($item["author-link"], $contact["url"])) { Logger::log("Thread author ".$parent["author-link"]." and item author ".$item["author-link"]." don't fit to expected contact ".$contact["url"], Logger::DEBUG); continue; } @@ -2729,7 +2730,7 @@ class Diaspora */ private static function receiveRetraction(array $importer, $sender, $data) { - $target_type = notags(XML::unescape($data->target_type)); + $target_type = Strings::escapeTags(XML::unescape($data->target_type)); $contact = self::contactByHandle($importer["uid"], $sender); if (!$contact && (in_array($target_type, ["Contact", "Person"]))) { @@ -2774,12 +2775,12 @@ class Diaspora */ private static function receiveStatusMessage(array $importer, SimpleXMLElement $data, $xml) { - $author = notags(XML::unescape($data->author)); - $guid = notags(XML::unescape($data->guid)); - $created_at = DateTimeFormat::utc(notags(XML::unescape($data->created_at))); - $public = notags(XML::unescape($data->public)); + $author = Strings::escapeTags(XML::unescape($data->author)); + $guid = Strings::escapeTags(XML::unescape($data->guid)); + $created_at = DateTimeFormat::utc(Strings::escapeTags(XML::unescape($data->created_at))); + $public = Strings::escapeTags(XML::unescape($data->public)); $text = XML::unescape($data->text); - $provider_display_name = notags(XML::unescape($data->provider_display_name)); + $provider_display_name = Strings::escapeTags(XML::unescape($data->provider_display_name)); $contact = self::allowedContactByHandle($importer, $author, false); if (!$contact) { @@ -2794,7 +2795,7 @@ class Diaspora $address = []; if ($data->location) { foreach ($data->location->children() as $fieldname => $data) { - $address[$fieldname] = notags(XML::unescape($data)); + $address[$fieldname] = Strings::escapeTags(XML::unescape($data)); } } @@ -2961,14 +2962,14 @@ class Diaspora */ public static function buildMagicEnvelope($msg, array $user) { - $b64url_data = base64url_encode($msg); + $b64url_data = Strings::base64UrlEncode($msg); $data = str_replace(["\n", "\r", " ", "\t"], ["", "", "", ""], $b64url_data); - $key_id = base64url_encode(self::myHandle($user)); + $key_id = Strings::base64UrlEncode(self::myHandle($user)); $type = "application/xml"; $encoding = "base64url"; $alg = "RSA-SHA256"; - $signable_data = $data.".".base64url_encode($type).".".base64url_encode($encoding).".".base64url_encode($alg); + $signable_data = $data.".".Strings::base64UrlEncode($type).".".Strings::base64UrlEncode($encoding).".".Strings::base64UrlEncode($alg); // Fallback if the private key wasn't transmitted in the expected field if ($user['uprvkey'] == "") { @@ -2976,7 +2977,7 @@ class Diaspora } $signature = Crypto::rsaSign($signable_data, $user["uprvkey"]); - $sig = base64url_encode($signature); + $sig = Strings::base64UrlEncode($signature); $xmldata = ["me:env" => ["me:data" => $data, "@attributes" => ["type" => $type], @@ -3055,7 +3056,7 @@ class Diaspora return 200; } - $logid = random_string(4); + $logid = Strings::getRandomHex(4); $dest_url = ($public_batch ? $contact["batch"] : $contact["notify"]); diff --git a/src/Protocol/Email.php b/src/Protocol/Email.php index bb70972b0..ba8c31190 100644 --- a/src/Protocol/Email.php +++ b/src/Protocol/Email.php @@ -7,6 +7,7 @@ namespace Friendica\Protocol; use Friendica\Core\Logger; use Friendica\Content\Text\HTML; use Friendica\Core\Protocol; +use Friendica\Model\Item; /** * @brief Email class @@ -331,7 +332,7 @@ class Email $part = uniqid("", true); - $html = prepare_body($item); + $html = Item::prepareBody($item); $headers .= "Mime-Version: 1.0\n"; $headers .= 'Content-Type: multipart/alternative; boundary="=_'.$part.'"'."\n\n"; diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index a1857c5db..0c096c25a 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -26,6 +26,7 @@ use Friendica\Object\Image; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; use Friendica\Util\XML; require_once 'include/dba.php'; @@ -98,7 +99,7 @@ class OStatus } $condition = ["`uid` = ? AND `nurl` IN (?, ?) AND `network` != ? AND `rel` IN (?, ?)", - $importer["uid"], normalise_link($author["author-link"]), normalise_link($aliaslink), + $importer["uid"], Strings::normaliseLink($author["author-link"]), Strings::normaliseLink($aliaslink), Protocol::STATUSNET, Contact::SHARING, Contact::FRIEND]; $contact = DBA::selectFirst('contact', [], $condition); } @@ -164,7 +165,7 @@ class OStatus // $contact["poll"] = $value; $contact['url'] = $author["author-link"]; - $contact['nurl'] = normalise_link($contact['url']); + $contact['nurl'] = Strings::normaliseLink($contact['url']); $value = XML::getFirstNodeValue($xpath, 'atom:author/atom:uri/text()', $context); if ($value != "") { @@ -209,7 +210,7 @@ class OStatus // Update it with the current values $fields = ['url' => $author["author-link"], 'name' => $contact["name"], - 'nurl' => normalise_link($author["author-link"]), + 'nurl' => Strings::normaliseLink($author["author-link"]), 'nick' => $contact["nick"], 'alias' => $contact["alias"], 'about' => $contact["about"], 'location' => $contact["location"], 'success_update' => DateTimeFormat::utcNow(), 'last-update' => DateTimeFormat::utcNow()]; @@ -1599,7 +1600,7 @@ class OStatus { $r = q( "SELECT * FROM `contact` WHERE `nurl` = '%s' AND `uid` IN (0, %d) ORDER BY `uid` DESC LIMIT 1", - DBA::escape(normalise_link($url)), + DBA::escape(Strings::normaliseLink($url)), intval($owner["uid"]) ); if (DBA::isResult($r)) { @@ -1608,7 +1609,7 @@ class OStatus } if (!DBA::isResult($r)) { - $gcontact = DBA::selectFirst('gcontact', [], ['nurl' => normalise_link($url)]); + $gcontact = DBA::selectFirst('gcontact', [], ['nurl' => Strings::normaliseLink($url)]); if (DBA::isResult($r)) { $contact = $gcontact; $contact["uid"] = -1; @@ -1651,7 +1652,7 @@ class OStatus */ private static function reshareEntry(DOMDocument $doc, array $item, array $owner, $repeated_guid, $toplevel) { - if (($item["id"] != $item["parent"]) && (normalise_link($item["author-link"]) != normalise_link($owner["url"]))) { + if (($item["id"] != $item["parent"]) && (Strings::normaliseLink($item["author-link"]) != Strings::normaliseLink($owner["url"]))) { Logger::log("OStatus entry is from author ".$owner["url"]." - not from ".$item["author-link"].". Quitting.", Logger::DEBUG); } @@ -1714,7 +1715,7 @@ class OStatus */ private static function likeEntry(DOMDocument $doc, array $item, array $owner, $toplevel) { - if (($item["id"] != $item["parent"]) && (normalise_link($item["author-link"]) != normalise_link($owner["url"]))) { + if (($item["id"] != $item["parent"]) && (Strings::normaliseLink($item["author-link"]) != Strings::normaliseLink($owner["url"]))) { Logger::log("OStatus entry is from author ".$owner["url"]." - not from ".$item["author-link"].". Quitting.", Logger::DEBUG); } @@ -1811,7 +1812,7 @@ class OStatus $item['follow'] = $contact['alias']; } - $condition = ['uid' => $owner['uid'], 'nurl' => normalise_link($contact["url"])]; + $condition = ['uid' => $owner['uid'], 'nurl' => Strings::normaliseLink($contact["url"])]; $user_contact = DBA::selectFirst('contact', ['id'], $condition); if (DBA::isResult($user_contact)) { @@ -1861,7 +1862,7 @@ class OStatus */ private static function noteEntry(DOMDocument $doc, array $item, array $owner, $toplevel) { - if (($item["id"] != $item["parent"]) && (normalise_link($item["author-link"]) != normalise_link($owner["url"]))) { + if (($item["id"] != $item["parent"]) && (Strings::normaliseLink($item["author-link"]) != Strings::normaliseLink($owner["url"]))) { Logger::log("OStatus entry is from author ".$owner["url"]." - not from ".$item["author-link"].". Quitting.", Logger::DEBUG); } @@ -2048,7 +2049,7 @@ class OStatus $mentioned = $newmentions; foreach ($mentioned as $mention) { - $condition = ['uid' => $owner['uid'], 'nurl' => normalise_link($mention)]; + $condition = ['uid' => $owner['uid'], 'nurl' => Strings::normaliseLink($mention)]; $contact = DBA::selectFirst('contact', ['forum', 'prv', 'self', 'contact-type'], $condition); if ($contact["forum"] || $contact["prv"] || ($owner['contact-type'] == Contact::ACCOUNT_TYPE_COMMUNITY) || ($contact['self'] && ($owner['account-type'] == Contact::ACCOUNT_TYPE_COMMUNITY))) { diff --git a/src/Protocol/PortableContact.php b/src/Protocol/PortableContact.php index 9c22a2163..7243da523 100644 --- a/src/Protocol/PortableContact.php +++ b/src/Protocol/PortableContact.php @@ -23,6 +23,7 @@ use Friendica\Model\Profile; use Friendica\Network\Probe; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Strings; use Friendica\Util\XML; require_once 'include/dba.php'; @@ -284,7 +285,7 @@ class PortableContact $r = q( "SELECT `id` FROM `gserver` WHERE `nurl` = '%s' AND `last_contact` > `last_failure`", - DBA::escape(normalise_link($server_url)) + DBA::escape(Strings::normaliseLink($server_url)) ); if (DBA::isResult($r)) { @@ -309,7 +310,7 @@ class PortableContact { $gcontacts = q( "SELECT * FROM `gcontact` WHERE `nurl` = '%s'", - DBA::escape(normalise_link($profile)) + DBA::escape(Strings::normaliseLink($profile)) ); if (!DBA::isResult($gcontacts)) { @@ -324,7 +325,7 @@ class PortableContact $server_url = ''; if ($force) { - $server_url = normalise_link(self::detectServer($profile)); + $server_url = Strings::normaliseLink(self::detectServer($profile)); } if (($server_url == '') && ($gcontacts[0]["server_url"] != "")) { @@ -332,7 +333,7 @@ class PortableContact } if (!$force && (($server_url == '') || ($gcontacts[0]["server_url"] == $gcontacts[0]["nurl"]))) { - $server_url = normalise_link(self::detectServer($profile)); + $server_url = Strings::normaliseLink(self::detectServer($profile)); } if (!in_array($gcontacts[0]["network"], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::FEED, Protocol::OSTATUS, ""])) { @@ -344,7 +345,7 @@ class PortableContact if (!self::checkServer($server_url, $gcontacts[0]["network"], $force)) { if ($force) { $fields = ['last_failure' => DateTimeFormat::utcNow()]; - DBA::update('gcontact', $fields, ['nurl' => normalise_link($profile)]); + DBA::update('gcontact', $fields, ['nurl' => Strings::normaliseLink($profile)]); } Logger::log("Profile ".$profile.": Server ".$server_url." wasn't reachable.", Logger::DEBUG); @@ -356,7 +357,7 @@ class PortableContact if (in_array($gcontacts[0]["network"], ["", Protocol::FEED])) { $server = q( "SELECT `network` FROM `gserver` WHERE `nurl` = '%s' AND `network` != ''", - DBA::escape(normalise_link($server_url)) + DBA::escape(Strings::normaliseLink($server_url)) ); if ($server) { @@ -369,7 +370,7 @@ class PortableContact // noscrape is really fast so we don't cache the call. if (($server_url != "") && ($gcontacts[0]["nick"] != "")) { // Use noscrape if possible - $server = q("SELECT `noscrape`, `network` FROM `gserver` WHERE `nurl` = '%s' AND `noscrape` != ''", DBA::escape(normalise_link($server_url))); + $server = q("SELECT `noscrape`, `network` FROM `gserver` WHERE `nurl` = '%s' AND `noscrape` != ''", DBA::escape(Strings::normaliseLink($server_url))); if ($server) { $curlResult = Network::curl($server[0]["noscrape"]."/".$gcontacts[0]["nick"]); @@ -425,7 +426,7 @@ class PortableContact if (!empty($noscrape["updated"])) { $fields = ['last_contact' => DateTimeFormat::utcNow()]; - DBA::update('gcontact', $fields, ['nurl' => normalise_link($profile)]); + DBA::update('gcontact', $fields, ['nurl' => Strings::normaliseLink($profile)]); Logger::log("Profile ".$profile." was last updated at ".$noscrape["updated"]." (noscrape)", Logger::DEBUG); @@ -449,11 +450,11 @@ class PortableContact // Is the profile link the alternate OStatus link notation? (http://domain.tld/user/4711) // Then check the other link and delete this one if (($data["network"] == Protocol::OSTATUS) && self::alternateOStatusUrl($profile) - && (normalise_link($profile) == normalise_link($data["alias"])) - && (normalise_link($profile) != normalise_link($data["url"])) + && (Strings::normaliseLink($profile) == Strings::normaliseLink($data["alias"])) + && (Strings::normaliseLink($profile) != Strings::normaliseLink($data["url"])) ) { // Delete the old entry - DBA::delete('gcontact', ['nurl' => normalise_link($profile)]); + DBA::delete('gcontact', ['nurl' => Strings::normaliseLink($profile)]); $gcontact = array_merge($gcontacts[0], $data); @@ -474,7 +475,7 @@ class PortableContact if (($data["poll"] == "") || (in_array($data["network"], [Protocol::FEED, Protocol::PHANTOM]))) { $fields = ['last_failure' => DateTimeFormat::utcNow()]; - DBA::update('gcontact', $fields, ['nurl' => normalise_link($profile)]); + DBA::update('gcontact', $fields, ['nurl' => Strings::normaliseLink($profile)]); Logger::log("Profile ".$profile." wasn't reachable (profile)", Logger::DEBUG); return false; @@ -490,7 +491,7 @@ class PortableContact if (!$curlResult->isSuccess()) { $fields = ['last_failure' => DateTimeFormat::utcNow()]; - DBA::update('gcontact', $fields, ['nurl' => normalise_link($profile)]); + DBA::update('gcontact', $fields, ['nurl' => Strings::normaliseLink($profile)]); Logger::log("Profile ".$profile." wasn't reachable (no feed)", Logger::DEBUG); return false; @@ -533,11 +534,11 @@ class PortableContact $fields['updated'] = $last_updated; } - DBA::update('gcontact', $fields, ['nurl' => normalise_link($profile)]); + DBA::update('gcontact', $fields, ['nurl' => Strings::normaliseLink($profile)]); if (($gcontacts[0]["generation"] == 0)) { $fields = ['generation' => 9]; - DBA::update('gcontact', $fields, ['nurl' => normalise_link($profile)]); + DBA::update('gcontact', $fields, ['nurl' => Strings::normaliseLink($profile)]); } Logger::log("Profile ".$profile." was last updated at ".$last_updated, Logger::DEBUG); @@ -930,11 +931,11 @@ class PortableContact return false; } - $gserver = DBA::selectFirst('gserver', [], ['nurl' => normalise_link($server_url)]); + $gserver = DBA::selectFirst('gserver', [], ['nurl' => Strings::normaliseLink($server_url)]); if (DBA::isResult($gserver)) { if ($gserver["created"] <= DBA::NULL_DATETIME) { $fields = ['created' => DateTimeFormat::utcNow()]; - $condition = ['nurl' => normalise_link($server_url)]; + $condition = ['nurl' => Strings::normaliseLink($server_url)]; DBA::update('gserver', $fields, $condition); } $poco = $gserver["poco"]; @@ -990,7 +991,7 @@ class PortableContact // Mastodon uses the "@" for user profiles. // But this can be misunderstood. if (parse_url($server_url, PHP_URL_USER) != '') { - DBA::update('gserver', ['last_failure' => DateTimeFormat::utcNow()], ['nurl' => normalise_link($server_url)]); + DBA::update('gserver', ['last_failure' => DateTimeFormat::utcNow()], ['nurl' => Strings::normaliseLink($server_url)]); return false; } @@ -1006,7 +1007,7 @@ class PortableContact if (DBA::isResult($gserver) && ($orig_server_url == $server_url) && ($curlResult->isTimeout())) { Logger::log("Connection to server ".$server_url." timed out.", Logger::DEBUG); - DBA::update('gserver', ['last_failure' => DateTimeFormat::utcNow()], ['nurl' => normalise_link($server_url)]); + DBA::update('gserver', ['last_failure' => DateTimeFormat::utcNow()], ['nurl' => Strings::normaliseLink($server_url)]); return false; } @@ -1021,7 +1022,7 @@ class PortableContact // Quit if there is a timeout if ($curlResult->isTimeout()) { Logger::log("Connection to server " . $server_url . " timed out.", Logger::DEBUG); - DBA::update('gserver', ['last_failure' => DateTimeFormat::utcNow()], ['nurl' => normalise_link($server_url)]); + DBA::update('gserver', ['last_failure' => DateTimeFormat::utcNow()], ['nurl' => Strings::normaliseLink($server_url)]); return false; } @@ -1048,7 +1049,7 @@ class PortableContact if (!$failure) { // This will be too low, but better than no value at all. - $registered_users = DBA::count('gcontact', ['server_url' => normalise_link($server_url)]); + $registered_users = DBA::count('gcontact', ['server_url' => Strings::normaliseLink($server_url)]); } // Look for poco @@ -1410,7 +1411,7 @@ class PortableContact } // Check again if the server exists - $found = DBA::exists('gserver', ['nurl' => normalise_link($server_url)]); + $found = DBA::exists('gserver', ['nurl' => Strings::normaliseLink($server_url)]); $version = strip_tags($version); $site_name = strip_tags($site_name); @@ -1424,9 +1425,9 @@ class PortableContact 'last_contact' => $last_contact, 'last_failure' => $last_failure]; if ($found) { - DBA::update('gserver', $fields, ['nurl' => normalise_link($server_url)]); + DBA::update('gserver', $fields, ['nurl' => Strings::normaliseLink($server_url)]); } elseif (!$failure) { - $fields['nurl'] = normalise_link($server_url); + $fields['nurl'] = Strings::normaliseLink($server_url); $fields['created'] = DateTimeFormat::utcNow(); DBA::insert('gserver', $fields); } @@ -1461,7 +1462,7 @@ class PortableContact return; } - $gserver = DBA::selectFirst('gserver', ['id', 'relay-subscribe', 'relay-scope'], ['nurl' => normalise_link($server_url)]); + $gserver = DBA::selectFirst('gserver', ['id', 'relay-subscribe', 'relay-scope'], ['nurl' => Strings::normaliseLink($server_url)]); if (!DBA::isResult($gserver)) { return; @@ -1560,7 +1561,7 @@ class PortableContact foreach ($serverlist as $server) { $server_url = str_replace("/index.php", "", $server['url']); - $r = q("SELECT `nurl` FROM `gserver` WHERE `nurl` = '%s'", DBA::escape(normalise_link($server_url))); + $r = q("SELECT `nurl` FROM `gserver` WHERE `nurl` = '%s'", DBA::escape(Strings::normaliseLink($server_url))); if (!DBA::isResult($r)) { Logger::log("Call server check for server ".$server_url, Logger::DEBUG); diff --git a/src/Protocol/Salmon.php b/src/Protocol/Salmon.php index 29abd77d0..47376890d 100644 --- a/src/Protocol/Salmon.php +++ b/src/Protocol/Salmon.php @@ -8,6 +8,7 @@ use Friendica\Core\Logger; use Friendica\Network\Probe; use Friendica\Util\Crypto; use Friendica\Util\Network; +use Friendica\Util\Strings; use Friendica\Util\XML; /** @@ -51,7 +52,7 @@ class Salmon } else { $ret[$x] = substr($ret[$x], 5); } - } elseif (normalise_link($ret[$x]) == 'http://') { + } elseif (Strings::normaliseLink($ret[$x]) == 'http://') { $ret[$x] = Network::fetchUrl($ret[$x]); } } @@ -70,7 +71,7 @@ class Salmon return $ret[0]; } else { foreach ($ret as $a) { - $hash = base64url_encode(hash('sha256', $a)); + $hash = Strings::base64UrlEncode(hash('sha256', $a)); if ($hash == $keyhash) { return $a; } @@ -104,22 +105,22 @@ class Salmon // create a magic envelope - $data = base64url_encode($slap); + $data = Strings::base64UrlEncode($slap); $data_type = 'application/atom+xml'; $encoding = 'base64url'; $algorithm = 'RSA-SHA256'; - $keyhash = base64url_encode(hash('sha256', self::salmonKey($owner['spubkey'])), true); + $keyhash = Strings::base64UrlEncode(hash('sha256', self::salmonKey($owner['spubkey'])), true); - $precomputed = '.' . base64url_encode($data_type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($algorithm); + $precomputed = '.' . Strings::base64UrlEncode($data_type) . '.' . Strings::base64UrlEncode($encoding) . '.' . Strings::base64UrlEncode($algorithm); // GNU Social format - $signature = base64url_encode(Crypto::rsaSign($data . $precomputed, $owner['sprvkey'])); + $signature = Strings::base64UrlEncode(Crypto::rsaSign($data . $precomputed, $owner['sprvkey'])); // Compliant format - $signature2 = base64url_encode(Crypto::rsaSign(str_replace('=', '', $data . $precomputed), $owner['sprvkey'])); + $signature2 = Strings::base64UrlEncode(Crypto::rsaSign(str_replace('=', '', $data . $precomputed), $owner['sprvkey'])); // Old Status.net format - $signature3 = base64url_encode(Crypto::rsaSign($data, $owner['sprvkey'])); + $signature3 = Strings::base64UrlEncode(Crypto::rsaSign($data, $owner['sprvkey'])); // At first try the non compliant method that works for GNU Social $xmldata = ["me:env" => ["me:data" => $data, @@ -208,6 +209,6 @@ class Salmon public static function salmonKey($pubkey) { Crypto::pemToMe($pubkey, $m, $e); - return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true); + return 'RSA' . '.' . Strings::base64UrlEncode($m, true) . '.' . Strings::base64UrlEncode($e, true); } } diff --git a/src/Util/Crypto.php b/src/Util/Crypto.php index 7dd0dee5c..3426babe3 100644 --- a/src/Util/Crypto.php +++ b/src/Util/Crypto.php @@ -7,6 +7,7 @@ namespace Friendica\Util; use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\Logger; +use Friendica\Util\Strings; use ASN_BASE; use ASNValue; @@ -159,8 +160,8 @@ class Crypto $r = ASN_BASE::parseASNString($x); - $m = base64url_decode($r[0]->asnData[0]->asnData); - $e = base64url_decode($r[0]->asnData[1]->asnData); + $m = Strings::base64UrlDecode($r[0]->asnData[0]->asnData); + $e = Strings::base64UrlDecode($r[0]->asnData[1]->asnData); } /** @@ -198,8 +199,8 @@ class Crypto $r = ASN_BASE::parseASNString($x); - $m = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[0]->asnData); - $e = base64url_decode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData); + $m = Strings::base64UrlDecode($r[0]->asnData[1]->asnData[0]->asnData[0]->asnData); + $e = Strings::base64UrlDecode($r[0]->asnData[1]->asnData[0]->asnData[1]->asnData); } /** @@ -355,7 +356,7 @@ class Crypto $result = ['encrypted' => true]; $key = random_bytes(256); $iv = random_bytes(256); - $result['data'] = base64url_encode(self::$fn($data, $key, $iv), true); + $result['data'] = Strings::base64UrlEncode(self::$fn($data, $key, $iv), true); // log the offending call so we can track it down if (!openssl_public_encrypt($key, $k, $pubkey)) { @@ -364,9 +365,9 @@ class Crypto } $result['alg'] = $alg; - $result['key'] = base64url_encode($k, true); + $result['key'] = Strings::base64UrlEncode($k, true); openssl_public_encrypt($iv, $i, $pubkey); - $result['iv'] = base64url_encode($i, true); + $result['iv'] = Strings::base64UrlEncode($i, true); return $result; } else { @@ -395,7 +396,7 @@ class Crypto $key = random_bytes(32); $iv = random_bytes(16); $result = ['encrypted' => true]; - $result['data'] = base64url_encode(self::encryptAES256CBC($data, $key, $iv), true); + $result['data'] = Strings::base64UrlEncode(self::encryptAES256CBC($data, $key, $iv), true); // log the offending call so we can track it down if (!openssl_public_encrypt($key, $k, $pubkey)) { @@ -404,9 +405,9 @@ class Crypto } $result['alg'] = 'aes256cbc'; - $result['key'] = base64url_encode($k, true); + $result['key'] = Strings::base64UrlEncode($k, true); openssl_public_encrypt($iv, $i, $pubkey); - $result['iv'] = base64url_encode($i, true); + $result['iv'] = Strings::base64UrlEncode($i, true); return $result; } @@ -448,10 +449,10 @@ class Crypto $fn = 'decrypt' . strtoupper($alg); if (method_exists(__CLASS__, $fn)) { - openssl_private_decrypt(base64url_decode($data['key']), $k, $prvkey); - openssl_private_decrypt(base64url_decode($data['iv']), $i, $prvkey); + openssl_private_decrypt(Strings::base64UrlDecode($data['key']), $k, $prvkey); + openssl_private_decrypt(Strings::base64UrlDecode($data['iv']), $i, $prvkey); - return self::$fn(base64url_decode($data['data']), $k, $i); + return self::$fn(Strings::base64UrlDecode($data['data']), $k, $i); } else { $x = ['data' => $data, 'prvkey' => $prvkey, 'alg' => $alg, 'result' => $data]; Addon::callHooks('other_unencapsulate', $x); @@ -471,10 +472,10 @@ class Crypto */ private static function unencapsulateAes($data, $prvkey) { - openssl_private_decrypt(base64url_decode($data['key']), $k, $prvkey); - openssl_private_decrypt(base64url_decode($data['iv']), $i, $prvkey); + openssl_private_decrypt(Strings::base64UrlDecode($data['key']), $k, $prvkey); + openssl_private_decrypt(Strings::base64UrlDecode($data['iv']), $i, $prvkey); - return self::decryptAES256CBC(base64url_decode($data['data']), $k, $i); + return self::decryptAES256CBC(Strings::base64UrlDecode($data['data']), $k, $i); } diff --git a/src/Util/JsonLD.php b/src/Util/JsonLD.php index bed7a67d6..78d81816e 100644 --- a/src/Util/JsonLD.php +++ b/src/Util/JsonLD.php @@ -90,7 +90,8 @@ class JsonLD 'dfrn' => (object)['@id' => 'http://purl.org/macgirvin/dfrn/1.0/', '@type' => '@id'], 'diaspora' => (object)['@id' => 'https://diasporafoundation.org/ns/', '@type' => '@id'], 'ostatus' => (object)['@id' => 'http://ostatus.org#', '@type' => '@id'], - 'dc' => (object)['@id' => 'http://purl.org/dc/terms/', '@type' => '@id']]; + 'dc' => (object)['@id' => 'http://purl.org/dc/terms/', '@type' => '@id'], + 'toot' => (object)['@id' => 'http://joinmastodon.org/ns#', '@type' => '@id']]; $jsonobj = json_decode(json_encode($json, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); diff --git a/src/Util/LDSignature.php b/src/Util/LDSignature.php index e53590cf3..c9fde441f 100644 --- a/src/Util/LDSignature.php +++ b/src/Util/LDSignature.php @@ -54,7 +54,7 @@ class LDSignature { $options = [ 'type' => 'RsaSignature2017', - 'nonce' => random_string(64), + 'nonce' => Strings::getRandomHex(64), 'creator' => $owner['url'] . '#main-key', 'created' => DateTimeFormat::utcNow(DateTimeFormat::ATOM) ]; diff --git a/src/Util/Network.php b/src/Util/Network.php index 0ff34f120..0ac0f2aeb 100644 --- a/src/Util/Network.php +++ b/src/Util/Network.php @@ -9,6 +9,7 @@ use Friendica\Core\Logger; use Friendica\Core\System; use Friendica\Core\Config; use Friendica\Network\CurlResult; +use Friendica\Util\Strings; use DOMDocument; use DomXPath; @@ -718,8 +719,8 @@ class Network return ""; } - $url1 = normalise_link($url1); - $url2 = normalise_link($url2); + $url1 = Strings::normaliseLink($url1); + $url2 = Strings::normaliseLink($url2); $parts1 = parse_url($url1); $parts2 = parse_url($url2); @@ -790,7 +791,7 @@ class Network $match .= $path; - return normalise_link($match); + return Strings::normaliseLink($match); } /** diff --git a/src/Util/ParseUrl.php b/src/Util/ParseUrl.php index 6530959f2..118821420 100644 --- a/src/Util/ParseUrl.php +++ b/src/Util/ParseUrl.php @@ -12,6 +12,7 @@ use Friendica\Core\Addon; use Friendica\Core\Logger; use Friendica\Database\DBA; use Friendica\Object\Image; +use Friendica\Util\Strings; require_once 'include/dba.php'; @@ -49,7 +50,7 @@ class ParseUrl } $parsed_url = DBA::selectFirst('parsed_url', ['content'], - ['url' => normalise_link($url), 'guessing' => !$no_guessing, 'oembed' => $do_oembed] + ['url' => Strings::normaliseLink($url), 'guessing' => !$no_guessing, 'oembed' => $do_oembed] ); if (!empty($parsed_url['content'])) { $data = unserialize($parsed_url['content']); @@ -61,7 +62,7 @@ class ParseUrl DBA::insert( 'parsed_url', [ - 'url' => normalise_link($url), 'guessing' => !$no_guessing, + 'url' => Strings::normaliseLink($url), 'guessing' => !$no_guessing, 'oembed' => $do_oembed, 'content' => serialize($data), 'created' => DateTimeFormat::utcNow() ], diff --git a/src/Util/Proxy.php b/src/Util/Proxy.php index 8478ce868..be70077f1 100644 --- a/src/Util/Proxy.php +++ b/src/Util/Proxy.php @@ -6,6 +6,7 @@ use Friendica\BaseModule; use Friendica\BaseObject; use Friendica\Core\Config; use Friendica\Core\System; +use Friendica\Util\Strings; /** * @brief Proxy utilities class @@ -76,7 +77,7 @@ class Proxy // Only continue if it isn't a local image and the isn't deactivated if (self::isLocalImage($url)) { - $url = str_replace(normalise_link(System::baseUrl()) . '/', System::baseUrl() . '/', $url); + $url = str_replace(Strings::normaliseLink(System::baseUrl()) . '/', System::baseUrl() . '/', $url); return $url; } @@ -140,7 +141,7 @@ class Proxy */ public static function proxifyHtml($html) { - $html = str_replace(normalise_link(System::baseUrl()) . '/', System::baseUrl() . '/', $html); + $html = str_replace(Strings::normaliseLink(System::baseUrl()) . '/', System::baseUrl() . '/', $html); return preg_replace_callback('/(]*src *= *["\'])([^"\']+)(["\'][^>]*>)/siU', 'self::replaceUrl', $html); } @@ -162,8 +163,8 @@ class Proxy } // links normalised - bug #431 - $baseurl = normalise_link(System::baseUrl()); - $url = normalise_link($url); + $baseurl = Strings::normaliseLink(System::baseUrl()); + $url = Strings::normaliseLink($url); return (substr($url, 0, strlen($baseurl)) == $baseurl); } diff --git a/src/Util/Strings.php b/src/Util/Strings.php new file mode 100644 index 000000000..48e580d67 --- /dev/null +++ b/src/Util/Strings.php @@ -0,0 +1,315 @@ +"], ['[', ']'], $string); + } + + /** + * @brief Use this on "body" or "content" input where angle chars shouldn't be removed, + * and allow them to be safely displayed. + * @param string $string + * + * @return string + */ + public static function escapeHtml($string) + { + return htmlspecialchars($string, ENT_COMPAT, 'UTF-8', false); + } + + /** + * @brief Generate a string that's random, but usually pronounceable. Used to generate initial passwords + * + * @param int $len length + * + * @return string + */ + public static function getRandomName($len) + { + if ($len <= 0) { + return ''; + } + + $vowels = ['a', 'a', 'ai', 'au', 'e', 'e', 'e', 'ee', 'ea', 'i', 'ie', 'o', 'ou', 'u']; + + if (mt_rand(0, 5) == 4) { + $vowels[] = 'y'; + } + + $cons = [ + 'b', 'bl', 'br', + 'c', 'ch', 'cl', 'cr', + 'd', 'dr', + 'f', 'fl', 'fr', + 'g', 'gh', 'gl', 'gr', + 'h', + 'j', + 'k', 'kh', 'kl', 'kr', + 'l', + 'm', + 'n', + 'p', 'ph', 'pl', 'pr', + 'qu', + 'r', 'rh', + 's' ,'sc', 'sh', 'sm', 'sp', 'st', + 't', 'th', 'tr', + 'v', + 'w', 'wh', + 'x', + 'z', 'zh' + ]; + + $midcons = ['ck', 'ct', 'gn', 'ld', 'lf', 'lm', 'lt', 'mb', 'mm', 'mn', 'mp', + 'nd', 'ng', 'nk', 'nt', 'rn', 'rp', 'rt']; + + $noend = ['bl', 'br', 'cl', 'cr', 'dr', 'fl', 'fr', 'gl', 'gr', + 'kh', 'kl', 'kr', 'mn', 'pl', 'pr', 'rh', 'tr', 'qu', 'wh', 'q']; + + $start = mt_rand(0, 2); + if ($start == 0) { + $table = $vowels; + } else { + $table = $cons; + } + + $word = ''; + + for ($x = 0; $x < $len; $x ++) { + $r = mt_rand(0, count($table) - 1); + $word .= $table[$r]; + + if ($table == $vowels) { + $table = array_merge($cons, $midcons); + } else { + $table = $vowels; + } + + } + + $word = substr($word, 0, $len); + + foreach ($noend as $noe) { + $noelen = strlen($noe); + if ((strlen($word) > $noelen) && (substr($word, -$noelen) == $noe)) { + $word = self::getRandomName($len); + break; + } + } + + return $word; + } + + /** + * @brief translate and format the networkname of a contact + * + * @param string $network Networkname of the contact (e.g. dfrn, rss and so on) + * @param string $url The contact url + * + * @return string Formatted network name + */ + public static function formatNetworkName($network, $url = 0) + { + if ($network != "") { + if ($url != "") { + $network_name = '' . ContactSelector::networkToName($network, $url) . ""; + } else { + $network_name = ContactSelector::networkToName($network); + } + + return $network_name; + } + } + + /** + * @brief Remove intentation from a text + * + * @param string $text String to be transformed. + * @param string $chr Optional. Indentation tag. Default tab (\t). + * @param int $count Optional. Default null. + * + * @return string Transformed string. + */ + public static function deindent($text, $chr = "[\t ]", $count = NULL) + { + $lines = explode("\n", $text); + + if (is_null($count)) { + $m = []; + $k = 0; + while ($k < count($lines) && strlen($lines[$k]) == 0) { + $k++; + } + preg_match("|^" . $chr . "*|", $lines[$k], $m); + $count = strlen($m[0]); + } + + for ($k = 0; $k < count($lines); $k++) { + $lines[$k] = preg_replace("|^" . $chr . "{" . $count . "}|", "", $lines[$k]); + } + + return implode("\n", $lines); + } + + /** + * @brief Get byte size returned in a Data Measurement (KB, MB, GB) + * + * @param int $bytes The number of bytes to be measured + * @param int $precision Optional. Default 2. + * + * @return string Size with measured units. + */ + public static function formatBytes($bytes, $precision = 2) + { + $units = ['B', 'KB', 'MB', 'GB', 'TB']; + $bytes = max($bytes, 0); + $pow = floor(($bytes ? log($bytes) : 0) / log(1024)); + $pow = min($pow, count($units) - 1); + $bytes /= pow(1024, $pow); + + return round($bytes, $precision) . ' ' . $units[$pow]; + } + + /** + * @brief Protect percent characters in sprintf calls + * + * @param string $s String to transform. + * + * @return string Transformed string. + */ + public static function protectSprintf($s) + { + return str_replace('%', '%%', $s); + } + + /** + * @brief Base64 Encode URL and translate +/ to -_ Optionally strip padding. + * + * @param string $s URL to encode + * @param boolean $strip_padding Optional. Default false + * + * @return string Encoded URL + */ + public static function base64UrlEncode($s, $strip_padding = false) + { + $s = strtr(base64_encode($s), '+/', '-_'); + + if ($strip_padding) { + $s = str_replace('=', '', $s); + } + + return $s; + } + + /** + * @brief Decode Base64 Encoded URL and translate -_ to +/ + * @param string $s URL to decode + * + * @return string Decoded URL + */ + public static function base64UrlDecode($s) + { + if (is_array($s)) { + Logger::log('base64url_decode: illegal input: ' . print_r(debug_backtrace(), true)); + return $s; + } + + /* + * // Placeholder for new rev of salmon which strips base64 padding. + * // PHP base64_decode handles the un-padded input without requiring this step + * // Uncomment if you find you need it. + * + * $l = strlen($s); + * if (!strpos($s,'=')) { + * $m = $l % 4; + * if ($m == 2) + * $s .= '=='; + * if ($m == 3) + * $s .= '='; + * } + * + */ + + return base64_decode(strtr($s, '-_', '+/')); + } + + /** + * @brief Normalize url + * + * @param string $url URL to be normalized. + * + * @return string Normalized URL. + */ + public static function normaliseLink($url) + { + $ret = str_replace(['https:', '//www.'], ['http:', '//'], $url); + return rtrim($ret, '/'); + } + + /** + * @brief Normalize OpenID identity + * + * @param string $s OpenID Identity + * + * @return string normalized OpenId Identity + */ + function normaliseOpenID($s) + { + return trim(str_replace(['http://', 'https://'], ['', ''], $s), '/'); + } + + /** + * @brief Compare two URLs to see if they are the same, but ignore + * slight but hopefully insignificant differences such as if one + * is https and the other isn't, or if one is www.something and + * the other isn't - and also ignore case differences. + * + * @param string $a first url + * @param string $b second url + * @return boolean True if the URLs match, otherwise False + * + */ + public static function compareLink($a, $b) + { + return (strcasecmp(self::normaliseLink($a), self::normaliseLink($b)) === 0); + } +} diff --git a/src/Worker/Delivery.php b/src/Worker/Delivery.php index 59d506af3..40230e3bd 100644 --- a/src/Worker/Delivery.php +++ b/src/Worker/Delivery.php @@ -18,6 +18,7 @@ use Friendica\Model\User; use Friendica\Protocol\DFRN; use Friendica\Protocol\Diaspora; use Friendica\Protocol\Email; +use Friendica\Util\Strings; require_once 'include/items.php'; @@ -247,8 +248,8 @@ class Delivery extends BaseObject // perform local delivery if we are on the same site - if (link_compare($basepath, System::baseUrl())) { - $condition = ['nurl' => normalise_link($contact['url']), 'self' => true]; + if (Strings::compareLink($basepath, System::baseUrl())) { + $condition = ['nurl' => Strings::normaliseLink($contact['url']), 'self' => true]; $target_self = DBA::selectFirst('contact', ['uid'], $condition); if (!DBA::isResult($target_self)) { return; diff --git a/src/Worker/DiscoverPoCo.php b/src/Worker/DiscoverPoCo.php index 72df3420e..55eeec98f 100644 --- a/src/Worker/DiscoverPoCo.php +++ b/src/Worker/DiscoverPoCo.php @@ -15,6 +15,7 @@ use Friendica\Network\Probe; use Friendica\Protocol\PortableContact; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Strings; class DiscoverPoCo { @@ -80,7 +81,7 @@ class DiscoverPoCo return; } $server_url = filter_var($server_url, FILTER_SANITIZE_URL); - if (substr(normalise_link($server_url), 0, 7) != "http://") { + if (substr(Strings::normaliseLink($server_url), 0, 7) != "http://") { return; } $result = "Checking server ".$server_url." - "; @@ -162,7 +163,7 @@ class DiscoverPoCo $urlparts = parse_url($user["url"]); if (!isset($urlparts["scheme"])) { DBA::update('gcontact', ['network' => Protocol::PHANTOM], - ['nurl' => normalise_link($user["url"])]); + ['nurl' => Strings::normaliseLink($user["url"])]); continue; } @@ -170,7 +171,7 @@ class DiscoverPoCo $networks = ["twitter.com" => Protocol::TWITTER, "identi.ca" => Protocol::PUMPIO]; DBA::update('gcontact', ['network' => $networks[$urlparts["host"]]], - ['nurl' => normalise_link($user["url"])]); + ['nurl' => Strings::normaliseLink($user["url"])]); continue; } @@ -179,7 +180,7 @@ class DiscoverPoCo if ($user["server_url"] != "") { - $force_update = (normalise_link($user["server_url"]) != normalise_link($server_url)); + $force_update = (Strings::normaliseLink($user["server_url"]) != Strings::normaliseLink($server_url)); $server_url = $user["server_url"]; } @@ -193,7 +194,7 @@ class DiscoverPoCo } } else { DBA::update('gcontact', ['last_failure' => DateTimeFormat::utcNow()], - ['nurl' => normalise_link($user["url"])]); + ['nurl' => Strings::normaliseLink($user["url"])]); } // Quit the loop after 3 minutes @@ -220,7 +221,7 @@ class DiscoverPoCo if (!empty($j->results)) { foreach ($j->results as $jj) { // Check if the contact already exists - $exists = q("SELECT `id`, `last_contact`, `last_failure`, `updated` FROM `gcontact` WHERE `nurl` = '%s'", normalise_link($jj->url)); + $exists = q("SELECT `id`, `last_contact`, `last_failure`, `updated` FROM `gcontact` WHERE `nurl` = '%s'", Strings::normaliseLink($jj->url)); if (DBA::isResult($exists)) { Logger::log("Profile ".$jj->url." already exists (".$search.")", Logger::DEBUG); diff --git a/src/Worker/GProbe.php b/src/Worker/GProbe.php index 55da28f91..4f51db2df 100644 --- a/src/Worker/GProbe.php +++ b/src/Worker/GProbe.php @@ -12,6 +12,7 @@ use Friendica\Database\DBA; use Friendica\Model\GContact; use Friendica\Network\Probe; use Friendica\Protocol\PortableContact; +use Friendica\Util\Strings; class GProbe { public static function execute($url = '') @@ -22,10 +23,10 @@ class GProbe { $r = q( "SELECT `id`, `url`, `network` FROM `gcontact` WHERE `nurl` = '%s' ORDER BY `id` LIMIT 1", - DBA::escape(normalise_link($url)) + DBA::escape(Strings::normaliseLink($url)) ); - Logger::log("gprobe start for ".normalise_link($url), Logger::DEBUG); + Logger::log("gprobe start for ".Strings::normaliseLink($url), Logger::DEBUG); if (!DBA::isResult($r)) { // Is it a DDoS attempt? @@ -51,7 +52,7 @@ class GProbe { $r = q( "SELECT `id`, `url`, `network` FROM `gcontact` WHERE `nurl` = '%s' ORDER BY `id` LIMIT 1", - DBA::escape(normalise_link($url)) + DBA::escape(Strings::normaliseLink($url)) ); } if (DBA::isResult($r)) { @@ -61,7 +62,7 @@ class GProbe { } } - Logger::log("gprobe end for ".normalise_link($url), Logger::DEBUG); + Logger::log("gprobe end for ".Strings::normaliseLink($url), Logger::DEBUG); return; } } diff --git a/src/Worker/OnePoll.php b/src/Worker/OnePoll.php index 77745b807..22fbf700a 100644 --- a/src/Worker/OnePoll.php +++ b/src/Worker/OnePoll.php @@ -18,6 +18,7 @@ use Friendica\Protocol\Email; use Friendica\Protocol\PortableContact; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; +use Friendica\Util\Strings; use Friendica\Util\XML; require_once 'include/dba.php'; @@ -474,9 +475,9 @@ class OnePoll $datarray['title'] .= $subpart->text; } } - $datarray['title'] = notags(trim($datarray['title'])); + $datarray['title'] = Strings::escapeTags(trim($datarray['title'])); - //$datarray['title'] = notags(trim($meta->subject)); + //$datarray['title'] = Strings::escapeTags(trim($meta->subject)); $datarray['created'] = DateTimeFormat::utc($meta->date); // Is it a reply? @@ -506,7 +507,7 @@ class OnePoll Logger::log("Mail: can't fetch msg ".$msg_uid." for ".$mailconf['user']); continue; } - $datarray['body'] = escape_tags($r['body']); + $datarray['body'] = Strings::escapeHtml($r['body']); $datarray['body'] = BBCode::limitBodySize($datarray['body']); Logger::log("Mail: Importing ".$msg_uid." for ".$mailconf['user']); diff --git a/src/Worker/UpdateGContact.php b/src/Worker/UpdateGContact.php index b7a78b51f..b927e61bb 100644 --- a/src/Worker/UpdateGContact.php +++ b/src/Worker/UpdateGContact.php @@ -12,6 +12,7 @@ use Friendica\Database\DBA; use Friendica\Network\Probe; use Friendica\Protocol\PortableContact; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Strings; class UpdateGContact { @@ -78,13 +79,13 @@ class UpdateGContact DBA::escape($data["nick"]), DBA::escape($data["addr"]), DBA::escape($data["photo"]), - DBA::escape(normalise_link($data["url"])) + DBA::escape(Strings::normaliseLink($data["url"])) ); q("UPDATE `contact` SET `addr` = '%s' WHERE `uid` != 0 AND `addr` = '' AND `nurl` = '%s'", DBA::escape($data["addr"]), - DBA::escape(normalise_link($data["url"])) + DBA::escape(Strings::normaliseLink($data["url"])) ); } } diff --git a/tests/Util/DBAMockTrait.php b/tests/Util/DBAMockTrait.php index 1bb69c27b..2ee54adaa 100644 --- a/tests/Util/DBAMockTrait.php +++ b/tests/Util/DBAMockTrait.php @@ -69,4 +69,117 @@ trait DBAMockTrait ->times($times) ->andReturn($return); } + + + /** + * Mocking DBA::select() + * + * @param string $tableName The name of the table + * @param array $select The Select Array (Default is []) + * @param array $where The Where Array (Default is []) + * @param object $return The array to return (Default is []) + * @param null|int $times How often the method will get used + */ + public function mockSelect($tableName, $select = [], $where = [], $return = null, $times = null) + { + if (!isset($this->dbaMock)) { + $this->dbaMock = \Mockery::mock('alias:Friendica\Database\DBA'); + } + + $this->dbaMock + ->shouldReceive('select') + ->with($tableName, $select, $where) + ->times($times) + ->andReturn($return); + } + + /** + * Mocking DBA::selectFirst() + * + * @param string $tableName The name of the table + * @param array $select The Select Array (Default is []) + * @param array $where The Where Array (Default is []) + * @param array $return The array to return (Default is []) + * @param null|int $times How often the method will get used + */ + public function mockSelectFirst($tableName, $select = [], $where = [], $return = [], $times = null) + { + if (!isset($this->dbaMock)) { + $this->dbaMock = \Mockery::mock('alias:Friendica\Database\DBA'); + } + + $this->dbaMock + ->shouldReceive('selectFirst') + ->with($tableName, $select, $where) + ->times($times) + ->andReturn($return); + } + + /** + * Mocking DBA::isResult() + * + * @param object $record The record to test + * @param bool $return True, if the DB is connected, otherwise false + * @param null|int $times How often the method will get used + */ + public function mockIsResult($record, $return = true, $times = null) + { + if (!isset($this->dbaMock)) { + $this->dbaMock = \Mockery::mock('alias:Friendica\Database\DBA'); + } + + $this->dbaMock + ->shouldReceive('isResult') + ->with($record) + ->times($times) + ->andReturn($return); + } + + /** + * Mocking DBA::isResult() + * + * @param object $record The record to test + * @param array $return The array to return + * @param null|int $times How often the method will get used + */ + public function mockToArray($record = null, $return = [], $times = null) + { + if (!isset($this->dbaMock)) { + $this->dbaMock = \Mockery::mock('alias:Friendica\Database\DBA'); + } + + $this->dbaMock + ->shouldReceive('toArray') + ->with($record) + ->times($times) + ->andReturn($return); + } + + + /** + * Mocking DBA::p() + * + * @param string $sql The SQL statement + * @param object $return The object to return + * @param null|int $times How often the method will get used + */ + public function mockP($sql = null, $return = null, $times = null) + { + if (!isset($this->dbaMock)) { + $this->dbaMock = \Mockery::mock('alias:Friendica\Database\DBA'); + } + + if (!isset($sql)) { + $this->dbaMock + ->shouldReceive('p') + ->times($times) + ->andReturn($return); + } else { + $this->dbaMock + ->shouldReceive('p') + ->with($sql) + ->times($times) + ->andReturn($return); + } + } } diff --git a/tests/include/TextTest.php b/tests/include/TextTest.php index 1422ee2ae..e516fe824 100644 --- a/tests/include/TextTest.php +++ b/tests/include/TextTest.php @@ -12,61 +12,6 @@ use PHPUnit\Framework\TestCase; */ class TextTest extends TestCase { - - /** - *autonames should be random, even length - */ - public function testAutonameEven() - { - $autoname1=autoname(10); - $autoname2=autoname(10); - - $this->assertNotEquals($autoname1, $autoname2); - } - - /** - *autonames should be random, odd length - */ - public function testAutonameOdd() - { - $autoname1=autoname(9); - $autoname2=autoname(9); - - $this->assertNotEquals($autoname1, $autoname2); - } - - /** - * try to fail autonames - */ - public function testAutonameNoLength() - { - $autoname1=autoname(0); - $this->assertEquals(0, strlen($autoname1)); - } - - /** - * try to fail it with invalid input - * - * @todo What's corect behaviour here? An exception? - */ - public function testAutonameNegativeLength() - { - $autoname1=autoname(-23); - $this->assertEquals(0, strlen($autoname1)); - } - - /** - * test with a length, that may be too short - */ - public function testAutonameLength1() - { - $autoname1=autoname(1); - $this->assertEquals(1, strlen($autoname1)); - - $autoname2=autoname(1); - $this->assertEquals(1, strlen($autoname2)); - } - /** * test attribute contains */ @@ -232,23 +177,6 @@ class TextTest extends TestCase $this->assertEquals(array(1,3), expand_acl($text)); } - /** - * test, that tags are escaped - */ - public function testEscapeTags() - { - $invalidstring=''; - - $validstring=notags($invalidstring); - $escapedString=escape_tags($invalidstring); - - $this->assertEquals('[submit type="button" onclick="alert(\'failed!\');" /]', $validstring); - $this->assertEquals( - "<submit type="button" onclick="alert('failed!');" />", - $escapedString - ); - } - /** * test hex2bin and reverse */ diff --git a/tests/src/Model/UserTest.php b/tests/src/Model/UserTest.php new file mode 100644 index 000000000..3e224fb4c --- /dev/null +++ b/tests/src/Model/UserTest.php @@ -0,0 +1,152 @@ +parent = [ + 'uid' => 1, + 'username' => 'maxmuster', + 'nickname' => 'Max Muster' + ]; + + $this->child = [ + 'uid' => 2, + 'username' => 'johndoe', + 'nickname' => 'John Doe' + ]; + + $this->manage = [ + 'uid' => 3, + 'username' => 'janesmith', + 'nickname' => 'Jane Smith' + ]; + } + + public function testIdentitiesEmpty() + { + $this->mockSelectFirst('user', + ['uid', 'nickname', 'username', 'parent-uid'], + ['uid' => $this->parent['uid']], + $this->parent, + 1 + ); + $this->mockIsResult($this->parent, false, 1); + + $record = User::identities($this->parent['uid']); + + $this->assertEquals([], $record); + } + + public function testIdentitiesAsParent() + { + $parentSelect = $this->parent; + $parentSelect['parent-uid'] = 0; + + // Select the user itself (=parent) + $this->mockSelectFirst('user', + ['uid', 'nickname', 'username', 'parent-uid'], + ['uid' => $this->parent['uid']], + $parentSelect, + 1 + ); + $this->mockIsResult($parentSelect, true, 1); + + // Select one child + $this->mockSelect('user', + ['uid', 'username', 'nickname'], + [ + 'parent-uid' => $this->parent['uid'], + 'account_removed' => false + ], + 'objectReturn', + 1 + ); + $this->mockIsResult('objectReturn', true, 1); + $this->mockToArray('objectReturn', [ $this->child ], 1); + + // Select the manage + $this->mockP(null, 'objectTwo', 1); + $this->mockIsResult('objectTwo', true, 1); + $this->mockToArray('objectTwo', [ $this->manage ], 1); + + $record = User::identities($this->parent['uid']); + + $this->assertEquals([ + $this->parent, + $this->child, + $this->manage + ], $record); + } + + public function testIdentitiesAsChild() + { + $childSelect = $this->child; + $childSelect['parent-uid'] = $this->parent['uid']; + + // Select the user itself (=child) + $this->mockSelectFirst('user', + ['uid', 'nickname', 'username', 'parent-uid'], + ['uid' => $this->child['uid']], + $childSelect, + 1 + ); + $this->mockIsResult($childSelect, true, 1); + + // Select the parent + $this->mockSelect('user', + ['uid', 'username', 'nickname'], + [ + 'uid' => $this->parent['uid'], + 'account_removed' => false + ], + 'objectReturn', + 1 + ); + $this->mockIsResult('objectReturn', true, 1); + $this->mockToArray('objectReturn', [ $this->parent ], 1); + + // Select the childs (user & manage) + $this->mockSelect('user', + ['uid', 'username', 'nickname'], + [ + 'parent-uid' => $this->parent['uid'], + 'account_removed' => false + ], + 'objectReturn', + 1 + ); + $this->mockIsResult('objectReturn', true, 1); + $this->mockToArray('objectReturn', [ $this->child, $this->manage ], 1); + + // Select the manage + $this->mockP(null, 'objectTwo', 1); + $this->mockIsResult('objectTwo', false, 1); + + $record = User::identities($this->child['uid']); + + $this->assertEquals([ + $this->parent, + $this->child, + $this->manage + ], $record); + } +} diff --git a/tests/src/Util/StringsTest.php b/tests/src/Util/StringsTest.php new file mode 100644 index 000000000..21349c848 --- /dev/null +++ b/tests/src/Util/StringsTest.php @@ -0,0 +1,85 @@ +assertNotEquals($randomname1, $randomname2); + } + + /** + * randomnames should be random, odd length + */ + public function testRandomOdd() + { + $randomname1 = Strings::getRandomName(9); + $randomname2 = Strings::getRandomName(9); + + $this->assertNotEquals($randomname1, $randomname2); + } + + /** + * try to fail ramdonnames + */ + public function testRandomNameNoLength() + { + $randomname1 = Strings::getRandomName(0); + $this->assertEquals(0, strlen($randomname1)); + } + + /** + * try to fail it with invalid input + * + * @todo What's corect behaviour here? An exception? + */ + public function testRandomNameNegativeLength() + { + $randomname1 = Strings::getRandomName(-23); + $this->assertEquals(0, strlen($randomname1)); + } + + /** + * test with a length, that may be too short + */ + public function testRandomNameLength1() + { + $randomname1 = Strings::getRandomName(1); + $this->assertEquals(1, strlen($randomname1)); + + $randomname2 = Strings::getRandomName(1); + $this->assertEquals(1, strlen($randomname2)); + } + + /** + * test, that tags are escaped + */ + public function testEscapeHtml() + { + $invalidstring=' '; + + $validstring = Strings::escapeTags($invalidstring); + $escapedString = Strings::escapeHtml($invalidstring); + + $this->assertEquals('[submit type="button" onclick="alert(\'failed!\');" /]', $validstring); + $this->assertEquals( + "<submit type="button" onclick="alert('failed!');" />", + $escapedString + ); + } +} diff --git a/view/global.css b/view/global.css index b46862d5a..48755b89d 100644 --- a/view/global.css +++ b/view/global.css @@ -602,3 +602,8 @@ img.invalid-src:after { vertical-align: top;} #register-explicid-content { font-weight: bold; } + +span.emoji.mastodon img { + height: 1.2em; + vertical-align: middle; +} diff --git a/view/theme/frio/theme.php b/view/theme/frio/theme.php index c7d38baeb..aa59081d9 100644 --- a/view/theme/frio/theme.php +++ b/view/theme/frio/theme.php @@ -20,6 +20,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\Model; use Friendica\Module; +use Friendica\Util\Strings; $frio = 'view/theme/frio'; @@ -300,7 +301,7 @@ function frio_remote_nav($a, &$nav) */ function frio_acl_lookup(App $a, &$results) { - $nets = x($_GET, 'nets') ? notags(trim($_GET['nets'])) : ''; + $nets = x($_GET, 'nets') ? Strings::escapeTags(trim($_GET['nets'])) : ''; // we introduce a new search type, r should do the same query like it's // done in /src/Module/Contact.php for connections @@ -310,7 +311,7 @@ function frio_acl_lookup(App $a, &$results) $sql_extra = ''; if ($results['search']) { - $search_txt = DBA::escape(protect_sprintf(preg_quote($results['search']))); + $search_txt = DBA::escape(Strings::protectSprintf(preg_quote($results['search']))); $sql_extra .= " AND (`attag` LIKE '%%" . $search_txt . "%%' OR `name` LIKE '%%" . $search_txt . "%%' OR `nick` LIKE '%%" . $search_txt . "%%') "; } diff --git a/view/theme/vier/theme.php b/view/theme/vier/theme.php index fb4f66431..9427f1f23 100644 --- a/view/theme/vier/theme.php +++ b/view/theme/vier/theme.php @@ -21,6 +21,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\GContact; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; function vier_init(App $a) { @@ -277,7 +278,7 @@ function vier_community_info() $query .= ","; } - $query .= "'".DBA::escape(normalise_link(trim($helper)))."'"; + $query .= "'".DBA::escape(Strings::normaliseLink(trim($helper)))."'"; } $r = q("SELECT `url`, `name` FROM `gcontact` WHERE `nurl` IN (%s)", $query);