streams/include/zid.php

465 lines
12 KiB
PHP
Raw Normal View History

<?php
use Zotlabs\Lib\Libzot;
2020-01-29 05:20:22 +00:00
use Zotlabs\Lib\Verify;
2021-12-03 03:01:39 +00:00
function is_matrix_url($url)
{
2021-12-03 03:01:39 +00:00
// in-memory cache to avoid repeated queries for the same host
static $remembered = [];
2021-12-03 03:01:39 +00:00
$m = @parse_url($url);
if (isset($m['host']) && $m['host']) {
if (in_array($m['host'], $remembered)) {
return true;
}
$r = q("select hubloc_url from hubloc where hubloc_host = '%s' and hubloc_network in ('nomad','zot6') limit 1",
2021-12-03 03:01:39 +00:00
dbesc($m['host'])
);
if ($r) {
$remembered[] = $m['host'];
return true;
}
}
return false;
}
/**
* @brief Adds a zid parameter to a url.
*
* @param string $s
* The url to accept the zid
2021-12-02 23:02:31 +00:00
* @param bool $address
* $address to use instead of session environment
* @return string
*/
2021-12-03 03:01:39 +00:00
function zid($s, $address = '')
{
if (! strlen($s) || strpos($s, 'zid=')) {
return $s;
}
$m = parse_url($s);
$fragment = ((array_key_exists('fragment', $m) && $m['fragment']) ? $m['fragment'] : false);
if ($fragment !== false) {
$s = str_replace('#' . $fragment, '', $s);
}
$has_params = ((strpos($s, '?')) ? true : false);
$num_slashes = substr_count($s, '/');
if (! $has_params) {
$has_params = ((strpos($s, '&')) ? true : false);
}
$achar = strpos($s, '?') ? '&' : '?';
$mine = get_my_url();
$myaddr = (($address) ? $address : get_my_address());
$mine_parsed = parse_url($mine);
$s_parsed = parse_url($s);
$url_match = false;
if (
isset($mine_parsed['host']) && isset($s_parsed['host'])
&& $mine_parsed['host'] === $s_parsed['host']
) {
$url_match = true;
}
if ($mine && $myaddr && (! $url_match)) {
$zurl = $s . (($num_slashes >= 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
*/
call_hooks('zid', $arr);
return $arr['result'];
}
2021-12-03 03:01:39 +00:00
function strip_query_param($s, $param)
{
return preg_replace('/[\?&]' . $param . '=(.*?)(&|$)/ism', '$2', $s);
2017-09-08 00:56:02 +00:00
}
2021-12-03 03:01:39 +00:00
function strip_zids($s)
{
return preg_replace('/[\?&]zid=(.*?)(&|$)/ism', '$2', $s);
}
2021-12-03 03:01:39 +00:00
function strip_owt($s)
{
return preg_replace('/[\?&]owt=(.*?)(&|$)/ism', '$2', $s);
2017-11-03 21:07:00 +00:00
}
2021-12-03 03:01:39 +00:00
function strip_zats($s)
{
return preg_replace('/[\?&]zat=(.*?)(&|$)/ism', '$2', $s);
}
2021-12-03 03:01:39 +00:00
function strip_escaped_zids($s)
{
$x = preg_replace('/&amp\;zid=(.*?)(&|$)/ism', '$2', $s);
return strip_query_param($x, 'f');
}
2017-11-03 21:07:00 +00:00
2021-12-03 03:01:39 +00:00
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');
2017-11-03 21:07:00 +00:00
2021-12-03 03:01:39 +00:00
return strip_query_param($x, 'f');
2017-11-03 21:07:00 +00:00
}
/**
* 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
*/
2018-07-02 04:07:35 +00:00
2021-12-03 03:01:39 +00:00
function zidify_callback($match)
{
2021-12-03 03:01:39 +00:00
$arr = [ 'zid' => ((strpos($match[1], 'zrl') || strpos($match[3], 'zrl')) ? true : false), 'url' => $match[2] ];
call_hooks('zidify', $arr);
2021-12-03 03:01:39 +00:00
$replace = '<a' . $match[1] . ' href="' . (intval($arr['zid']) ? zid($arr['url']) : $arr['url']) . '"' . $match[3] . '>';
2021-12-03 03:01:39 +00:00
$x = str_replace($match[0], $replace, $match[0]);
2021-12-03 03:01:39 +00:00
return $x;
}
2021-12-03 03:01:39 +00:00
function zidify_img_callback($match)
{
2021-12-03 03:01:39 +00:00
$arr = [ 'zid' => ((strpos($match[1], 'zrl') || strpos($match[3], 'zrl')) ? true : false), 'url' => $match[2] ];
call_hooks('zidify', $arr);
2021-12-03 03:01:39 +00:00
$replace = '<img' . $match[1] . ' src="' . (intval($arr['zid']) ? zid($arr['url']) : $arr['url']) . '"' . $match[3] . '>';
2021-12-03 03:01:39 +00:00
$x = str_replace($match[0], $replace, $match[0]);
2021-12-03 03:01:39 +00:00
return $x;
}
2021-12-03 03:01:39 +00:00
function zidify_links($s)
{
$s = preg_replace_callback('/\<a(.*?)href\=\"(.*?)\"(.*?)\>/ism', 'zidify_callback', $s);
$s = preg_replace_callback('/\<img(.*?)src\=\"(.*?)\"(.*?)\>/ism', 'zidify_img_callback', $s);
2021-12-03 03:01:39 +00:00
return $s;
}
2021-12-03 03:01:39 +00:00
function zidify_text_callback($match)
{
$is_zid = is_matrix_url($match[2]);
$replace = '<a' . $match[1] . ' href="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"' . $match[3] . '>';
2021-12-03 03:01:39 +00:00
$x = str_replace($match[0], $replace, $match[0]);
2021-12-03 03:01:39 +00:00
return $x;
}
2021-12-03 03:01:39 +00:00
function zidify_text_img_callback($match)
{
$is_zid = is_matrix_url($match[2]);
$replace = '<img' . $match[1] . ' src="' . (($is_zid) ? zid($match[2]) : $match[2]) . '"' . $match[3] . '>';
2021-12-03 03:01:39 +00:00
$x = str_replace($match[0], $replace, $match[0]);
2021-12-03 03:01:39 +00:00
return $x;
}
2021-12-03 03:01:39 +00:00
function zidify_text($s)
{
2021-12-03 03:01:39 +00:00
$s = preg_replace_callback('/\<a(.*?)href\=\"(.*?)\"(.*?)\>/ism', 'zidify_text_callback', $s);
$s = preg_replace_callback('/\<img(.*?)src\=\"(.*?)\"(.*?)\>/ism', 'zidify_text_img_callback', $s);
2021-12-03 03:01:39 +00:00
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
*/
2021-12-03 03:01:39 +00:00
function red_zrl_callback($matches)
{
2017-01-30 23:01:22 +00:00
2021-12-03 03:01:39 +00:00
$zrl = is_matrix_url($matches[2]);
2021-12-03 03:01:39 +00:00
$t = strip_zids($matches[2]);
if ($t !== $matches[2]) {
$zrl = true;
$matches[2] = $t;
}
2021-12-03 03:01:39 +00:00
if ($matches[1] === '#^') {
$matches[1] = '';
}
2021-12-03 03:01:39 +00:00
if ($zrl) {
return $matches[1] . '[zrl=' . $matches[2] . ']' . $matches[2] . '[/zrl]';
}
2021-12-03 03:01:39 +00:00
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
*/
2021-12-03 03:01:39 +00:00
function red_escape_zrl_callback($matches)
{
2021-12-03 03:01:39 +00:00
// Uncertain why the url/zrl forms weren't picked up by the non-greedy regex.
2021-12-03 03:01:39 +00:00
if ((strpos($matches[3], 'zmg') !== false) || (strpos($matches[3], 'img') !== false) || (strpos($matches[3], 'zrl') !== false) || (strpos($matches[3], 'url') !== false)) {
return $matches[0];
}
2021-12-03 03:01:39 +00:00
return '[' . $matches[1] . 'rl' . $matches[2] . ']' . $matches[3] . '"' . $matches[4] . '"' . $matches[5] . '[/' . $matches[6] . 'rl]';
}
2021-12-03 03:01:39 +00:00
function red_escape_codeblock($m)
{
return '[$b64' . $m[2] . base64_encode($m[1]) . '[/' . $m[2] . ']';
}
2021-12-03 03:01:39 +00:00
function red_unescape_codeblock($m)
{
return '[' . $m[2] . base64_decode($m[1]) . '[/' . $m[2] . ']';
}
2021-12-03 03:01:39 +00:00
function red_zrlify_img_callback($matches)
{
2017-01-30 23:01:22 +00:00
2021-12-03 03:01:39 +00:00
$zrl = is_matrix_url($matches[2]);
2021-12-03 03:01:39 +00:00
$t = strip_zids($matches[2]);
if ($t !== $matches[2]) {
$zrl = true;
$matches[2] = $t;
}
2021-12-03 03:01:39 +00:00
if ($zrl) {
return '[zmg' . $matches[1] . ']' . $matches[2] . '[/zmg]';
}
2021-12-03 03:01:39 +00:00
return $matches[0];
}
/**
* @brief OpenWebAuth authentication.
*
* @param string $token
*/
2021-12-03 03:01:39 +00:00
function owt_init($token)
{
2017-09-08 00:56:02 +00:00
2021-12-03 03:01:39 +00:00
require_once('include/security.php');
2017-09-08 00:56:02 +00:00
2021-12-03 03:01:39 +00:00
Verify::purge('owt', '3 MINUTE');
2017-09-08 00:56:02 +00:00
2021-12-03 03:01:39 +00:00
$ob_hash = Verify::get_meta('owt', 0, $token);
2017-09-08 01:52:18 +00:00
2021-12-03 03:01:39 +00:00
if ($ob_hash === false) {
return;
}
2017-09-08 00:56:02 +00:00
2021-12-03 03:01:39 +00:00
$r = q(
"select * from hubloc left join xchan on xchan_hash = hubloc_hash
2018-10-10 04:08:57 +00:00
where hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s' order by hubloc_id desc",
2021-12-03 03:01:39 +00:00
dbesc($ob_hash),
dbesc($ob_hash),
dbesc($ob_hash)
);
if (! $r) {
// finger them if they can't be found.
$wf = discover_by_webbie($ob_hash);
if ($wf) {
$r = q(
"select * from hubloc left join xchan on xchan_hash = hubloc_hash
2018-10-10 04:08:57 +00:00
where hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s' order by hubloc_id desc",
2021-12-03 03:01:39 +00:00
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;
}
}
}
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
*/
call_hooks('magic_auth_success', $arr);
App::set_observer($hubloc);
App::set_groups(init_groups_visitor($_SESSION['visitor_id']));
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;
}
2019-03-09 21:13:04 +00:00
2021-12-03 03:01:39 +00:00
function observer_auth($ob_hash)
{
2019-03-09 21:13:04 +00:00
2021-12-03 03:01:39 +00:00
require_once('include/security.php');
2021-12-03 03:01:39 +00:00
if ($ob_hash === false) {
return;
}
2019-03-09 21:13:04 +00:00
2021-12-03 03:01:39 +00:00
$r = q(
"select * from hubloc left join xchan on xchan_hash = hubloc_hash
2019-03-09 21:13:04 +00:00
where hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s' order by hubloc_id desc",
2021-12-03 03:01:39 +00:00
dbesc($ob_hash),
dbesc($ob_hash),
dbesc($ob_hash)
);
if (! $r) {
// finger them if they can't be found.
$wf = discover_by_webbie($ob_hash);
if ($wf) {
$r = q(
"select * from hubloc left join xchan on xchan_hash = hubloc_hash
2019-03-09 21:13:04 +00:00
where hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s' order by hubloc_id desc",
2021-12-03 03:01:39 +00:00
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 Zotlabs\Web\WebServer.php
// @FIXME: to work seamlessly with Friendica and other platforms that choose to
// provide OWA we will need to store the OWA endpoints for each site in SConfig
// and refer to this to determine whether or not to provide "zidified" links.
if (in_array($hubloc['hubloc_network'],['nomad','zot6'])) {
2021-12-03 03:01:39 +00:00
$_SESSION['my_address'] = $hubloc['hubloc_addr'];
}
$_SESSION['remote_hub'] = $hubloc['hubloc_url'];
$_SESSION['DNT'] = 1;
2019-03-09 21:13:04 +00:00
2021-12-03 03:01:39 +00:00
App::set_observer($hubloc);
App::set_groups(init_groups_visitor($_SESSION['visitor_id']));
2019-03-09 21:13:04 +00:00
}