2015-03-21 23:06:08 +00:00
< ? php
2018-08-03 23:03:16 +00:00
2022-02-16 04:08:28 +00:00
use Code\Lib\Libzot ;
use Code\Lib\Zotfinger ;
use Code\Lib\Webfinger ;
2022-08-31 00:30:11 +00:00
use Code\Lib\Channel ;
2022-02-16 04:08:28 +00:00
use Code\Lib\Activity ;
use Code\Lib\ActivityPub ;
use Code\Lib\Queue ;
use Code\Lib\System ;
use Code\Lib\LDSignatures ;
use Code\Lib\Addon ;
2022-06-23 07:38:34 +00:00
use Code\Lib\Url ;
2022-02-16 04:08:28 +00:00
use Code\Web\HTTPSig ;
use Code\Daemon\Run ;
use Code\Extend\Hook ;
2022-06-22 10:19:52 +00:00
use Code\Storage\Stdio ;
2020-09-15 06:11:49 +00:00
2015-03-21 23:06:08 +00:00
/**
* @ file include / network . php
2017-09-04 22:23:42 +00:00
* @ brief Network related functions .
2015-03-21 23:06:08 +00:00
*/
2013-02-14 04:09:30 +00:00
2020-11-17 05:39:49 +00:00
2021-12-03 03:01:39 +00:00
function json_return_and_die ( $x , $content_type = 'application/json' , $debug = false )
{
header ( " Content-type: $content_type " );
if ( $debug ) {
logger ( 'returned_json: ' . json_encode ( $x , JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ), LOGGER_DATA );
}
echo json_encode ( $x );
killme ();
}
2020-11-17 05:39:49 +00:00
2021-12-03 03:01:39 +00:00
function as_return_and_die ( $obj , $channel )
{
2020-11-17 05:39:49 +00:00
2022-12-04 18:15:43 +00:00
if ( is_array ( $obj )) {
2022-12-15 21:30:16 +00:00
$x = array_merge ( Activity :: ap_context (), $obj );
2022-12-04 18:15:43 +00:00
}
2021-12-03 03:01:39 +00:00
$headers = [];
$headers [ 'Content-Type' ] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ;
$x [ 'signature' ] = LDSignatures :: sign ( $x , $channel );
$ret = json_encode ( $x , JSON_UNESCAPED_SLASHES );
logger ( 'data: ' . jindent ( $ret ), LOGGER_DATA );
$headers [ 'Date' ] = datetime_convert ( 'UTC' , 'UTC' , 'now' , 'D, d M Y H:i:s \\G\\M\\T' );
$headers [ 'Digest' ] = HTTPSig :: generate_digest_header ( $ret );
$headers [ '(request-target)' ] = strtolower ( $_SERVER [ 'REQUEST_METHOD' ]) . ' ' . $_SERVER [ 'REQUEST_URI' ];
2022-01-25 01:26:12 +00:00
$h = HTTPSig :: create_sig ( $headers , $channel [ 'channel_prvkey' ], Channel :: url ( $channel ));
2021-12-03 03:01:39 +00:00
HTTPSig :: set_headers ( $h );
echo $ret ;
killme ();
2020-11-17 05:39:49 +00:00
}
2013-03-28 02:02:01 +00:00
/**
2017-04-06 17:45:19 +00:00
* @ brief Send HTTP status header .
2015-03-21 23:06:08 +00:00
*
2013-03-28 02:02:01 +00:00
* @ param int $val
* integer HTTP status result value
2013-04-25 08:55:35 +00:00
* @ param string $msg
* optional message
2013-03-28 02:02:01 +00:00
*/
2021-12-03 03:01:39 +00:00
function http_status ( $val , $msg = '' )
{
if ( $val >= 400 ) {
2022-09-03 21:16:47 +00:00
$msg = (( $msg ) ? : 'Error' );
2021-12-03 03:01:39 +00:00
}
if ( $val >= 200 && $val < 300 ) {
2022-09-03 21:16:47 +00:00
$msg = (( $msg ) ? : 'OK' );
2021-12-03 03:01:39 +00:00
}
logger ( App :: $query_string . ':' . $val . ' ' . $msg );
header ( $_SERVER [ 'SERVER_PROTOCOL' ] . ' ' . $val . ' ' . $msg );
2015-11-21 02:56:41 +00:00
}
/**
* @ brief Send HTTP status header and exit .
*
* @ param int $val
* integer HTTP status result value
* @ param string $msg
* optional message
2017-09-04 22:23:42 +00:00
* @ return void does not return , process is terminated
2015-11-21 02:56:41 +00:00
*/
2021-12-03 03:01:39 +00:00
function http_status_exit ( $val , $msg = '' )
{
http_status ( $val , $msg );
killme ();
2013-02-26 23:49:37 +00:00
}
2011-08-10 01:55:46 +00:00
2020-08-13 06:58:09 +00:00
/*
*
* Takes the output of parse_url and builds a URL from it
*
*/
2021-12-03 03:01:39 +00:00
function unparse_url ( $parsed_url )
{
$scheme = isset ( $parsed_url [ 'scheme' ]) ? $parsed_url [ 'scheme' ] . '://' : '' ;
2022-11-20 06:44:13 +00:00
$host = $parsed_url [ 'host' ] ? ? '' ;
2021-12-03 03:01:39 +00:00
$port = (( isset ( $parsed_url [ 'port' ]) && intval ( $parsed_url [ 'port' ])) ? ':' . intval ( $parsed_url [ 'port' ]) : '' );
2022-11-20 06:44:13 +00:00
$user = $parsed_url [ 'user' ] ? ? '' ;
2021-12-03 03:01:39 +00:00
$pass = isset ( $parsed_url [ 'pass' ]) ? ':' . $parsed_url [ 'pass' ] : '' ;
$pass = ( $user || $pass ) ? " $pass @ " : '' ;
2022-11-20 06:44:13 +00:00
$path = $parsed_url [ 'path' ] ? ? '' ;
2021-12-03 03:01:39 +00:00
$query = isset ( $parsed_url [ 'query' ]) ? '?' . $parsed_url [ 'query' ] : '' ;
$fragment = isset ( $parsed_url [ 'fragment' ]) ? '#' . $parsed_url [ 'fragment' ] : '' ;
return " $scheme $user $pass $host $port $path $query $fragment " ;
}
2020-08-13 06:58:09 +00:00
2017-04-06 17:45:19 +00:00
/**
2017-09-04 22:23:42 +00:00
* @ brief Convert an XML document to a normalised , case - corrected array used by webfinger .
2017-04-06 17:45:19 +00:00
*
* @ param string | array | SimpleXMLElement $xml_element
2017-09-04 22:23:42 +00:00
* @ param [ in , out ] int $recursion_depth
2017-04-06 17:45:19 +00:00
* @ return NULL | string | array
*/
2021-12-03 03:01:39 +00:00
function convert_xml_element_to_array ( $xml_element , & $recursion_depth = 0 )
{
2011-08-01 23:51:01 +00:00
2021-12-03 03:01:39 +00:00
// If we're getting too deep, bail out
if ( $recursion_depth > 512 ) {
2022-09-03 21:16:47 +00:00
return null ;
2021-12-03 03:01:39 +00:00
}
2014-08-25 00:52:26 +00:00
2021-12-03 03:01:39 +00:00
if (
! is_string ( $xml_element ) &&
! is_array ( $xml_element ) &&
( get_class ( $xml_element ) == 'SimpleXMLElement' )
) {
$xml_element_copy = $xml_element ;
$xml_element = get_object_vars ( $xml_element );
}
2014-08-25 00:52:26 +00:00
2021-12-03 03:01:39 +00:00
if ( is_array ( $xml_element )) {
$result_array = [];
if ( count ( $xml_element ) <= 0 ) {
return ( trim ( strval ( $xml_element_copy )));
}
2014-08-25 00:52:26 +00:00
2021-12-03 03:01:39 +00:00
foreach ( $xml_element as $key => $value ) {
$recursion_depth ++ ;
$result_array [ strtolower ( $key )] =
convert_xml_element_to_array ( $value , $recursion_depth );
$recursion_depth -- ;
}
if ( $recursion_depth == 0 ) {
$temp_array = $result_array ;
2022-09-03 21:16:47 +00:00
$result_array = [
2021-12-03 03:01:39 +00:00
strtolower ( $xml_element_copy -> getName ()) => $temp_array ,
2022-09-03 21:16:47 +00:00
];
2021-12-03 03:01:39 +00:00
}
2017-04-06 17:45:19 +00:00
2021-12-03 03:01:39 +00:00
return ( $result_array );
} else {
return ( trim ( strval ( $xml_element )));
}
2013-02-26 23:49:37 +00:00
}
2011-08-01 23:51:01 +00:00
2016-10-26 01:27:32 +00:00
2021-12-03 03:01:39 +00:00
function z_dns_check ( $h , $check_mx = 0 )
{
2016-10-26 01:27:32 +00:00
2021-12-03 03:01:39 +00:00
// dns_get_record() has issues on some platforms
// so allow somebody to ignore it completely
// Use config values from memory as this can be called during setup
// before a database or even any config structure exists.
2016-10-26 01:27:32 +00:00
2021-12-03 03:01:39 +00:00
if ( is_array ( App :: $config ) && array_path_exists ( 'system/do_not_check_dns' , App :: $config ) && App :: $config [ 'system' ][ 'do_not_check_dns' ]) {
return true ;
}
2016-10-26 01:27:32 +00:00
2021-12-03 03:01:39 +00:00
// This will match either Windows or Mac ('Darwin')
if ( stripos ( PHP_OS , 'win' ) !== false ) {
return true ;
}
2018-05-24 23:32:21 +00:00
2021-12-03 03:01:39 +00:00
// BSD variants have dns_get_record() but it only works reliably without any options
if ( stripos ( PHP_OS , 'bsd' ) !== false ) {
2022-08-14 09:20:43 +00:00
return @ dns_get_record ( $h ) || filter_var ( $h , FILTER_VALIDATE_IP );
2021-12-03 03:01:39 +00:00
}
2018-05-24 23:32:21 +00:00
2021-12-03 03:01:39 +00:00
// Otherwise we will assume dns_get_record() works as documented
2018-05-24 23:32:21 +00:00
2021-12-03 03:01:39 +00:00
$opts = DNS_A + DNS_CNAME + DNS_AAAA ;
if ( $check_mx ) {
$opts += DNS_MX ;
}
2016-11-03 06:37:57 +00:00
2022-08-14 09:20:43 +00:00
return @ dns_get_record ( $h , $opts ) || filter_var ( $h , FILTER_VALIDATE_IP );
2016-10-26 01:27:32 +00:00
}
2017-04-06 17:45:19 +00:00
/**
2017-09-04 22:23:42 +00:00
* @ brief Validates a given URL .
2017-04-06 17:45:19 +00:00
*
* Take a URL from the wild , prepend http :// if necessary and check DNS to see
* if it ' s real ( or check if is a valid IP address ) .
*
* @ see z_dns_check ()
*
2017-09-04 22:23:42 +00:00
* @ param [ in , out ] string $url URL to check
2021-12-02 23:02:31 +00:00
* @ return bool Return true if it ' s OK , false if something is wrong with it
2017-04-06 17:45:19 +00:00
*/
2021-12-03 03:01:39 +00:00
function validate_url ( & $url )
{
2016-10-01 22:41:25 +00:00
2021-12-03 03:01:39 +00:00
// no naked subdomains (allow localhost for tests)
2022-09-03 21:16:47 +00:00
if ( ! str_contains ( $url , '.' ) && ! str_contains ( $url , '/localhost/' )) {
2021-12-03 03:01:39 +00:00
return false ;
}
2017-04-06 17:45:19 +00:00
2022-09-03 21:16:47 +00:00
if ( ! str_starts_with ( $url , 'http' )) {
2021-12-03 03:01:39 +00:00
$url = 'http://' . $url ;
}
2017-04-06 17:45:19 +00:00
2021-12-03 03:01:39 +00:00
$h = @ parse_url ( $url );
2016-10-01 22:41:25 +00:00
2021-12-03 03:01:39 +00:00
if (( $h ) && z_dns_check ( $h [ 'host' ])) {
return true ;
}
2017-04-06 17:45:19 +00:00
2021-12-03 03:01:39 +00:00
return false ;
2013-02-26 23:49:37 +00:00
}
2011-08-01 23:51:01 +00:00
2017-04-06 17:45:19 +00:00
/**
* @ brief Checks that email is an actual resolvable internet address .
*
* @ param string $addr
2021-12-02 23:02:31 +00:00
* @ return bool
2017-04-06 17:45:19 +00:00
*/
2021-12-03 03:01:39 +00:00
function validate_email ( $addr )
{
2011-08-01 23:51:01 +00:00
2021-12-03 03:01:39 +00:00
if ( get_config ( 'system' , 'disable_email_validation' )) {
return true ;
}
2012-07-02 01:56:00 +00:00
2021-12-03 03:01:39 +00:00
if ( ! strpos ( $addr , '@' )) {
return false ;
}
2011-08-01 23:51:01 +00:00
2021-12-03 03:01:39 +00:00
$h = substr ( $addr , strpos ( $addr , '@' ) + 1 );
2017-04-06 17:45:19 +00:00
2021-12-03 03:01:39 +00:00
if (( $h ) && z_dns_check ( $h , true )) {
return true ;
}
2017-04-06 17:45:19 +00:00
2021-12-03 03:01:39 +00:00
return false ;
2013-02-26 23:49:37 +00:00
}
2011-08-01 23:51:01 +00:00
2017-04-06 17:45:19 +00:00
/**
* @ brief Check if email address is allowed to register here .
*
* Compare against our list ( wildcards allowed ) .
*
* @ param string $email
2021-12-02 23:02:31 +00:00
* @ return bool Returns false if not allowed , true if allowed or if allowed list is
2017-04-06 17:45:19 +00:00
* not configured .
*/
2021-12-03 03:01:39 +00:00
function allowed_email ( $email )
{
2011-08-01 23:51:01 +00:00
2021-12-03 03:01:39 +00:00
$domain = strtolower ( substr ( $email , strpos ( $email , '@' ) + 1 ));
if ( ! $domain ) {
return false ;
}
2011-08-01 23:51:01 +00:00
2021-12-03 03:01:39 +00:00
$str_allowed = get_config ( 'system' , 'allowed_email' );
$str_not_allowed = get_config ( 'system' , 'not_allowed_email' );
2016-10-01 22:41:25 +00:00
2021-12-03 03:01:39 +00:00
if ( ! $str_allowed && ! $str_not_allowed ) {
return true ;
}
2011-08-01 23:51:01 +00:00
2021-12-03 03:01:39 +00:00
$return = false ;
$found_allowed = false ;
$found_not_allowed = false ;
2016-10-01 22:41:25 +00:00
2021-12-03 03:01:39 +00:00
$fnmatch = function_exists ( 'fnmatch' );
2015-01-25 03:16:28 +00:00
2021-12-03 03:01:39 +00:00
$allowed = explode ( ',' , $str_allowed );
2011-08-01 23:51:01 +00:00
2021-12-03 03:01:39 +00:00
if ( count ( $allowed )) {
foreach ( $allowed as $a ) {
$pat = strtolower ( trim ( $a ));
if (( $fnmatch && fnmatch ( $pat , $email )) || ( $pat == $domain )) {
$found_allowed = true ;
break ;
}
}
}
2015-01-25 03:16:28 +00:00
2021-12-03 03:01:39 +00:00
$not_allowed = explode ( ',' , $str_not_allowed );
2015-01-25 03:16:28 +00:00
2021-12-03 03:01:39 +00:00
if ( count ( $not_allowed )) {
foreach ( $not_allowed as $na ) {
$pat = strtolower ( trim ( $na ));
if (( $fnmatch && fnmatch ( $pat , $email )) || ( $pat == $domain )) {
$found_not_allowed = true ;
break ;
}
}
}
2016-10-01 22:41:25 +00:00
2021-12-03 03:01:39 +00:00
if ( $found_allowed ) {
$return = true ;
} elseif ( ! $str_allowed && ! $found_not_allowed ) {
$return = true ;
}
2017-04-06 17:45:19 +00:00
2021-12-03 03:01:39 +00:00
return $return ;
2013-02-26 23:49:37 +00:00
}
2011-08-01 23:51:01 +00:00
2021-12-03 03:01:39 +00:00
function parse_xml_string ( $s , $strict = true )
{
if ( $strict ) {
2022-09-03 22:06:54 +00:00
if ( ! str_contains ( $s , '<?xml' )) {
2021-12-03 03:01:39 +00:00
return false ;
}
2017-04-06 17:45:19 +00:00
2021-12-03 03:01:39 +00:00
$s2 = substr ( $s , strpos ( $s , '<?xml' ));
} else {
$s2 = $s ;
}
2017-04-06 17:45:19 +00:00
2021-12-03 03:01:39 +00:00
libxml_use_internal_errors ( true );
2011-08-01 23:51:01 +00:00
2018-04-30 06:05:38 +00:00
2021-12-03 03:01:39 +00:00
$x = @ simplexml_load_string ( $s2 );
if ( $x === false ) {
logger ( 'libxml: parse: error: ' . $s2 , LOGGER_DATA );
foreach ( libxml_get_errors () as $err ) {
logger ( 'libxml: parse: ' . $err -> code . ' at ' . $err -> line
. ':' . $err -> column . ' : ' . $err -> message , LOGGER_DATA );
}
libxml_clear_errors ();
}
2017-04-06 17:45:19 +00:00
2021-12-03 03:01:39 +00:00
return $x ;
2013-02-26 23:49:37 +00:00
}
2011-08-18 11:20:30 +00:00
2018-04-30 06:05:38 +00:00
2022-09-03 22:06:54 +00:00
function sxml2array ( $xmlObject , $out = [])
2018-04-30 06:05:38 +00:00
{
2021-12-03 03:01:39 +00:00
foreach (( array ) $xmlObject as $index => $node ) {
$out [ $index ] = ( is_object ( $node ) ) ? sxml2array ( $node ) : $node ;
}
2018-04-30 06:05:38 +00:00
return $out ;
}
2012-05-17 04:29:57 +00:00
/**
2021-03-15 05:10:44 +00:00
* @ brief xml2 [] will convert the given XML text to an array in the XML structure .
2017-04-06 17:45:19 +00:00
*
2012-05-17 04:29:57 +00:00
* Link : http :// www . bin - co . com / php / scripts / xml2array /
2021-12-03 03:01:39 +00:00
* Portions significantly re - written by mike @ macgirvin . com
2017-04-06 17:45:19 +00:00
* ( namespaces , lowercase tags , get_attribute default changed , more ... )
*
2012-05-17 04:29:57 +00:00
* Examples : $array = xml2array ( file_get_contents ( 'feed.xml' ));
2017-04-06 17:45:19 +00:00
* $array = xml2array ( file_get_contents ( 'feed.xml' , true , 1 , 'attribute' ));
*
* @ param string $contents The XML text
2021-12-02 23:02:31 +00:00
* @ param bool $namespaces true or false include namespace information in the returned array as array elements
2017-04-06 17:45:19 +00:00
* @ param int $get_attributes 1 or 0. If this is 1 the function will get the attributes as well as the tag values - this results in a different array structure in the return value .
2022-09-03 22:06:54 +00:00
* @ param string $priority Can be 'tag' or 'attribute' . This will change the way the resulting array structure . For 'tag' , the tags are given more importance .
2017-04-06 17:45:19 +00:00
*
* @ return array The parsed XML in an array form . Use print_r () to see the resulting array structure .
2016-10-01 22:41:25 +00:00
*/
2021-12-03 03:01:39 +00:00
function xml2array ( $contents , $namespaces = true , $get_attributes = 1 , $priority = 'attribute' )
{
if ( ! $contents ) {
return [];
}
2016-10-01 22:41:25 +00:00
2021-12-03 03:01:39 +00:00
if ( ! function_exists ( 'xml_parser_create' )) {
logger ( 'xml2array: parser function missing' );
return [];
}
2014-08-25 00:52:26 +00:00
2021-12-03 03:01:39 +00:00
libxml_use_internal_errors ( true );
libxml_clear_errors ();
2014-08-25 00:52:26 +00:00
2021-12-03 03:01:39 +00:00
if ( $namespaces ) {
$parser = @ xml_parser_create_ns ( " UTF-8 " , ':' );
} else {
$parser = @ xml_parser_create ();
}
2012-05-17 04:29:57 +00:00
2021-12-03 03:01:39 +00:00
if ( ! $parser ) {
logger ( 'xml2array: xml_parser_create: no resource' );
return [];
}
2014-08-25 00:52:26 +00:00
2021-12-03 03:01:39 +00:00
xml_parser_set_option ( $parser , XML_OPTION_TARGET_ENCODING , " UTF-8 " );
// http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
xml_parser_set_option ( $parser , XML_OPTION_CASE_FOLDING , 0 );
xml_parser_set_option ( $parser , XML_OPTION_SKIP_WHITE , 1 );
@ xml_parse_into_struct ( $parser , trim ( $contents ), $xml_values );
@ xml_parser_free ( $parser );
if ( ! $xml_values ) {
logger ( 'xml2array: libxml: parse error: ' . $contents , LOGGER_DATA );
foreach ( libxml_get_errors () as $err ) {
logger ( 'libxml: parse: ' . $err -> code . " at " . $err -> line . " : " . $err -> column . " : " . $err -> message , LOGGER_DATA );
}
libxml_clear_errors ();
2014-08-25 00:52:26 +00:00
2022-09-02 23:45:58 +00:00
return [];
2021-12-03 03:01:39 +00:00
}
2014-08-25 00:52:26 +00:00
2022-11-20 06:44:13 +00:00
// Initializations
2021-12-03 03:01:39 +00:00
$xml_array = [];
2016-10-01 22:41:25 +00:00
2021-12-03 03:01:39 +00:00
$current = & $xml_array ; // Reference
2014-08-25 00:52:26 +00:00
2021-12-03 03:01:39 +00:00
// Go through the tags.
$repeated_tag_index = []; // Multiple tags with same name will be turned into an array
foreach ( $xml_values as $data ) {
unset ( $attributes , $value ); // Remove existing values, or there will be trouble
2014-08-25 00:52:26 +00:00
2021-12-03 03:01:39 +00:00
// This command will extract these variables into the foreach scope
// tag(string), type(string), level(int), attributes(array).
extract ( $data ); // We could use the array by itself, but this cooler.
2014-08-25 00:52:26 +00:00
2021-12-03 03:01:39 +00:00
$result = [];
$attributes_data = [];
2016-10-01 22:41:25 +00:00
2021-12-03 03:01:39 +00:00
if ( isset ( $value )) {
if ( $priority == 'tag' ) {
$result = $value ;
} else {
2022-08-14 09:20:43 +00:00
$result [ 'value' ] = $value ; // Put the value in an assoc array if we are in the 'Attribute' mode
2021-12-03 03:01:39 +00:00
}
}
2016-10-01 22:41:25 +00:00
2021-12-03 03:01:39 +00:00
//Set the attributes too.
if ( isset ( $attributes ) and $get_attributes ) {
foreach ( $attributes as $attr => $val ) {
if ( $priority == 'tag' ) {
$attributes_data [ $attr ] = $val ;
} else {
2022-08-14 09:20:43 +00:00
$result [ '@attributes' ][ $attr ] = $val ; // Set all the attributes in an array called 'attr'
2021-12-03 03:01:39 +00:00
}
}
}
2014-08-25 00:52:26 +00:00
2021-12-03 03:01:39 +00:00
// See tag status and do the needed.
if ( $namespaces && strpos ( $tag , ':' )) {
$namespc = substr ( $tag , 0 , strrpos ( $tag , ':' ));
$tag = strtolower ( substr ( $tag , strlen ( $namespc ) + 1 ));
$result [ '@namespace' ] = $namespc ;
}
$tag = strtolower ( $tag );
if ( $type == " open " ) { // The starting of the tag '<tag>'
$parent [ $level - 1 ] = & $current ;
if ( ! is_array ( $current ) or ( ! in_array ( $tag , array_keys ( $current )))) { // Insert New tag
$current [ $tag ] = $result ;
if ( $attributes_data ) {
$current [ $tag . '_attr' ] = $attributes_data ;
}
$repeated_tag_index [ $tag . '_' . $level ] = 1 ;
$current = & $current [ $tag ];
} else { // There was another element with the same tag name
if ( isset ( $current [ $tag ][ 0 ])) { // If there is a 0th element it is already an array
$current [ $tag ][ $repeated_tag_index [ $tag . '_' . $level ]] = $result ;
$repeated_tag_index [ $tag . '_' . $level ] ++ ;
} else { // This section will make the value an array if multiple tags with the same name appear together
2022-11-20 05:28:50 +00:00
$current [ $tag ] = [ $current [ $tag ], $result ]; // This will combine the existing item and the new item together to make an array
2021-12-03 03:01:39 +00:00
$repeated_tag_index [ $tag . '_' . $level ] = 2 ;
if ( isset ( $current [ $tag . '_attr' ])) { // The attribute of the last(0th) tag must be moved as well
$current [ $tag ][ '0_attr' ] = $current [ $tag . '_attr' ];
unset ( $current [ $tag . '_attr' ]);
}
}
$last_item_index = $repeated_tag_index [ $tag . '_' . $level ] - 1 ;
$current = & $current [ $tag ][ $last_item_index ];
}
} elseif ( $type == " complete " ) { // Tags that ends in 1 line '<tag />'
//See if the key is already taken.
if ( ! isset ( $current [ $tag ])) { //New Key
$current [ $tag ] = $result ;
$repeated_tag_index [ $tag . '_' . $level ] = 1 ;
if ( $priority == 'tag' and $attributes_data ) {
$current [ $tag . '_attr' ] = $attributes_data ;
}
} else { // If taken, put all things inside a list(array)
if ( isset ( $current [ $tag ][ 0 ]) and is_array ( $current [ $tag ])) { // If it is already an array...
// ...push the new element into that array.
$current [ $tag ][ $repeated_tag_index [ $tag . '_' . $level ]] = $result ;
if ( $priority == 'tag' and $get_attributes and $attributes_data ) {
$current [ $tag ][ $repeated_tag_index [ $tag . '_' . $level ] . '_attr' ] = $attributes_data ;
}
$repeated_tag_index [ $tag . '_' . $level ] ++ ;
} else { // If it is not an array...
2022-11-20 05:28:50 +00:00
$current [ $tag ] = [ $current [ $tag ], $result ]; //...Make it an array using the existing value and the new value
2021-12-03 03:01:39 +00:00
$repeated_tag_index [ $tag . '_' . $level ] = 1 ;
if ( $priority == 'tag' and $get_attributes ) {
if ( isset ( $current [ $tag . '_attr' ])) { // The attribute of the last(0th) tag must be moved as well
$current [ $tag ][ '0_attr' ] = $current [ $tag . '_attr' ];
unset ( $current [ $tag . '_attr' ]);
}
if ( $attributes_data ) {
$current [ $tag ][ $repeated_tag_index [ $tag . '_' . $level ] . '_attr' ] = $attributes_data ;
}
}
$repeated_tag_index [ $tag . '_' . $level ] ++ ; // 0 and 1 indexes are already taken
}
}
} elseif ( $type == 'close' ) { // End of tag '</tag>'
$current = & $parent [ $level - 1 ];
}
}
2016-10-01 22:41:25 +00:00
2021-12-03 03:01:39 +00:00
return ( $xml_array );
2016-10-01 22:41:25 +00:00
}
2012-08-09 23:26:44 +00:00
2012-10-23 02:46:18 +00:00
2021-12-03 03:01:39 +00:00
function email_header_encode ( $in_str , $charset = 'UTF-8' , $header = 'Subject' )
{
$out_str = $in_str ;
$need_to_convert = false ;
2012-10-23 02:46:18 +00:00
2021-12-03 03:01:39 +00:00
for ( $x = 0 ; $x < strlen ( $in_str ); $x ++ ) {
if (( ord ( $in_str [ $x ]) == 0 ) || (( ord ( $in_str [ $x ]) > 128 ))) {
$need_to_convert = true ;
break ;
}
}
2012-10-23 02:46:18 +00:00
2021-12-03 03:01:39 +00:00
if ( ! $need_to_convert ) {
return $in_str ;
}
if ( $out_str && $charset ) {
2022-09-03 22:06:54 +00:00
// define start delimiter, end delimiter and spacer
2021-12-03 03:01:39 +00:00
$end = " ?= " ;
$start = " =? " . $charset . " ?B? " ;
$spacer = $end . PHP_EOL . " " . $start ;
// determine length of encoded text within chunks
// and ensure length is even
$length = 75 - strlen ( $start ) - strlen ( $end ) - ( strlen ( $header ) + 2 );
/*
[ EDIT BY danbrown AT php DOT net : The following
is a bugfix provided by ( gardan AT gmx DOT de )
on 31 - MAR - 2005 with the following note :
" This means: $length should not be even,
but divisible by 4. The reason is that in
base64 - encoding 3 8 - bit - chars are represented
by 4 6 - bit - chars . These 4 chars must not be
split between two encoded words , according
2022-09-03 21:16:47 +00:00
to RFC - 2047. " ]
2021-12-03 03:01:39 +00:00
*/
$length = $length - ( $length % 4 );
// encode the string and split it into chunks
// with spacers after each chunk
$out_str = base64_encode ( $out_str );
$out_str = chunk_split ( $out_str , $length , $spacer );
// remove trailing spacer and
// add start and end delimiters
$spacer = preg_quote ( $spacer , '/' );
$out_str = preg_replace ( " / " . $spacer . " $ / " , " " , $out_str );
$out_str = $start . $out_str . $end ;
}
return $out_str ;
2012-10-23 02:46:18 +00:00
}
2017-09-04 22:23:42 +00:00
/**
* @ brief
*
2022-09-03 21:30:13 +00:00
* @ param string $resource
2017-09-04 22:23:42 +00:00
* @ param string $protocol ( optional ) default empty
2021-12-02 23:02:31 +00:00
* @ param bool $verify ( optional ) default true , verify HTTP signatures on Zot discovery packets .
2022-09-03 21:30:13 +00:00
* @ return bool | string
2017-09-04 22:23:42 +00:00
*/
2022-09-03 21:30:13 +00:00
function discover_resource ( string $resource , $protocol = '' , $verify = true )
2021-12-03 03:01:39 +00:00
{
2022-09-03 21:30:13 +00:00
$x = Webfinger :: exec ( $resource );
2018-08-23 06:04:37 +00:00
2021-12-03 03:01:39 +00:00
$address = EMPTY_STR ;
2018-08-23 06:04:37 +00:00
2022-09-03 21:16:47 +00:00
if ( $x && array_key_exists ( 'subject' , $x ) && str_starts_with ( $x [ 'subject' ], 'acct:' )) {
2021-12-03 03:01:39 +00:00
$address = str_replace ( 'acct:' , '' , $x [ 'subject' ]);
}
if ( $x && array_key_exists ( 'aliases' , $x ) && count ( $x [ 'aliases' ])) {
foreach ( $x [ 'aliases' ] as $a ) {
2022-09-03 21:16:47 +00:00
if ( str_starts_with ( $a , 'acct:' )) {
2021-12-03 03:01:39 +00:00
$address = str_replace ( 'acct:' , '' , $a );
2018-08-23 06:04:37 +00:00
break ;
}
}
}
2021-12-03 03:01:39 +00:00
if ( $x && array_key_exists ( 'links' , $x ) && is_array ( $x [ 'links' ])) {
2021-10-28 20:44:32 +00:00
2022-09-04 01:58:22 +00:00
// look for Nomad first
2021-10-28 20:44:32 +00:00
2022-09-04 01:58:22 +00:00
foreach ( $x [ 'links' ] as $link ) {
if ( array_key_exists ( 'rel' , $link )) {
$apurl = null ;
2021-10-28 20:44:32 +00:00
2022-09-04 01:58:22 +00:00
// If we discover zot - don't search further; grab the info and get out of
// here.
2021-10-28 20:44:32 +00:00
2022-09-04 01:58:22 +00:00
if ( $link [ 'rel' ] == PROTOCOL_NOMAD && (( ! $protocol ) || ( strtolower ( $protocol ) == 'nomad' ))) {
logger ( 'nomad found for ' . $resource , LOGGER_DEBUG );
$record = Zotfinger :: exec ( $link [ 'href' ], null , $verify );
2021-10-28 20:44:32 +00:00
2022-09-04 01:58:22 +00:00
// Check the HTTP signature
2021-10-28 20:44:32 +00:00
2022-09-04 01:58:22 +00:00
if ( $verify ) {
2022-09-03 21:30:13 +00:00
$hsig_valid = false ;
2022-09-04 01:58:22 +00:00
$hsig = $record [ 'signature' ];
if ( $hsig && $hsig [ 'signer' ] === $link [ 'href' ] && $hsig [ 'header_valid' ] === true && $hsig [ 'content_valid' ] === true ) {
$hsig_valid = true ;
}
if ( ! $hsig_valid ) {
logger ( 'http signature not valid: ' . print_r ( $hsig , true ));
continue ;
}
}
$x = Libzot :: import_xchan ( $record [ 'data' ]);
if ( $x [ 'success' ]) {
return $x [ 'hash' ];
}
}
}
}
// if we reached this point, nomad wasn't found.
2021-10-28 20:44:32 +00:00
2021-12-03 03:01:39 +00:00
foreach ( $x [ 'links' ] as $link ) {
if ( array_key_exists ( 'rel' , $link )) {
$apurl = null ;
// If we discover zot - don't search further; grab the info and get out of
// here.
if ( $link [ 'rel' ] === PROTOCOL_ZOT6 && (( ! $protocol ) || ( strtolower ( $protocol ) === 'zot6' ))) {
2022-09-03 21:30:13 +00:00
logger ( 'zot6 found for ' . $resource , LOGGER_DEBUG );
2021-12-03 03:01:39 +00:00
$record = Zotfinger :: exec ( $link [ 'href' ], null , $verify );
// Check the HTTP signature
if ( $verify ) {
2022-09-03 22:06:54 +00:00
$hsig_valid = false ;
2021-12-03 03:01:39 +00:00
$hsig = $record [ 'signature' ];
2022-08-14 09:20:43 +00:00
if ( $hsig && $hsig [ 'signer' ] === $link [ 'href' ] && $hsig [ 'header_valid' ] === true && $hsig [ 'content_valid' ] === true ) {
2021-12-03 03:01:39 +00:00
$hsig_valid = true ;
}
if ( ! $hsig_valid ) {
logger ( 'http signature not valid: ' . print_r ( $hsig , true ));
continue ;
}
}
$x = Libzot :: import_xchan ( $record [ 'data' ]);
if ( $x [ 'success' ]) {
return $x [ 'hash' ];
}
}
2022-09-03 21:16:47 +00:00
if ( $link [ 'rel' ] === 'self' && ( $link [ 'type' ] === 'application/activity+json' || str_contains ( $link [ 'type' ], 'ld+json' )) && (( ! $protocol ) || ( strtolower ( $protocol ) === 'activitypub' ))) {
2021-12-03 03:01:39 +00:00
$ap = ActivityPub :: discover ( $link [ 'href' ]);
if ( $ap ) {
return $ap ;
}
}
}
}
}
2018-08-03 23:03:16 +00:00
2022-09-04 01:58:22 +00:00
if ( str_starts_with ( $resource , 'http' ) && ! $x ) {
2022-09-03 21:30:13 +00:00
$record = Zotfinger :: exec ( $resource , null , $verify );
2022-01-04 10:31:41 +00:00
// Check the HTTP signature
2022-09-04 01:58:22 +00:00
if ( $record ) {
2022-01-04 10:31:41 +00:00
if ( $verify ) {
2022-09-03 22:06:54 +00:00
$hsig_valid = false ;
2022-01-04 10:31:41 +00:00
$hsig = $record [ 'signature' ];
2022-09-03 21:30:13 +00:00
if ( $hsig && $hsig [ 'signer' ] === $resource && $hsig [ 'header_valid' ] === true && $hsig [ 'content_valid' ] === true ) {
2022-01-04 10:31:41 +00:00
$hsig_valid = true ;
}
if ( ! $hsig_valid ) {
logger ( 'http signature not valid: ' . print_r ( $hsig , true ));
return false ;
}
}
$x = Libzot :: import_xchan ( $record [ 'data' ]);
if ( $x [ 'success' ]) {
return $x [ 'hash' ];
}
2022-09-04 01:58:22 +00:00
}
}
2022-01-04 10:31:41 +00:00
2022-09-03 21:30:13 +00:00
if ( str_starts_with ( $resource , 'http' )) {
$ap = ActivityPub :: discover ( $resource );
2021-12-03 03:01:39 +00:00
if ( $ap ) {
return $ap ;
}
}
2014-08-20 02:38:42 +00:00
2021-12-03 03:01:39 +00:00
logger ( 'webfinger: ' . print_r ( $x , true ), LOGGER_DATA , LOG_INFO );
$arr = [
2022-09-03 21:30:13 +00:00
'address' => $resource ,
2021-12-03 03:01:39 +00:00
'protocol' => $protocol ,
'success' => false ,
'xchan' => '' ,
'webfinger' => $x
];
/**
* @ hooks discover_channel_webfinger
* Called when performing a webfinger lookup .
2022-09-03 22:06:54 +00:00
* * \e string \b address - The resource
2021-12-03 03:01:39 +00:00
* * \e string \b protocol
* * \e array \b webfinger - The result from webfinger_rfc7033 ()
* * \e boolean \b success - The return value , default false
*/
2022-02-12 08:50:48 +00:00
Hook :: call ( 'discover_channel_webfinger' , $arr );
2021-12-03 03:01:39 +00:00
if ( $arr [ 'success' ]) {
return $arr [ 'xchan' ];
}
2018-09-17 04:42:41 +00:00
2021-12-03 03:01:39 +00:00
return false ;
2017-03-09 19:51:21 +00:00
}
2016-03-23 02:58:59 +00:00
2016-10-01 22:41:25 +00:00
2021-12-03 03:01:39 +00:00
function do_delivery ( $deliveries , $force = false )
{
2015-06-29 23:56:18 +00:00
2021-12-03 03:01:39 +00:00
// $force is set if a site that wasn't responding suddenly returns to life.
// Try and shove through everything going to that site while it's responding.
2015-06-29 23:56:18 +00:00
2021-12-03 03:01:39 +00:00
if ( ! ( is_array ( $deliveries ) && count ( $deliveries ))) {
return ;
}
2017-11-02 10:13:30 +00:00
2021-12-03 03:01:39 +00:00
$x = q ( " select count(outq_hash) as total from outq where outq_delivered = 0 " );
if ( intval ( $x [ 0 ][ 'total' ]) > intval ( get_config ( 'system' , 'force_queue_threshold' , 3000 )) && ( ! $force )) {
logger ( 'immediate delivery deferred.' , LOGGER_DEBUG , LOG_INFO );
foreach ( $deliveries as $d ) {
2022-08-31 00:30:11 +00:00
Queue :: update ( $d , 'Delivery deferred' );
2021-12-03 03:01:39 +00:00
}
return ;
}
2017-11-02 10:13:30 +00:00
2023-02-06 21:40:25 +00:00
$interval = intval ( get_config ( 'system' , 'delivery_interval' , 2 ));
2021-12-03 03:01:39 +00:00
$deliveries_per_process = intval ( get_config ( 'system' , 'delivery_batch_count' ));
2015-06-29 23:56:18 +00:00
2021-12-03 03:01:39 +00:00
if ( $deliveries_per_process <= 0 ) {
$deliveries_per_process = 1 ;
}
2015-06-29 23:56:18 +00:00
2021-12-03 03:01:39 +00:00
$deliver = [];
foreach ( $deliveries as $d ) {
if ( ! $d ) {
continue ;
}
2016-05-20 03:48:40 +00:00
2021-12-03 03:01:39 +00:00
$deliver [] = $d ;
2015-10-16 01:52:04 +00:00
2021-12-03 03:01:39 +00:00
if ( count ( $deliver ) >= $deliveries_per_process ) {
Run :: Summon ([ 'Deliver' , $deliver ]);
$deliver = [];
if ( $interval ) {
@ time_sleep_until ( microtime ( true ) + ( float ) $interval );
}
}
}
2015-10-16 01:52:04 +00:00
2021-12-03 03:01:39 +00:00
// catch any stragglers
2015-10-16 01:52:04 +00:00
2021-12-03 03:01:39 +00:00
if ( $deliver ) {
2023-02-06 20:50:39 +00:00
Run :: Summon ([ 'Deliver' , $deliver ]);
2021-12-03 03:01:39 +00:00
}
2015-02-09 02:31:51 +00:00
}
2015-11-30 03:37:03 +00:00
2021-12-03 03:01:39 +00:00
function get_site_info ()
{
2022-09-03 22:06:54 +00:00
$register_policy = [ 'REGISTER_CLOSED' , 'REGISTER_APPROVE' , 'REGISTER_OPEN' ];
2015-11-30 03:37:03 +00:00
2021-12-03 03:01:39 +00:00
$r = q ( " select * from channel left join account on account_id = channel_account_id where ( account_roles & 4096 ) > 0 and account_default_channel = channel_id " );
2015-11-30 03:37:03 +00:00
2021-12-03 03:01:39 +00:00
if ( $r ) {
$admin = [];
foreach ( $r as $rr ) {
if ( $rr [ 'channel_pageflags' ] & PAGE_HUBADMIN ) {
2022-09-03 22:06:54 +00:00
$admin [] = [ 'name' => $rr [ 'channel_name' ], 'address' => Channel :: get_webfinger ( $rr ), 'channel' => z_root () . '/channel/' . $rr [ 'channel_address' ]];
2021-12-03 03:01:39 +00:00
}
}
if ( ! $admin ) {
foreach ( $r as $rr ) {
2022-09-03 22:06:54 +00:00
$admin [] = [ 'name' => $rr [ 'channel_name' ], 'address' => Channel :: get_webfinger ( $rr ), 'channel' => z_root () . '/channel/' . $rr [ 'channel_address' ]];
2021-12-03 03:01:39 +00:00
}
}
} else {
$admin = false ;
}
2015-11-30 03:37:03 +00:00
2021-12-03 03:01:39 +00:00
$def_service_class = get_config ( 'system' , 'default_service_class' );
if ( $def_service_class ) {
$service_class = get_config ( 'service_class' , $def_service_class );
} else {
$service_class = false ;
}
2015-11-30 03:37:03 +00:00
2022-02-16 02:35:25 +00:00
$visible_plugins = Addon :: list_visible ();
2015-12-04 01:09:05 +00:00
2021-12-03 03:01:39 +00:00
if ( @ is_dir ( '.git' ) && function_exists ( 'shell_exec' )) {
$commit = trim ( @ shell_exec ( 'git log -1 --format="%h"' ));
}
if ( ! isset ( $commit ) || strlen ( $commit ) > 16 ) {
$commit = '' ;
}
2016-01-18 00:29:32 +00:00
2021-12-03 03:01:39 +00:00
$site_info = get_config ( 'system' , 'info' );
$site_name = get_config ( 'system' , 'sitename' );
if ( ! get_config ( 'system' , 'hidden_version_siteinfo' )) {
$version = System :: get_project_version ();
2016-10-01 22:41:25 +00:00
2021-12-03 03:01:39 +00:00
if ( @ is_dir ( '.git' ) && function_exists ( 'shell_exec' )) {
$commit = trim ( @ shell_exec ( 'git log -1 --format="%h"' ));
}
2018-08-02 08:56:34 +00:00
2021-12-03 03:01:39 +00:00
if ( ! isset ( $commit ) || strlen ( $commit ) > 16 ) {
$commit = '' ;
}
} else {
$version = $commit = '' ;
}
2015-11-30 03:37:03 +00:00
2021-12-03 03:01:39 +00:00
$site_expire = intval ( get_config ( 'system' , 'default_expire_days' ));
load_config ( 'feature_lock' );
$locked_features = [];
if ( is_array ( App :: $config [ 'feature_lock' ]) && count ( App :: $config [ 'feature_lock' ])) {
foreach ( App :: $config [ 'feature_lock' ] as $k => $v ) {
if ( $k === 'config_loaded' ) {
continue ;
}
$locked_features [ $k ] = intval ( $v );
}
}
2016-01-10 07:39:53 +00:00
2022-06-07 03:41:40 +00:00
$protocols = [ 'nomad' , 'zot6' ];
2021-12-03 03:01:39 +00:00
if ( get_config ( 'system' , 'activitypub' , ACTIVITYPUB_ENABLED )) {
$protocols [] = 'activitypub' ;
}
2016-01-10 07:39:53 +00:00
2022-09-03 22:06:54 +00:00
return [
2021-12-03 03:01:39 +00:00
'url' => z_root (),
2022-01-29 22:27:35 +00:00
'platform' => System :: get_project_name (),
2021-12-03 03:01:39 +00:00
'site_name' => (( $site_name ) ? $site_name : '' ),
'version' => $version ,
'addon_version' => defined ( 'ADDON_VERSION' ) ? ADDON_VERSION : 'unknown' ,
'commit' => $commit ,
'protocols' => $protocols ,
'plugins' => $visible_plugins ,
2022-01-29 22:27:35 +00:00
'register_policy' => $register_policy [ get_config ( 'system' , 'register_policy' )],
2022-09-03 22:06:54 +00:00
'invitation_only' => ( defined ( 'INVITE_WORKING' ) && intval ( get_config ( 'system' , 'invitation_only' ))),
2021-12-03 03:01:39 +00:00
'language' => get_config ( 'system' , 'language' ),
'expiration' => $site_expire ,
'default_service_restrictions' => $service_class ,
'locked_features' => $locked_features ,
'admin' => $admin ,
'dbdriver' => DBA :: $dba -> getdriver () . ' ' . (( ACTIVE_DBTYPE == DBTYPE_POSTGRES ) ? 'postgres' : 'mysql' ),
'lastpoll' => get_config ( 'system' , 'lastpoll' ),
'info' => (( $site_info ) ? $site_info : '' )
];
2022-09-03 22:06:54 +00:00
}
function match_access_rule ( $resource , $allowed , $denied , $retvalue ) {
if ( is_array ( $allowed ) && $allowed ) {
if ( ! ( is_array ( $denied ) && $denied )) {
$retvalue = false ;
}
foreach ( $allowed as $entry ) {
if ( $entry === '*' ) {
$retvalue = true ;
}
if ( $entry && ( str_contains ( $resource , $entry ) || wildmat ( $entry , $resource ))) {
return true ;
}
}
}
if ( is_array ( $denied ) && $denied ) {
foreach ( $denied as $entry ) {
if ( $entry === '*' ) {
$retvalue = false ;
}
if ( $entry && ( str_contains ( $resource , $entry ) || wildmat ( $entry , $resource ))) {
return false ;
}
}
}
2022-09-03 21:30:13 +00:00
2022-09-03 22:06:54 +00:00
return $retvalue ;
2015-11-30 04:26:00 +00:00
}
2017-04-06 17:45:19 +00:00
/**
* @ brief
*
* @ param string $url
2021-12-02 23:02:31 +00:00
* @ return bool
2017-04-06 17:45:19 +00:00
*/
2021-12-03 03:01:39 +00:00
function check_siteallowed ( $url )
{
2015-11-30 04:26:00 +00:00
2021-12-03 03:01:39 +00:00
$retvalue = true ;
2015-11-30 04:26:00 +00:00
2022-09-03 22:06:54 +00:00
if ( ! ( isset ( $url ) && $url )) {
2022-04-21 21:46:21 +00:00
return false ;
}
2022-09-03 22:06:54 +00:00
$arr = [ 'url' => $url ];
2021-12-03 03:01:39 +00:00
/**
* @ hooks check_siteallowed
* Used to over - ride or bypass the site black / white block lists .
* * \e string \b url
* * \e boolean \b allowed - optional return value set in hook
*/
2022-02-12 08:50:48 +00:00
Hook :: call ( 'check_siteallowed' , $arr );
2015-12-07 04:45:21 +00:00
2021-12-03 03:01:39 +00:00
if ( array_key_exists ( 'allowed' , $arr )) {
return $arr [ 'allowed' ];
}
2015-12-07 04:45:21 +00:00
2021-12-03 03:01:39 +00:00
// your own site is always allowed
2022-09-03 22:06:54 +00:00
if ( str_contains ( $url , z_root ())) {
2021-12-03 03:01:39 +00:00
return $retvalue ;
}
2021-04-15 00:33:21 +00:00
2022-09-03 22:06:54 +00:00
$allowed = get_config ( 'system' , 'allowed_sites' );
$denied = get_config ( 'system' , 'denied_sites' );
return match_access_rule ( $url , $allowed , $denied , $retvalue );
2015-11-30 04:26:00 +00:00
}
2019-01-05 22:47:21 +00:00
/**
* @ brief
*
* @ param string $url
2021-12-02 23:02:31 +00:00
* @ return bool
2019-01-05 22:47:21 +00:00
*/
2021-12-03 03:01:39 +00:00
function check_pubstream_siteallowed ( $url )
{
2019-01-05 22:47:21 +00:00
2021-12-03 03:01:39 +00:00
$retvalue = true ;
2019-01-05 22:47:21 +00:00
2022-09-03 22:06:54 +00:00
$arr = [ 'url' => $url ];
2021-12-03 03:01:39 +00:00
/**
* @ hooks check_siteallowed
* Used to over - ride or bypass the site black / white block lists .
* * \e string \b url
* * \e boolean \b allowed - optional return value set in hook
*/
2022-02-12 08:50:48 +00:00
Hook :: call ( 'pubstream_check_siteallowed' , $arr );
2019-01-05 22:47:21 +00:00
2021-12-03 03:01:39 +00:00
if ( array_key_exists ( 'allowed' , $arr )) {
return $arr [ 'allowed' ];
}
2019-01-05 22:47:21 +00:00
2021-12-03 03:01:39 +00:00
// your own site is always allowed
2022-11-20 05:28:50 +00:00
if ( str_contains ( $url , z_root ())) {
2021-12-03 03:01:39 +00:00
return $retvalue ;
}
2021-04-15 00:33:21 +00:00
2022-09-03 22:06:54 +00:00
$allowed = get_config ( 'system' , 'pubstream_allowed_sites' );
$denied = get_config ( 'system' , 'pubstream_denied_sites' );
return match_access_rule ( $url , $allowed , $denied , $retvalue );
2019-01-05 22:47:21 +00:00
}
2017-04-06 17:45:19 +00:00
/**
* @ brief
*
* @ param string $hash
2021-12-02 23:02:31 +00:00
* @ return bool
2017-04-06 17:45:19 +00:00
*/
2021-12-03 03:01:39 +00:00
function check_channelallowed ( $hash )
{
2015-11-30 04:26:00 +00:00
2021-12-03 03:01:39 +00:00
$retvalue = true ;
2015-11-30 04:26:00 +00:00
2022-09-03 22:06:54 +00:00
$arr = [ 'hash' => $hash ];
2021-12-03 03:01:39 +00:00
/**
* @ hooks check_channelallowed
* Used to over - ride or bypass the channel black / white block lists .
* * \e string \b hash
* * \e boolean \b allowed - optional return value set in hook
*/
2022-02-12 08:50:48 +00:00
Hook :: call ( 'check_channelallowed' , $arr );
2015-12-07 04:45:21 +00:00
2021-12-03 03:01:39 +00:00
if ( array_key_exists ( 'allowed' , $arr )) {
return $arr [ 'allowed' ];
}
2015-12-07 04:45:21 +00:00
2022-09-03 22:06:54 +00:00
$allowed = get_config ( 'system' , 'allowed_channels' );
$denied = get_config ( 'system' , 'denied_channels' );
return match_access_rule ( $hash , $allowed , $denied , $retvalue );
2015-11-30 04:26:00 +00:00
}
2019-01-05 22:47:21 +00:00
/**
* @ brief
*
* @ param string $hash
2021-12-02 23:02:31 +00:00
* @ return bool
2019-01-05 22:47:21 +00:00
*/
2021-12-03 03:01:39 +00:00
function check_pubstream_channelallowed ( $hash )
{
2019-01-05 22:47:21 +00:00
2021-12-03 03:01:39 +00:00
$retvalue = true ;
2019-01-05 22:47:21 +00:00
2022-11-20 05:28:50 +00:00
$arr = [ 'hash' => $hash ];
2021-12-03 03:01:39 +00:00
/**
* @ hooks check_channelallowed
* Used to over - ride or bypass the channel black / white block lists .
* * \e string \b hash
* * \e boolean \b allowed - optional return value set in hook
*/
2022-02-12 08:50:48 +00:00
Hook :: call ( 'check_pubstream_channelallowed' , $arr );
2019-01-05 22:47:21 +00:00
2021-12-03 03:01:39 +00:00
if ( array_key_exists ( 'allowed' , $arr )) {
return $arr [ 'allowed' ];
}
2019-01-05 22:47:21 +00:00
2022-09-03 22:06:54 +00:00
$allowed = get_config ( 'system' , 'pubstream_allowed_channels' );
$denied = get_config ( 'system' , 'pubstream_denied_channels' );
return match_access_rule ( $hash , $allowed , $denied , $retvalue );
2019-01-05 22:47:21 +00:00
}
2021-12-03 03:01:39 +00:00
function deliverable_singleton ( $channel_id , $xchan )
{
2015-12-10 02:30:30 +00:00
2021-12-03 03:01:39 +00:00
if ( array_key_exists ( 'xchan_hash' , $xchan )) {
$xchan_hash = $xchan [ 'xchan_hash' ];
} elseif ( array_key_exists ( 'hubloc_hash' , $xchan )) {
$xchan_hash = $xchan [ 'hubloc_hash' ];
} else {
return true ;
}
$r = q (
" select abook_instance from abook where abook_channel = %d and abook_xchan = '%s' limit 1 " ,
intval ( $channel_id ),
dbesc ( $xchan_hash )
);
if ( $r ) {
if ( ! $r [ 0 ][ 'abook_instance' ]) {
return true ;
}
2022-11-20 05:28:50 +00:00
if ( str_contains ( $r [ 0 ][ 'abook_instance' ], z_root ())) {
2021-12-03 03:01:39 +00:00
return true ;
}
}
return false ;
2015-12-10 02:30:30 +00:00
}
2016-05-11 04:46:04 +00:00
2021-12-03 03:01:39 +00:00
function get_repository_version ( $branch = 'release' )
{
2022-10-24 21:03:04 +00:00
$path = 'https://raw.codeberg.page/streams/' . REPOSITORY_ID . " /@ $branch /version.php " ;
2016-10-01 22:41:25 +00:00
2022-06-23 07:38:34 +00:00
$x = Url :: get ( $path );
2021-12-03 03:01:39 +00:00
if ( $x [ 'success' ]) {
$y = preg_match ( '/define(.*?)STD_VERSION(.*?)([0-9.].*)\'/' , $x [ 'body' ], $matches );
if ( $y ) {
return $matches [ 3 ];
}
}
return '?.?' ;
2016-10-01 22:41:25 +00:00
}
2016-05-21 05:13:20 +00:00
2017-04-06 17:45:19 +00:00
/**
* @ brief Get translated network name .
*
* @ param string $s Network string , see boot . php
* @ return string Translated name of the network
*/
2021-12-03 03:01:39 +00:00
function network_to_name ( $s )
{
2022-11-20 05:28:50 +00:00
$nets = [
2021-12-03 03:01:39 +00:00
NETWORK_FEED => t ( 'RSS/Atom' ),
NETWORK_ACTIVITYPUB => t ( 'ActivityPub' ),
NETWORK_DIASPORA => t ( 'Diaspora' ),
2022-06-21 23:13:01 +00:00
NETWORK_NOMAD => t ( 'Nomad' ),
NETWORK_ZOT6 => t ( 'Zot6' ),
2022-11-20 05:28:50 +00:00
];
2021-12-03 03:01:39 +00:00
/**
* @ hooks network_to_name
* @ deprecated
*/
2022-02-12 08:50:48 +00:00
Hook :: call ( 'network_to_name' , $nets );
2021-12-03 03:01:39 +00:00
$search = array_keys ( $nets );
$replace = array_values ( $nets );
return str_replace ( $search , $replace , $s );
2016-05-21 05:13:20 +00:00
}
2016-10-01 10:06:01 +00:00
2017-04-06 17:45:19 +00:00
/**
* @ brief Send a text email message .
*
2017-09-04 22:23:42 +00:00
* @ param array $params an associative array with :
2017-04-06 17:45:19 +00:00
* * \e string \b fromName name of the sender
* * \e string \b fromEmail email of the sender
2022-08-14 09:20:43 +00:00
* * \e string \b replyTo address to direct responses
2017-04-06 17:45:19 +00:00
* * \e string \b toEmail destination email address
* * \e string \b messageSubject subject of the message
* * \e string \b htmlVersion html version of the message
* * \e string \b textVersion text only version of the message
* * \e string \b additionalMailHeader additions to the smtp mail header
*/
2021-12-03 03:01:39 +00:00
function z_mail ( $params )
{
2016-10-01 10:06:01 +00:00
2021-12-03 03:01:39 +00:00
if ( ! $params [ 'fromEmail' ]) {
$params [ 'fromEmail' ] = get_config ( 'system' , 'from_email' );
if ( ! $params [ 'fromEmail' ]) {
$params [ 'fromEmail' ] = 'Administrator' . '@' . App :: get_hostname ();
}
}
if ( ! $params [ 'fromName' ]) {
$params [ 'fromName' ] = get_config ( 'system' , 'from_email_name' );
if ( ! $params [ 'fromName' ]) {
$params [ 'fromName' ] = System :: get_site_name ();
}
}
if ( ! $params [ 'replyTo' ]) {
$params [ 'replyTo' ] = get_config ( 'system' , 'reply_address' );
if ( ! $params [ 'replyTo' ]) {
$params [ 'replyTo' ] = 'noreply' . '@' . App :: get_hostname ();
}
}
2016-10-01 10:06:01 +00:00
2021-12-03 03:01:39 +00:00
$params [ 'sent' ] = false ;
$params [ 'result' ] = false ;
2016-10-01 10:06:01 +00:00
2021-12-03 03:01:39 +00:00
/**
* @ hooks email_send
* * \e params @ see z_mail ()
*/
2022-02-12 08:50:48 +00:00
Hook :: call ( 'email_send' , $params );
2016-10-01 10:06:01 +00:00
2021-12-03 03:01:39 +00:00
if ( $params [ 'sent' ]) {
logger ( 'notification: z_mail returns ' . (( $params [ 'result' ]) ? 'success' : 'failure' ), LOGGER_DEBUG );
return $params [ 'result' ];
}
2016-10-01 10:06:01 +00:00
2021-12-03 03:01:39 +00:00
$fromName = email_header_encode ( html_entity_decode ( $params [ 'fromName' ], ENT_QUOTES , 'UTF-8' ), 'UTF-8' );
$messageSubject = email_header_encode ( html_entity_decode ( $params [ 'messageSubject' ], ENT_QUOTES , 'UTF-8' ), 'UTF-8' );
$messageHeader =
$params [ 'additionalMailHeader' ] .
" From: $fromName < { $params [ 'fromEmail' ] } > " . PHP_EOL .
" Reply-To: $fromName < { $params [ 'replyTo' ] } > " . PHP_EOL .
" Content-Type: text/plain; charset=UTF-8 " ;
// send the message
$res = mail (
$params [ 'toEmail' ], // send to address
$messageSubject , // subject
$params [ 'textVersion' ],
$messageHeader // message headers
);
logger ( 'notification: z_mail returns ' . (( $res ) ? 'success' : 'failure' ), LOGGER_DEBUG );
return $res ;
2016-10-01 10:06:01 +00:00
}
2016-10-12 03:53:13 +00:00
2017-04-06 17:45:19 +00:00
/**
2022-04-10 01:47:20 +00:00
* @ brief Discover the best API path available for the project servers .
2017-04-06 17:45:19 +00:00
*
* @ param string $host
* @ return string
*/
2021-12-03 03:01:39 +00:00
function probe_api_path ( $host )
{
2016-10-12 03:53:13 +00:00
2021-12-03 03:01:39 +00:00
$schemes = [ 'https' , 'http' ];
$paths = [ '/api/z/1.0/version' , '/api/red/version' ];
2016-10-12 03:53:13 +00:00
2021-12-03 03:01:39 +00:00
foreach ( $schemes as $scheme ) {
foreach ( $paths as $path ) {
$curpath = $scheme . '://' . $host . $path ;
2022-06-23 07:38:34 +00:00
$x = Url :: get ( $curpath );
2021-12-03 03:01:39 +00:00
if ( $x [ 'success' ] && ! strpos ( $x [ 'body' ], 'not implemented' )) {
return str_replace ( 'version' , '' , $curpath );
}
}
}
2016-10-12 03:53:13 +00:00
2021-12-03 03:01:39 +00:00
return '' ;
2016-10-27 00:41:32 +00:00
}
2017-05-03 03:17:47 +00:00
2021-12-03 03:01:39 +00:00
function service_plink ( $contact , $guid )
{
2017-05-05 04:55:56 +00:00
2021-12-03 03:01:39 +00:00
$plink = '' ;
2017-05-05 04:55:56 +00:00
2021-12-03 03:01:39 +00:00
$m = parse_url ( $contact [ 'xchan_url' ]);
if ( $m ) {
$url = $m [ 'scheme' ] . '://' . $m [ 'host' ] . (( isset ( $m [ 'port' ]) && intval ( $m [ 'port' ])) ? ':' . intval ( $m [ 'port' ]) : '' );
} else {
$url = 'https://' . substr ( $contact [ 'xchan_addr' ], strpos ( $contact [ 'xchan_addr' ], '@' ) + 1 );
}
2017-05-05 04:55:56 +00:00
2021-12-03 03:01:39 +00:00
$handle = substr ( $contact [ 'xchan_addr' ], 0 , strpos ( $contact [ 'xchan_addr' ], '@' ));
2017-05-05 04:55:56 +00:00
2021-12-03 03:01:39 +00:00
$plink = $url . '/channel/' . $handle . '?f=&mid=' . $guid ;
2017-05-05 04:55:56 +00:00
2021-12-03 03:01:39 +00:00
$x = [ 'xchan' => $contact , 'guid' => $guid , 'url' => $url , 'plink' => $plink ];
/**
* @ hooks service_plink
* * \e array \b xchan
* * \e string \b guid
* * \e string \b url
* * \e string \b plink will get returned
*/
2022-02-12 08:50:48 +00:00
Hook :: call ( 'service_plink' , $x );
2017-05-05 04:55:56 +00:00
2021-12-03 03:01:39 +00:00
return $x [ 'plink' ];
2017-05-05 04:55:56 +00:00
}
2017-09-04 22:23:42 +00:00
/**
* @ brief
*
* @ param array $mimeTypes
* @ param string $acceptedTypes by default false will use $_SERVER [ 'HTTP_ACCEPT' ]
* @ return array | NULL
*/
2021-12-03 03:01:39 +00:00
function getBestSupportedMimeType ( $mimeTypes = null , $acceptedTypes = false )
{
// Values will be stored in this array
$AcceptTypes = [];
2017-07-18 02:53:03 +00:00
2021-12-03 03:01:39 +00:00
if ( $acceptedTypes === false ) {
$acceptedTypes = (( isset ( $_SERVER [ 'HTTP_ACCEPT' ]) && $_SERVER [ 'HTTP_ACCEPT' ]) ? $_SERVER [ 'HTTP_ACCEPT' ] : EMPTY_STR );
}
2017-07-18 02:53:03 +00:00
2022-08-14 09:20:43 +00:00
// Accept header is case-insensitive, and whitespace isn’ t important
2021-12-03 03:01:39 +00:00
$accept = strtolower ( str_replace ( ' ' , '' , $acceptedTypes ));
// divide it into parts in the place of a ","
$accept = explode ( ',' , $accept );
foreach ( $accept as $a ) {
// the default quality is 1.
$q = 1 ;
// check if there is a different quality
if ( strpos ( $a , ';q=' )) {
// divide "mime/type;q=X" into two parts: "mime/type" i "X"
list ( $a , $q ) = explode ( ';q=' , $a );
}
// mime-type $a is accepted with the quality $q
// WARNING: $q == 0 means, that mime-type isn’ t supported!
$AcceptTypes [ $a ] = $q ;
}
arsort ( $AcceptTypes );
2017-09-20 02:15:15 +00:00
2021-12-03 03:01:39 +00:00
// if no parameter was passed, just return parsed data
if ( ! $mimeTypes ) {
return $AcceptTypes ;
}
2017-09-20 02:15:15 +00:00
2021-12-03 03:01:39 +00:00
$mimeTypes = array_map ( 'strtolower' , ( array ) $mimeTypes );
2017-09-20 02:15:15 +00:00
2021-12-03 03:01:39 +00:00
// let’ s check our supported types:
foreach ( $AcceptTypes as $mime => $q ) {
if ( $q && in_array ( $mime , $mimeTypes )) {
2022-09-03 21:16:47 +00:00
return [ $mime ];
2021-12-03 03:01:39 +00:00
}
}
2017-09-04 22:23:42 +00:00
2021-12-03 03:01:39 +00:00
// no mime-type found
return null ;
2017-09-04 22:23:42 +00:00
}
/**
* @ brief Perform caching for jsonld normaliser .
*
* @ param string $url
2021-12-02 23:02:31 +00:00
* @ return mixed | bool | array
2017-09-04 22:23:42 +00:00
*/
2021-12-03 03:01:39 +00:00
function jsonld_document_loader ( $url )
{
2017-09-20 02:15:15 +00:00
2021-12-03 03:01:39 +00:00
require_once ( 'library/jsonld/jsonld.php' );
2017-09-20 02:15:15 +00:00
2021-12-03 03:01:39 +00:00
$recursion = 0 ;
2018-08-11 23:16:54 +00:00
2021-12-03 03:01:39 +00:00
$x = debug_backtrace ();
if ( $x ) {
foreach ( $x as $n ) {
if ( $n [ 'function' ] === __FUNCTION__ ) {
$recursion ++ ;
}
}
}
if ( $recursion > 5 ) {
logger ( 'jsonld bomb detected at: ' . $url );
killme ();
}
2018-08-11 23:16:54 +00:00
2021-12-03 03:01:39 +00:00
$cachepath = 'cache/ldcache' ;
if ( ! is_dir ( $cachepath )) {
2022-06-22 10:19:52 +00:00
Stdio :: mkdir ( $cachepath , STORAGE_DEFAULT_PERMISSIONS , true );
2021-12-03 03:01:39 +00:00
}
2017-09-20 02:15:15 +00:00
2021-12-03 03:01:39 +00:00
$filename = $cachepath . '/' . urlencode ( $url );
if ( file_exists ( $filename ) && filemtime ( $filename ) > time () - ( 12 * 60 * 60 )) {
return json_decode ( file_get_contents ( $filename ));
}
2017-09-20 02:15:15 +00:00
2021-12-03 03:01:39 +00:00
$r = jsonld_default_document_loader ( $url );
if ( $r ) {
file_put_contents ( $filename , json_encode ( $r ));
return $r ;
}
2017-09-20 02:15:15 +00:00
2021-12-03 03:01:39 +00:00
logger ( 'not found' );
if ( file_exists ( $filename )) {
return json_decode ( file_get_contents ( $filename ));
}
2017-09-20 02:15:15 +00:00
2021-12-03 03:01:39 +00:00
return [];
2018-04-23 02:49:26 +00:00
}
2021-12-03 03:01:39 +00:00
function is_https_request ()
{
$https = false ;
2021-04-11 23:27:44 +00:00
2021-12-03 03:01:39 +00:00
if ( array_key_exists ( 'HTTPS' , $_SERVER ) && $_SERVER [ 'HTTPS' ]) {
$https = true ;
} elseif ( array_key_exists ( 'SERVER_PORT' , $_SERVER ) && intval ( $_SERVER [ 'SERVER_PORT' ]) === 443 ) {
$https = true ;
} elseif ( array_key_exists ( 'HTTP_X_FORWARDED_PROTO' , $_SERVER ) && $_SERVER [ 'HTTP_X_FORWARDED_PROTO' ] === 'https' ) {
$https = true ; // technically this is not true, but pretending it is will allow reverse proxies to work
}
2021-04-11 23:27:44 +00:00
2021-12-03 03:01:39 +00:00
return $https ;
2018-05-23 06:20:29 +00:00
}
2018-10-11 00:58:51 +00:00
/**
2021-08-04 00:12:28 +00:00
* @ brief Given a URL , return everything after the host portion , but exclude any fragments .
2018-10-11 00:58:51 +00:00
* example https :// foobar . com / gravy ? g = 5 & y = 6
* returns / gravy ? g = 5 & y = 6
2021-08-04 00:12:28 +00:00
* example https ::// foobar . com / gravy ? g = 5 & y = 6 #fragment
* also returns / gravy ? g = 5 & y = 6
2018-10-11 00:58:51 +00:00
* result always returns the leading slash
*/
2021-12-03 03:01:39 +00:00
function get_request_string ( $url )
{
2021-08-04 00:12:28 +00:00
2021-12-03 03:01:39 +00:00
$m = parse_url ( $url );
if ( $m ) {
2022-11-20 06:44:13 +00:00
return ( ( $m [ 'path' ] ? ? '/' ) . ( isset ( $m [ 'query' ]) ? '?' . $m [ 'query' ] : '' ) );
2021-12-03 03:01:39 +00:00
}
2018-10-11 00:58:51 +00:00
2022-09-03 22:37:48 +00:00
return '' ;
2018-10-11 00:58:51 +00:00
}