= 3) ? '' : '/') . (($achar === '?') ? '?f=&' : '&') . 'zid=' . urlencode($myaddr); } else { $zurl = $s; } // put fragment at the end if ($fragment) { $zurl .= '#' . $fragment; } $arr = [ 'url' => $s, 'zid' => urlencode($myaddr), 'result' => $zurl ]; /** * @hooks zid * Called when adding the observer's zid to a URL. * * \e string \b url - url to accept zid * * \e string \b zid - urlencoded zid * * \e string \b result - the return string we calculated, change it if you want to return something else */ Hook::call('zid', $arr); return $arr['result']; } function strip_query_param($s, $param) { return preg_replace('/[\?&]' . $param . '=(.*?)(&|$)/ism', '$2', $s); } function strip_zids($s) { return preg_replace('/[\?&]zid=(.*?)(&|$)/ism', '$2', $s); } function strip_accesstokens($s) { return preg_replace('/[\?&]token=(.*?)(&|$)/ism', '$2', $s); } function strip_owt($s) { return preg_replace('/[\?&]owt=(.*?)(&|$)/ism', '$2', $s); } function strip_zats($s) { return preg_replace('/[\?&]zat=(.*?)(&|$)/ism', '$2', $s); } function strip_escaped_zids($s) { $x = preg_replace('/&\;zid=(.*?)(&|$)/ism', '$2', $s); return strip_query_param($x, 'f'); } function clean_query_string($s = '') { $x = strip_zids(($s) ? $s : App::$query_string); $x = strip_owt($x); $x = strip_zats($x); $x = strip_query_param($x, 'sort'); return strip_query_param($x, 'f'); } /** * zidify_callback() and zidify_links() work together to turn any HTML a tags with class="zrl" into zid links * These will typically be generated by a bbcode '[zrl]' tag. This is done inside prepare_text() rather than bbcode() * because the latter is used for general purpose conversions and the former is used only when preparing text for * immediate display. * * * @param array $match * @return string */ function zidify_callback($match) { $arr = [ 'zid' => ((strpos($match[1], 'zrl') || strpos($match[3], 'zrl')) ? true : false), 'url' => $match[2] ]; Hook::call('zidify', $arr); $replace = ''; $x = str_replace($match[0], $replace, $match[0]); return $x; } function zidify_img_callback($match) { $arr = [ 'zid' => ((strpos($match[1], 'zrl') || strpos($match[3], 'zrl')) ? true : false), 'url' => $match[2] ]; Hook::call('zidify', $arr); $replace = ''; $x = str_replace($match[0], $replace, $match[0]); return $x; } function zidify_links($s) { $s = preg_replace_callback('/\/ism', 'zidify_callback', $s); $s = preg_replace_callback('/\/ism', 'zidify_img_callback', $s); return $s; } function zidify_text_callback($match) { $is_zid = isOWAEnabled($match[2]); $replace = ''; $x = str_replace($match[0], $replace, $match[0]); return $x; } function zidify_text_img_callback($match) { $is_zid = isOWAEnabled($match[2]); $replace = ''; $x = str_replace($match[0], $replace, $match[0]); return $x; } function zidify_text($s) { $s = preg_replace_callback('/\/ism', 'zidify_text_callback', $s); $s = preg_replace_callback('/\/ism', 'zidify_text_img_callback', $s); return $s; } /** * @brief preg_match function when fixing 'naked' links in mod item.php. * * Check if we've got a hubloc for the site and use a zrl if we do, a url if we don't. * Remove any existing zid= param which may have been pasted by mistake - and will have * the author's credentials. zid's are dynamic and can't really be passed around like * that. * * @param array $matches * @return string */ function red_zrl_callback($matches) { $zrl = isOWAEnabled($matches[2]); $t = strip_zids($matches[2]); if ($t !== $matches[2]) { $zrl = true; $matches[2] = $t; } if ($matches[1] === '#^') { $matches[1] = ''; } if ($zrl) { return $matches[1] . '[zrl=' . $matches[2] . ']' . $matches[2] . '[/zrl]'; } return $matches[1] . '[url=' . $matches[2] . ']' . $matches[2] . '[/url]'; } /** * If we've got a url or zrl tag with a naked url somewhere in the link text, * escape it with quotes unless the naked url is a linked photo. * * @param array $matches * @return string */ function red_escape_zrl_callback($matches) { // Uncertain why the url/zrl forms weren't picked up by the non-greedy regex. if ((strpos($matches[3], 'zmg') !== false) || (strpos($matches[3], 'img') !== false) || (strpos($matches[3], 'zrl') !== false) || (strpos($matches[3], 'url') !== false)) { return $matches[0]; } return '[' . $matches[1] . 'rl' . $matches[2] . ']' . $matches[3] . '"' . $matches[4] . '"' . $matches[5] . '[/' . $matches[6] . 'rl]'; } function red_escape_codeblock($m) { return '[$b64' . $m[2] . base64_encode($m[1]) . '[/' . $m[2] . ']'; } function red_unescape_codeblock($m) { return '[' . $m[2] . base64_decode($m[1]) . '[/' . $m[2] . ']'; } function red_zrlify_img_callback($matches) { $zrl = isOWAEnabled($matches[2]); $t = strip_zids($matches[2]); if ($t !== $matches[2]) { $zrl = true; $matches[2] = $t; } if ($zrl) { return '[zmg' . $matches[1] . ']' . $matches[2] . '[/zmg]'; } return $matches[0]; } /** * @brief OpenWebAuth authentication. * * @param string $token */ function owt_init($token) { require_once('include/security.php'); Verify::purge('owt', '3 MINUTE'); $ob_hash = Verify::get_meta('owt', 0, $token); if ($ob_hash === false) { return; } $r = q( "select * from hubloc left join xchan on xchan_hash = hubloc_hash where (hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s') and hubloc_deleted = 0 order by hubloc_id desc", dbesc($ob_hash), dbesc($ob_hash), dbesc($ob_hash) ); if (! $r) { // finger them if they can't be found. $wf = discover_resource($ob_hash, verify: false); if ($wf) { $r = q( "select * from hubloc left join xchan on xchan_hash = hubloc_hash where (hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s') and hubloc_deleted = 0 order by hubloc_id desc", dbesc($ob_hash), dbesc($ob_hash), dbesc($ob_hash) ); } } if (! $r) { logger('owt: unable to finger ' . $ob_hash); return; } $r = Libzot::zot_record_preferred($r); $hubloc = $r; $_SESSION['authenticated'] = 1; $delegate_success = false; if ($_REQUEST['delegate']) { $r = q( "select * from channel left join xchan on channel_hash = xchan_hash where xchan_addr = '%s' limit 1", dbesc($_REQUEST['delegate']) ); if ($r && intval($r[0]['channel_id'])) { $allowed = perm_is_allowed($r[0]['channel_id'], $hubloc['xchan_hash'], 'delegate'); if ($allowed) { $_SESSION['delegate_channel'] = $r[0]['channel_id']; $_SESSION['delegate'] = $hubloc['xchan_hash']; $_SESSION['account_id'] = intval($r[0]['channel_account_id']); // this will set the local_channel authentication in the session change_channel($r[0]['channel_id']); $delegate_success = true; } // experimental 2022-03-16 // $allowed = perm_is_allowed($r[0]['channel_id'], $hubloc['xchan_hash'], 'full_control'); // if ($allowed) { // $_SESSION['account_id'] = intval($r[0]['channel_account_id']); // // this will set the local_channel authentication in the session // change_channel($r[0]['channel_id']); // $delegate_success = true; // } } } if (! $delegate_success) { // normal visitor (remote_channel) login session credentials $_SESSION['visitor_id'] = $hubloc['xchan_hash']; $_SESSION['my_url'] = $hubloc['xchan_url']; $_SESSION['my_address'] = $hubloc['hubloc_addr']; $_SESSION['remote_hub'] = $hubloc['hubloc_url']; $_SESSION['DNT'] = 1; } $arr = [ 'xchan' => $hubloc, 'url' => App::$query_string, 'session' => $_SESSION ]; /** * @hooks magic_auth_success * Called when a magic-auth was successful. * * \e array \b xchan * * \e string \b url * * \e array \b session */ Hook::call('magic_auth_success', $arr); App::set_observer($hubloc); if (! get_config('system', 'hide_owa_greeting')) { info(sprintf(t('OpenWebAuth: %1$s welcomes %2$s'), App::get_hostname(), $hubloc['xchan_name'])); } logger('OpenWebAuth: auth success from ' . $hubloc['xchan_addr']); return; } function observer_auth($ob_hash) { require_once('include/security.php'); if ($ob_hash === false) { return; } $r = q( "select * from hubloc left join xchan on xchan_hash = hubloc_hash where (hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s') and hubloc_deleted = 0 order by hubloc_id desc", dbesc($ob_hash), dbesc($ob_hash), dbesc($ob_hash) ); if (! $r) { // finger them if they can't be found. $wf = discover_resource($ob_hash, verify: false); if ($wf) { $r = q( "select * from hubloc left join xchan on xchan_hash = hubloc_hash where (hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s') and hubloc_deleted = 0 order by hubloc_id desc", dbesc($ob_hash), dbesc($ob_hash), dbesc($ob_hash) ); } } if (! $r) { logger('unable to finger ' . $ob_hash); return; } $hubloc = $r[0]; $_SESSION['authenticated'] = 1; // normal visitor (remote_channel) login session credentials $_SESSION['visitor_id'] = $hubloc['xchan_hash']; $_SESSION['my_url'] = $hubloc['xchan_url']; // For now, only enable authenticated link substitution for zot6 channels or // those that arrive with a zid. // This is to prevent signed ActivityPub fetches from getting zid-enabled links. // If a pre-set zid applies, $_SESSION['my_address'] will have been set already // in Code\Web\WebServer.php if (isOWAEnabled($hubloc['hubloc_url'])) { $_SESSION['my_address'] = $hubloc['hubloc_addr']; } $_SESSION['remote_hub'] = $hubloc['hubloc_url']; $_SESSION['DNT'] = 1; App::set_observer($hubloc); }