diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/api_zot.php | 87 | ||||
-rw-r--r-- | include/attach.php | 6 | ||||
-rw-r--r-- | include/bb2diaspora.php | 12 | ||||
-rw-r--r-- | include/bbcode.php | 66 | ||||
-rw-r--r-- | include/config.php | 24 | ||||
-rw-r--r-- | include/conversation.php | 4 | ||||
-rw-r--r-- | include/crypto.php | 117 | ||||
-rwxr-xr-x | include/dba/dba_driver.php | 2 | ||||
-rwxr-xr-x | include/dba/dba_pdo.php | 2 | ||||
-rw-r--r-- | include/dir_fns.php | 10 | ||||
-rw-r--r-- | include/help.php | 5 | ||||
-rwxr-xr-x | include/items.php | 34 | ||||
-rw-r--r-- | include/nav.php | 20 | ||||
-rwxr-xr-x | include/oembed.php | 2 | ||||
-rw-r--r-- | include/queue_fn.php | 2 | ||||
-rw-r--r-- | include/taxonomy.php | 2 | ||||
-rw-r--r-- | include/text.php | 9 | ||||
-rw-r--r-- | include/widgets.php | 30 | ||||
-rw-r--r-- | include/wiki.php | 96 | ||||
-rw-r--r-- | include/zot.php | 342 |
20 files changed, 578 insertions, 294 deletions
diff --git a/include/api_zot.php b/include/api_zot.php index 60cb288af..bdbed6a5f 100644 --- a/include/api_zot.php +++ b/include/api_zot.php @@ -28,11 +28,12 @@ api_register_func('api/z/1.0/group','api_group', true); api_register_func('api/red/xchan','api_red_xchan',true); api_register_func('api/z/1.0/xchan','api_red_xchan',true); - api_register_func('api/red/item/new','red_item_new', true); - api_register_func('api/z/1.0/item/new','red_item_new', true); + api_register_func('api/red/item/update','zot_item_update', true); + api_register_func('api/z/1.0/item/update','zot_item_update', true); api_register_func('api/red/item/full','red_item', true); api_register_func('api/z/1.0/item/full','red_item', true); + api_register_func('api/z/1.0/network/stream','api_network_stream', true); api_register_func('api/z/1.0/abook','api_zot_abook_xchan',true); api_register_func('api/z/1.0/abconfig','api_zot_abconfig',true); api_register_func('api/z/1.0/perm_allowed','api_zot_perm_allowed',true); @@ -55,24 +56,81 @@ } + function api_network_stream($type) { + if(api_user() === false) { + logger('api_channel_stream: no user'); + return false; + } + + $channel = channelx_by_n(api_user()); + if(! $channel) + return false; + + + if($_SERVER['REQUEST_METHOD'] == 'POST') { + // json_return_and_die(post_activity_item($_REQUEST)); + } + else { + $mindate = (($_REQUEST['mindate']) ? datetime_convert('UTC','UTC',$_REQUEST['mindate']) : ''); + if(! $mindate) + $mindate = datetime_convert('UTC','UTC', 'now - 14 days'); + + $arr = $_REQUEST; + $ret = []; + $i = items_fetch($arr,App::get_channel(),get_observer_hash()); + if($i) { + foreach($i as $iv) { + $ret[] = encode_item($iv); + } + } + + json_return_and_die($ret); + } + } + + + + + + function api_channel_stream($type) { if(api_user() === false) { logger('api_channel_stream: no user'); return false; } + $channel = channelx_by_n(api_user()); + if(! $channel) + return false; + + if($_SERVER['REQUEST_METHOD'] == 'POST') { json_return_and_die(post_activity_item($_REQUEST)); } else { - // fetch stream + $mindate = (($_REQUEST['mindate']) ? datetime_convert('UTC','UTC',$_REQUEST['mindate']) : ''); + if(! $mindate) + $mindate = datetime_convert('UTC','UTC', 'now - 14 days'); + json_return_and_die(zot_feed($channel['channel_id'],$channel['channel_hash'],[ 'mindate' => $mindate ])); } } function api_attach_list($type) { logger('api_user: ' . api_user()); - json_return_and_die(attach_list_files(api_user(),get_observer_hash(),'','','','created asc')); + $hash = ((array_key_exists('filehash',$_REQUEST)) ? $_REQUEST['filehash'] : ''); + $filename = ((array_key_exists('filename',$_REQUEST)) ? $_REQUEST['filename'] : ''); + $filetype = ((array_key_exists('filetype',$_REQUEST)) ? $_REQUEST['filetype'] : ''); + $start = ((array_key_exists('start',$_REQUEST)) ? intval($_REQUEST['start']) : 0); + $records = ((array_key_exists('records',$_REQUEST)) ? intval($_REQUEST['records']) : 0); + + $x = attach_list_files(api_user(),get_observer_hash(),$hash,$filename,$filetype,'created asc',$start,$records); + if($start || $records) { + $x['start'] = $start; + $x['records'] = count($x['results']); + } + + json_return_and_die($x); } @@ -237,8 +295,8 @@ } if($r) { - $x = q("select * from group_member left join xchan on group_member.xchan = xchan.xchan_hash - left join abook on abook_xchan = xchan_hash where gid = %d", + $x = q("select * from group_member left join abook on abook_xchan = xchan and abook_channel = group_member.uid left join xchan on group_member.xchan = xchan.xchan_hash + where gid = %d", intval($r[0]['id']) ); json_return_and_die($x); @@ -266,7 +324,7 @@ require_once('include/hubloc.php'); if($_SERVER['REQUEST_METHOD'] === 'POST') { - $r = xchan_store($_REQUEST); + // $r = xchan_store($_REQUEST); } $r = xchan_fetch($_REQUEST); json_return_and_die($r); @@ -341,15 +399,15 @@ } - function red_item_new($type) { + function zot_item_update($type) { if (api_user() === false) { - logger('api_red_item_new: no user'); + logger('api_red_item_store: no user'); return false; } - logger('api_red_item_new: REQUEST ' . print_r($_REQUEST,true)); - logger('api_red_item_new: FILES ' . print_r($_FILES,true)); + logger('api_red_item_store: REQUEST ' . print_r($_REQUEST,true)); + logger('api_red_item_store: FILES ' . print_r($_FILES,true)); // set this so that the item_post() function is quiet and doesn't redirect or emit json @@ -360,11 +418,10 @@ if(x($_FILES,'media')) { $_FILES['userfile'] = $_FILES['media']; // upload the image if we have one - $_REQUEST['silent']='1'; //tell wall_upload function to return img info instead of echo - $mod = new Zotlabs\Module\Wall_upload(); + $mod = new Zotlabs\Module\Wall_attach(); $media = $mod->post(); - if(strlen($media)>0) - $_REQUEST['body'] .= "\n\n".$media; + if($media) + $_REQUEST['body'] .= "\n\n" . $media; } $mod = new Zotlabs\Module\Item(); diff --git a/include/attach.php b/include/attach.php index ac0185f5d..ba2f60a90 100644 --- a/include/attach.php +++ b/include/attach.php @@ -197,13 +197,13 @@ function attach_list_files($channel_id, $observer, $hash = '', $filename = '', $ $sql_extra .= protect_sprintf(" and hash = '" . dbesc($hash) . "' "); if($filename) - $sql_extra .= protect_sprintf(" and filename like '@" . dbesc($filename) . "@' "); + $sql_extra .= protect_sprintf(" and filename like '%" . dbesc($filename) . "%' "); if($filetype) - $sql_extra .= protect_sprintf(" and filetype like '@" . dbesc($filetype) . "@' "); + $sql_extra .= protect_sprintf(" and filetype like '%" . dbesc($filetype) . "%' "); if($entries) - $limit = " limit " . intval($start) . ", " . intval(entries) . " "; + $limit = " limit " . intval($start) . ", " . intval($entries) . " "; // Retrieve all columns except 'data' diff --git a/include/bb2diaspora.php b/include/bb2diaspora.php index da02d6cac..e22b6a7dd 100644 --- a/include/bb2diaspora.php +++ b/include/bb2diaspora.php @@ -149,16 +149,18 @@ function markdown_to_bb($s, $use_zrl = false) { $s = html2bbcode($s); + $s = preg_replace("/\[([uz])rl=(.*?)\]\[\/[uz]rl\]/ism",'[$1rl=$2]$2[/$1rl]',$s); + // protect the recycle symbol from turning into a tag, but without unescaping angles and naked ampersands $s = str_replace('♲',html_entity_decode('♲',ENT_QUOTES,'UTF-8'),$s); // Convert everything that looks like a link to a link if($use_zrl) { $s = str_replace(array('[img','/img]'),array('[zmg','/zmg]'),$s); - $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[zrl=$2$3]$2$3[/zrl]',$s); + $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\(\)]+)/ism", '$1[zrl=$2$3]$2$3[/zrl]',$s); } else { - $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", '$1[url=$2$3]$2$3[/url]',$s); + $s = preg_replace("/([^\]\=]|^)(https?\:\/\/)([a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\(\)]+)/ism", '$1[url=$2$3]$2$3[/url]',$s); } // remove duplicate adjacent code tags @@ -427,6 +429,12 @@ function bb2diaspora($Text,$preserve_nl = false, $fordiaspora = true) { $Text = preg_replace_callback('/\@\!?\[([zu])rl\=(\w+.*?)\](\w+.*?)\[\/([zu])rl\]/i', 'bb2dmention_callback', $Text); + // strip map tags, as the rendering is performed in bbcode() and the resulting output + // is not compatible with Diaspora (at least in the case of openstreetmap and probably + // due to the inclusion of an html iframe) + + $Text = preg_replace("/\[map\=(.*?)\]/ism", '$1', $Text); + $Text = preg_replace("/\[map\](.*?)\[\/map\]/ism", '$1', $Text); // Converting images with size parameters to simple images. Markdown doesn't know it. $Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $Text); diff --git a/include/bbcode.php b/include/bbcode.php index 21bc6de77..b315255f5 100644 --- a/include/bbcode.php +++ b/include/bbcode.php @@ -512,10 +512,10 @@ function bb_code($match) { } function bb_highlight($match) { - if(in_array(strtolower($match[1]),['php','css','mysql','sql','abap','diff','html','perl','ruby', + $lang = ((in_array(strtolower($match[1]),['php','css','mysql','sql','abap','diff','html','perl','ruby', 'vbscript','avrc','dtd','java','xml','cpp','python','javascript','js','json','sh'])) - return text_highlight($match[2],strtolower($match[1])); - return $match[0]; + ? strtolower($match[1]) : 'php' ); + return text_highlight($match[2],$lang); } function bb_fixtable_lf($match) { @@ -529,7 +529,49 @@ function bb_fixtable_lf($match) { } +function parseIdentityAwareHTML($Text) { + + // process [observer] tags before we do anything else because we might + // be stripping away stuff that then doesn't need to be worked on anymore + $observer = App::get_observer(); + + if ((strpos($Text,'[/observer]') !== false) || (strpos($Text,'[/rpost]') !== false)) { + if ($observer) { + $Text = preg_replace("/\[observer\=1\](.*?)\[\/observer\]/ism", '$1', $Text); + $Text = preg_replace("/\[observer\=0\].*?\[\/observer\]/ism", '', $Text); + $Text = preg_replace_callback("/\[rpost(=(.*?))?\](.*?)\[\/rpost\]/ism", 'rpost_callback', $Text); + } else { + $Text = preg_replace("/\[observer\=1\].*?\[\/observer\]/ism", '', $Text); + $Text = preg_replace("/\[observer\=0\](.*?)\[\/observer\]/ism", '$1', $Text); + $Text = preg_replace("/\[rpost(=.*?)?\](.*?)\[\/rpost\]/ism", '', $Text); + } + } + // replace [observer.baseurl] + if ($observer) { + $s1 = '<span class="bb_observer" title="' . t('Different viewers will see this text differently') . '">'; + $s2 = '</span>'; + $obsBaseURL = $observer['xchan_connurl']; + $obsBaseURL = preg_replace("/\/poco\/.*$/", '', $obsBaseURL); + $Text = str_replace('[observer.baseurl]', $obsBaseURL, $Text); + $Text = str_replace('[observer.url]',$observer['xchan_url'], $Text); + $Text = str_replace('[observer.name]',$s1 . $observer['xchan_name'] . $s2, $Text); + $Text = str_replace('[observer.address]',$s1 . $observer['xchan_addr'] . $s2, $Text); + $Text = str_replace('[observer.webname]', substr($observer['xchan_addr'],0,strpos($observer['xchan_addr'],'@')), $Text); + $Text = str_replace('[observer.photo]',$s1 . '[zmg]'.$observer['xchan_photo_l'].'[/zmg]' . $s2, $Text); + } else { + $Text = str_replace('[observer.baseurl]', '', $Text); + $Text = str_replace('[observer.url]','', $Text); + $Text = str_replace('[observer.name]','', $Text); + $Text = str_replace('[observer.address]','', $Text); + $Text = str_replace('[observer.webname]','',$Text); + $Text = str_replace('[observer.photo]','', $Text); + } + + $Text = str_replace(array('[baseurl]','[sitename]'),array(z_root(),get_config('system','sitename')),$Text); + + return $Text; +} // BBcode 2 HTML was written by WAY2WEB.net // extended to work with Mistpark/Friendica/Redmatrix/Hubzilla - Mike Macgirvin @@ -661,7 +703,7 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) // Perform URL Search - $urlchars = '[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,\@]'; + $urlchars = '[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,\@\(\)]'; if (strpos($Text,'http') !== false) { if($tryoembed) { @@ -745,6 +787,12 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) if (strpos($Text,'[/color]') !== false) { $Text = preg_replace("(\[color=(.*?)\](.*?)\[\/color\])ism", "<span style=\"color: $1;\">$2</span>", $Text); } + // Check for colored text + if (strpos($Text,'[/hl]') !== false) { + $Text = preg_replace("(\[hl\](.*?)\[\/hl\])ism", "<span style=\"background-color: yellow;\">$1</span>", $Text); + $Text = preg_replace("(\[hl=(.*?)\](.*?)\[\/hl\])ism", "<span style=\"background-color: $1;\">$2</span>", $Text); + } + // Check for sized text // [size=50] --> font-size: 50px (with the unit). if (strpos($Text,'[/size]') !== false) { @@ -776,12 +824,14 @@ function bbcode($Text, $preserve_nl = false, $tryoembed = true, $cache = false) $Text = preg_replace("(\[h6\](.*?)\[\/h6\])ism",'<h6>$1</h6>',$Text); } // Check for table of content without params - if (strpos($Text,'[toc]') !== false) { - $Text = preg_replace("/\[toc\]/ism",'<ul id="toc"></ul>',$Text); + while(strpos($Text,'[toc]') !== false) { + $toc_id = 'toc-' . random_string(10); + $Text = preg_replace("/\[toc\]/ism", '<ul id="' . $toc_id . '" class="toc" data-toc=".section-content-wrapper"></ul><script>$("#' . $toc_id . '").toc();</script>', $Text, 1); } // Check for table of content with params - if (strpos($Text,'[toc') !== false) { - $Text = preg_replace("/\[toc([^\]]+?)\]/ism",'<ul$1></ul>',$Text); + while(strpos($Text,'[toc') !== false) { + $toc_id = 'toc-' . random_string(10); + $Text = preg_replace("/\[toc([^\]]+?)\]/ism", '<ul id="' . $toc_id . '" class="toc"$1></ul><script>$("#' . $toc_id . '").toc();</script>', $Text, 1); } // Check for centered text if (strpos($Text,'[/center]') !== false) { diff --git a/include/config.php b/include/config.php index 44ef29614..0b0e639ab 100644 --- a/include/config.php +++ b/include/config.php @@ -35,8 +35,8 @@ function load_config($family) { Zlib\Config::Load($family); } -function get_config($family, $key) { - return Zlib\Config::Get($family,$key); +function get_config($family, $key, $default = false) { + return Zlib\Config::Get($family,$key,$default); } function set_config($family, $key, $value) { @@ -51,8 +51,8 @@ function load_pconfig($uid) { Zlib\PConfig::Load($uid); } -function get_pconfig($uid, $family, $key, $instore = false) { - return Zlib\PConfig::Get($uid,$family,$key,$instore = false); +function get_pconfig($uid, $family, $key, $default = false) { + return Zlib\PConfig::Get($uid,$family,$key,$default); } function set_pconfig($uid, $family, $key, $value) { @@ -67,8 +67,8 @@ function load_xconfig($xchan) { Zlib\XConfig::Load($xchan); } -function get_xconfig($xchan, $family, $key) { - return Zlib\XConfig::Get($xchan,$family,$key); +function get_xconfig($xchan, $family, $key, $default = false) { + return Zlib\XConfig::Get($xchan,$family,$key, $default); } function set_xconfig($xchan, $family, $key, $value) { @@ -83,8 +83,8 @@ function load_aconfig($account_id) { Zlib\AConfig::Load($account_id); } -function get_aconfig($account_id, $family, $key) { - return Zlib\AConfig::Get($account_id, $family, $key); +function get_aconfig($account_id, $family, $key, $default = false) { + return Zlib\AConfig::Get($account_id, $family, $key, $default); } function set_aconfig($account_id, $family, $key, $value) { @@ -99,8 +99,8 @@ function load_abconfig($chan, $xhash, $family = '') { return Zlib\AbConfig::Load($chan,$xhash,$family); } -function get_abconfig($chan,$xhash,$family,$key) { - return Zlib\AbConfig::Get($chan,$xhash,$family,$key); +function get_abconfig($chan,$xhash,$family,$key, $default = false) { + return Zlib\AbConfig::Get($chan,$xhash,$family,$key, $default); } function set_abconfig($chan,$xhash,$family,$key,$value) { @@ -115,8 +115,8 @@ function load_iconfig(&$item) { Zlib\IConfig::Load($item); } -function get_iconfig(&$item, $family, $key) { - return Zlib\IConfig::Get($item, $family, $key); +function get_iconfig(&$item, $family, $key, $default = false) { + return Zlib\IConfig::Get($item, $family, $key, $default); } function set_iconfig(&$item, $family, $key, $value, $sharing = false) { diff --git a/include/conversation.php b/include/conversation.php index c260eb4a0..0f61eea27 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -363,7 +363,7 @@ function localize_item(&$item){ if(intval($item['item_obscured']) && strlen($item['body']) && (! strpos($item['body'],'data'))) { - $item['body'] = json_encode(crypto_encapsulate($item['body'],get_config('system','pubkey'))); + $item['body'] = z_obscure($item['body']); } } @@ -1752,7 +1752,7 @@ function profile_tabs($a, $is_owner = false, $nickname = null){ if(feature_enabled($uid,'wiki') && (get_account_techlevel($account_id) > 3)) { $tabs[] = array( - 'label' => t('Wiki'), + 'label' => t('Wikis'), 'url' => z_root() . '/wiki/' . $nickname, 'sel' => ((argv(0) == 'wiki') ? 'active' : ''), 'title' => t('Wiki'), diff --git a/include/crypto.php b/include/crypto.php index bc798d919..f75390985 100644 --- a/include/crypto.php +++ b/include/crypto.php @@ -48,27 +48,122 @@ function pkcs5_unpad($text) function AES256CBC_encrypt($data,$key,$iv) { return openssl_encrypt($data,'aes-256-cbc',str_pad($key,32,"\0"),OPENSSL_RAW_DATA,str_pad($iv,16,"\0")); - } function AES256CBC_decrypt($data,$key,$iv) { return openssl_decrypt($data,'aes-256-cbc',str_pad($key,32,"\0"),OPENSSL_RAW_DATA,str_pad($iv,16,"\0")); +} + +function AES128CBC_encrypt($data,$key,$iv) { + $key = substr($key,0,16); + $iv = substr($iv,0,16); + return openssl_encrypt($data,'aes-128-cbc',str_pad($key,16,"\0"),OPENSSL_RAW_DATA,str_pad($iv,16,"\0")); +} + +function AES128CBC_decrypt($data,$key,$iv) { + $key = substr($key,0,16); + $iv = substr($iv,0,16); + return openssl_decrypt($data,'aes-128-cbc',str_pad($key,16,"\0"),OPENSSL_RAW_DATA,str_pad($iv,16,"\0")); +} + +function STD_encrypt($data,$key,$iv) { + $key = substr($key,0,32); + $iv = substr($iv,0,16); + return openssl_encrypt($data,'aes-256-cbc',str_pad($key,32,"\0"),OPENSSL_RAW_DATA,str_pad($iv,16,"\0")); +} + +function STD_decrypt($data,$key,$iv) { + $key = substr($key,0,32); + $iv = substr($iv,0,16); + return openssl_decrypt($data,'aes-256-cbc',str_pad($key,32,"\0"),OPENSSL_RAW_DATA,str_pad($iv,16,"\0")); +} +function CAST5CBC_encrypt($data,$key,$iv) { + $key = substr($key,0,16); + $iv = substr($iv,0,8); + return openssl_encrypt($data,'cast5-cbc',str_pad($key,16,"\0"),OPENSSL_RAW_DATA,str_pad($iv,8,"\0")); +} + +function CAST5CBC_decrypt($data,$key,$iv) { + $key = substr($key,0,16); + $iv = substr($iv,0,8); + return openssl_decrypt($data,'cast5-cbc',str_pad($key,16,"\0"),OPENSSL_RAW_DATA,str_pad($iv,8,"\0")); } function crypto_encapsulate($data,$pubkey,$alg='aes256cbc') { + $fn = strtoupper($alg) . '_encrypt'; + if($alg === 'aes256cbc') return aes_encapsulate($data,$pubkey); + return other_encapsulate($data,$pubkey,$alg); + +} + +function other_encapsulate($data,$pubkey,$alg) { + if(! $pubkey) + logger('no key. data: ' . $data); + + $fn = strtoupper($alg) . '_encrypt'; + if(function_exists($fn)) { + + // A bit hesitant to use openssl_random_pseudo_bytes() as we know + // it has been historically targeted by US agencies for 'weakening'. + // It is still arguably better than trying to come up with an + // alternative cryptographically secure random generator. + // There is little point in using the optional second arg to flag the + // assurance of security since it is meaningless if the source algorithms + // have been compromised. Also none of this matters if RSA has been + // compromised by state actors and evidence is mounting that this has + // already happened. + + $key = openssl_random_pseudo_bytes(256); + $iv = openssl_random_pseudo_bytes(256); + $result['data'] = base64url_encode($fn($data,$key,$iv),true); + // log the offending call so we can track it down + if(! openssl_public_encrypt($key,$k,$pubkey)) { + $x = debug_backtrace(); + logger('RSA failed. ' . print_r($x[0],true)); + } + + $result['alg'] = $alg; + $result['key'] = base64url_encode($k,true); + openssl_public_encrypt($iv,$i,$pubkey); + $result['iv'] = base64url_encode($i,true); + return $result; + } + else { + $x = [ 'data' => $data, 'pubkey' => $pubkey, 'alg' => $alg, 'result' => $data ]; + call_hooks('other_encapsulate', $x); + return $x['result']; + } +} + +function crypto_methods() { + + if(\Zotlabs\Lib\System::get_server_role() !== 'pro') + return [ 'aes256cbc' ]; + + // 'std' is the new project standard which is aes256cbc but transmits/receives 256-byte key and iv. + // aes256cbc is provided for compatibility with earlier zot implementations which assume 32-byte key and 16-byte iv. + // other_encapsulate() now produces these longer keys/ivs by default so that it is difficult to guess a + // particular implementation or choice of underlying implementations based on the key/iv length. + // The actual methods are responsible for deriving the actual key/iv from the provided parameters; + // possibly by truncation or segmentation - though many other methods could be used. + + $r = [ 'std', 'aes256cbc', 'aes128cbc', 'cast5cbc' ]; + call_hooks('crypto_methods',$r); + return $r; + } function aes_encapsulate($data,$pubkey) { if(! $pubkey) logger('aes_encapsulate: no key. data: ' . $data); - $key = random_string(32,RANDOM_STRING_TEXT); - $iv = random_string(16,RANDOM_STRING_TEXT); + $key = openssl_random_pseudo_bytes(32); + $iv = openssl_random_pseudo_bytes(16); $result['data'] = base64url_encode(AES256CBC_encrypt($data,$key,$iv),true); // log the offending call so we can track it down if(! openssl_public_encrypt($key,$k,$pubkey)) { @@ -89,6 +184,22 @@ function crypto_unencapsulate($data,$prvkey) { if($alg === 'aes256cbc') return aes_unencapsulate($data,$prvkey); + return other_unencapsulate($data,$prvkey,$alg); + +} + +function other_unencapsulate($data,$prvkey,$alg) { + $fn = strtoupper($alg) . '_decrypt'; + if(function_exists($fn)) { + openssl_private_decrypt(base64url_decode($data['key']),$k,$prvkey); + openssl_private_decrypt(base64url_decode($data['iv']),$i,$prvkey); + return $fn(base64url_decode($data['data']),$k,$i); + } + else { + $x = [ 'data' => $data, 'prvkey' => $prvkey, 'alg' => $alg, 'result' => $data ]; + call_hooks('other_unencapsulate',$x); + return $x['result']; + } } diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php index 0b5f085af..81a3bd590 100755 --- a/include/dba/dba_driver.php +++ b/include/dba/dba_driver.php @@ -98,7 +98,7 @@ class DBA { abstract class dba_driver { // legacy behavior - protected $db; + public $db; protected $pdo = array(); public $debug = 0; diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php index e235c467b..f76e6cdd7 100755 --- a/include/dba/dba_pdo.php +++ b/include/dba/dba_pdo.php @@ -133,7 +133,7 @@ class dba_pdo extends dba_driver { } function unescapebin($str) { - if($this->driver_dbtype === 'pgsql') { + if($this->driver_dbtype === 'pgsql' && (! is_null($str))) { $x = ''; while(! feof($str)) { $x .= fread($str,8192); diff --git a/include/dir_fns.php b/include/dir_fns.php index 03cc2706a..3922730fc 100644 --- a/include/dir_fns.php +++ b/include/dir_fns.php @@ -192,17 +192,19 @@ function sync_directories($dirmode) { 'site_update' => NULL_DATE, 'site_directory' => DIRECTORY_FALLBACK_MASTER . '/dirsearch', 'site_realm' => DIRECTORY_REALM, - 'site_valid' => 1 + 'site_valid' => 1, + 'site_crypto' => 'aes256cbc' ); - $x = q("insert into site ( site_url, site_flags, site_update, site_directory, site_realm, site_valid ) - values ( '%s', %d, '%s', '%s', '%s', %d ) ", + $x = q("insert into site ( site_url, site_flags, site_update, site_directory, site_realm, site_valid, site_crypto ) + values ( '%s', %d, '%s', '%s', '%s', %d, '%s' ) ", dbesc($r[0]['site_url']), intval($r[0]['site_flags']), dbesc($r[0]['site_update']), dbesc($r[0]['site_directory']), dbesc($r[0]['site_realm']), - intval($r[0]['site_valid']) + intval($r[0]['site_valid']), + dbesc($r[0]['site_crypto']) ); $r = q("select * from site where site_flags in (%d, %d) and site_url != '%s' and site_type = %d ", diff --git a/include/help.php b/include/help.php index f7fffc4d4..03d01d1a1 100644 --- a/include/help.php +++ b/include/help.php @@ -15,7 +15,7 @@ function get_help_content($tocpath = false) { $text = ''; $path = (($tocpath !== false) ? $tocpath : ''); - + if($tocpath === false && argc() > 1) { $path = ''; for($x = 1; $x < argc(); $x ++) { @@ -55,6 +55,7 @@ function get_help_content($tocpath = false) { if(! $text) { $doctype = 'bbcode'; $text = load_doc_file('doc/main.bb'); + goaway('/help/about/about_hubzilla'); \App::$page['title'] = t('Help'); } @@ -68,7 +69,7 @@ function get_help_content($tocpath = false) { } if($doctype === 'html') - $content = $text; + $content = parseIdentityAwareHTML($text); if($doctype === 'markdown') { require_once('library/markdown.php'); # escape #include tags diff --git a/include/items.php b/include/items.php index 4ac4d6049..3bbd4cce3 100755 --- a/include/items.php +++ b/include/items.php @@ -1463,6 +1463,11 @@ function item_store($arr, $allow_exec = false, $deliver = true) { $ret = array('success' => false, 'item_id' => 0); + if(array_key_exists('cancel',$arr) && $arr['cancel']) { + logger('cancelled by plugin'); + return $ret; + } + if(! $arr['uid']) { logger('item_store: no uid'); $ret['message'] = 'No uid.'; @@ -1808,6 +1813,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) { $x = q("update item set parent = id where id = %d", intval($r[0]['id']) ); + $arr['parent'] = $r[0]['id']; } @@ -1881,6 +1887,12 @@ function item_store_update($arr,$allow_exec = false, $deliver = true) { $allow_exec = $d['allow_exec']; $ret = array('success' => false, 'item_id' => 0); + + if(array_key_exists('cancel',$arr) && $arr['cancel']) { + logger('cancelled by plugin'); + return $ret; + } + if(! intval($arr['uid'])) { logger('item_store_update: no uid'); $ret['message'] = 'no uid.'; @@ -3968,8 +3980,8 @@ function items_fetch($arr,$channel = null,$observer_hash = null,$client_mode = C $sql_nets .= "( abook.abook_closeness >= " . intval($arr['cmin']) . " "; $sql_nets .= " AND abook.abook_closeness <= " . intval($arr['cmax']) . " ) "; - /** @fixme dead code, $cmax is undefined */ - if ($cmax == 99) + + if ($arr['cmax'] == 99) $sql_nets .= " OR abook.abook_closeness IS NULL ) "; } } @@ -4104,25 +4116,21 @@ function webpage_to_namespace($webpage) { function update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid) { - $page_type = ''; - if(! $post_id) return; - if($webpage == ITEM_TYPE_WEBPAGE) - $page_type = 'WEBPAGE'; - elseif($webpage == ITEM_TYPE_BLOCK) - $page_type = 'BUILDBLOCK'; - elseif($webpage == ITEM_TYPE_PDL) - $page_type = 'PDL'; - elseif($webpage == ITEM_TYPE_DOC) - $page_type = 'docfile'; - elseif($namespace && $remote_id) { + $page_type = webpage_to_namespace($webpage); + + if($page_type == 'unknown' && $namespace && $remote_id) { $page_type = $namespace; $pagetitle = $remote_id; } + else { + $page_type = ''; + } if($page_type) { + // store page info as an alternate message_id so we can access it via // https://sitename/page/$channelname/$pagetitle // if no pagetitle was given or it couldn't be transliterated into a url, use the first diff --git a/include/nav.php b/include/nav.php index c2a058457..2762e2a14 100644 --- a/include/nav.php +++ b/include/nav.php @@ -108,7 +108,7 @@ EOT; if(feature_enabled($channel['channel_id'],'webpages') && (! $basic)) $nav['usermenu'][] = Array('webpages/' . $channel['channel_address'],t('Webpages'),"",t('Your webpages'),'webpages_nav_btn'); if(feature_enabled($channel['channel_id'],'wiki') && (! $basic)) - $nav['usermenu'][] = Array('wiki/' . $channel['channel_address'],t('Wiki'),"",t('Your wiki'),'wiki_nav_btn'); + $nav['usermenu'][] = Array('wiki/' . $channel['channel_address'],t('Wikis'),"",t('Your wikis'),'wiki_nav_btn'); } else { if(! get_account_id()) { @@ -127,26 +127,24 @@ EOT; ); } - if($observer) { - $nav['lock'] = array('logout','','lock', - sprintf( t('%s - click to logout'), $observer['xchan_addr'])); - } elseif(! $_SESSION['authenticated']) { $nav['loginmenu'][] = Array('rmagic',t('Remote authentication'),'',t('Click to authenticate to your home hub'),'rmagic_nav_btn'); } - /** - * "Home" should also take you home from an authenticated remote profile connection - */ - $homelink = get_my_url(); if(! $homelink) { $observer = App::get_observer(); $homelink = (($observer) ? $observer['xchan_url'] : ''); } - if(! local_channel()) - $nav['home'] = array($homelink, t('Home'), "", t('Home Page'),'home_nav_btn'); + if(! local_channel()) { + $nav['rusermenu'] = array( + $homelink, + t('Get me home'), + 'logout', + t('Log me out of this site') + ); + } if(((get_config('system','register_policy') == REGISTER_OPEN) || (get_config('system','register_policy') == REGISTER_APPROVE)) && (! $_SESSION['authenticated'])) $nav['register'] = array('register',t('Register'), "", t('Create an account'),'register_nav_btn'); diff --git a/include/oembed.php b/include/oembed.php index 52fb04058..eb7b76437 100755 --- a/include/oembed.php +++ b/include/oembed.php @@ -338,7 +338,7 @@ function oembed_iframe($src,$width,$height) { // Make sure any children are sandboxed within their own iframe. - return '<iframe ' . $scroll . 'height="' . $height . '" width="' . $width . '" src="' . $s . '" frameborder="no" >' + return '<iframe ' . $scroll . 'height="' . $height . '" width="' . $width . '" src="' . $s . '" allowfullscreen frameborder="no" >' . t('Embedded content') . '</iframe>'; } diff --git a/include/queue_fn.php b/include/queue_fn.php index 1e3126f77..0950faf85 100644 --- a/include/queue_fn.php +++ b/include/queue_fn.php @@ -93,7 +93,7 @@ function queue_deliver($outq, $immediate = false) { // your site has existed. Since we don't know for sure what these sites are, // call them unknown - q("insert into site (site_url, site_update, site_dead, site_type) values ('%s','%s',0,%d) ", + q("insert into site (site_url, site_update, site_dead, site_type, site_crypto) values ('%s','%s',0,%d,'') ", dbesc($base), dbesc(datetime_convert()), intval(($outq['outq_driver'] === 'post') ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN) diff --git a/include/taxonomy.php b/include/taxonomy.php index 067bd3246..0b4b2aa9a 100644 --- a/include/taxonomy.php +++ b/include/taxonomy.php @@ -386,7 +386,7 @@ function get_things($profile_hash,$uid) { $things[$k] = null; foreach($r as $rr) { - $l = q("select xchan_name, xchan_photo_s, xchan_url from likes left join xchan on likee = xchan_hash where + $l = q("select xchan_name, xchan_photo_s, xchan_url from likes left join xchan on liker = xchan_hash where target_type = '%s' and target_id = '%s' and channel_id = %d", dbesc(ACTIVITY_OBJ_THING), dbesc($rr['obj_obj']), diff --git a/include/text.php b/include/text.php index 12b37222b..b25eb8e46 100644 --- a/include/text.php +++ b/include/text.php @@ -2049,7 +2049,7 @@ function ids_to_array($arr,$idx = 'id') { $t = array(); if($arr) { foreach($arr as $x) { - if(array_key_exists($idx,$x) && strlen($x[$idx]) && (! in_array($x[$idx],$t))) { + if(array_key_exists($idx,$x) && strlen($x[$idx]) && (! in_array($x[$idx],$t))) { $t[] = $x[$idx]; } } @@ -2060,12 +2060,15 @@ function ids_to_array($arr,$idx = 'id') { -function ids_to_querystr($arr,$idx = 'id') { +function ids_to_querystr($arr,$idx = 'id',$quote = false) { $t = array(); if($arr) { foreach($arr as $x) { if(! in_array($x[$idx],$t)) { - $t[] = $x[$idx]; + if($quote) + $t[] = "'" . dbesc($x[$idx]) . "'"; + else + $t[] = $x[$idx]; } } } diff --git a/include/widgets.php b/include/widgets.php index 3dc555b46..b6d3fb7ae 100644 --- a/include/widgets.php +++ b/include/widgets.php @@ -956,7 +956,7 @@ function widget_wiki_list($arr) { } } if ($wikis) { - return replace_macros(get_markup_template('wikilist.tpl'), array( + return replace_macros(get_markup_template('wikilist_widget.tpl'), array( '$header' => t('Wiki List'), '$channel' => $channel['channel_address'], '$wikis' => $wikis['wikis'], @@ -967,7 +967,7 @@ function widget_wiki_list($arr) { '$view' => t('View'), '$addnew' => t('Create new wiki'), '$create' => t('Create'), - '$wikiName' => array('wikiName', t('Wiki name'), '', ''), + '$wikiName' => array('wikiName', t('Wiki name')), '$lockstate' => $x['lockstate'], '$acl' => $x['acl'], '$allow_cid' => $x['allow_cid'], @@ -975,7 +975,7 @@ function widget_wiki_list($arr) { '$deny_cid' => $x['deny_cid'], '$deny_gid' => $x['deny_gid'], '$bang' => $x['bang'], - '$notify' => t('Send notification') + '$notify' => array('postVisible', t('Send notification'), '', '', array(t('No'), t('Yes'))) )); } return ''; @@ -1017,6 +1017,7 @@ function widget_wiki_pages($arr) { '$pages' => $pages, '$canadd' => $can_create, '$addnew' => t('Add new page'), + '$pageName' => array('pageName', t('Page name')), )); } @@ -1472,14 +1473,23 @@ function widget_forums($arr) { $perms_sql = item_permissions_sql(local_channel()) . item_normal(); - /** - * We used to try and find public forums with custom permissions by checking to see if - * send_stream was false and tag_deliver was true. However with the newer extensible - * permissions infrastructure this makes for a very complicated query. Now we're only - * checking channels that report themselves specifically as pubforums - */ + $xf = false; + + $x1 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'send_stream' and v = 0", + intval(local_channel()) + ); + if($x1) { + $xc = ids_to_querystr($x1,'xchan',true); + $x2 = q("select xchan from abconfig where chan = %d and cat = 'their_perms' and k = 'tag_deliver' and v = 1 and xchan in (" . $xc . ") ", + intval(local_channel()) + ); + if($x2) + $xf = ids_to_querystr($x2,'xchan',true); + } + + $sql_extra = (($xf) ? " and ( xchan_hash in (" . $xf . ") or xchan_pubforum = 1 ) " : " and xchan_pubforum = 1 "); - $r1 = q("select abook_id, xchan_hash, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_pubforum = 1 and xchan_deleted = 0 and abook_channel = %d order by xchan_name $limit ", + $r1 = q("select abook_id, xchan_hash, xchan_name, xchan_url, xchan_photo_s from abook left join xchan on abook_xchan = xchan_hash where xchan_deleted = 0 and abook_channel = %d $sql_extra order by xchan_name $limit ", intval(local_channel()) ); if(! $r1) diff --git a/include/wiki.php b/include/wiki.php index bcdf9d7d8..542d617b9 100644 --- a/include/wiki.php +++ b/include/wiki.php @@ -19,6 +19,7 @@ function wiki_list($channel, $observer_hash) { $w['htmlName'] = get_iconfig($w, 'wiki', 'htmlName'); $w['urlName'] = get_iconfig($w, 'wiki', 'urlName'); $w['path'] = get_iconfig($w, 'wiki', 'path'); + $w['mimeType'] = get_iconfig($w, 'wiki', 'mimeType'); } } // TODO: query db for wikis the observer can access. Return with two lists, for read and write access @@ -31,14 +32,30 @@ function wiki_page_list($resource_id) { if (!$w['path']) { return array('pages' => null, 'wiki' => null); } - $pages = array(); + + $pages[] = [ + 'resource_id' => '', + 'title' => 'Home', + 'url' => 'Home', + 'link_id' => 'id_wiki_home_0' + ]; + if (is_dir($w['path']) === true) { $files = array_diff(scandir($w['path']), array('.', '..', '.git')); // TODO: Check that the files are all text files - + $i = 1; foreach($files as $file) { - // strip the .md file extension and unwrap URL encoding to leave HTML encoded name - $pages[] = array('title' => urldecode(substr($file, 0, -3)), 'url' => urlencode(substr($file, 0, -3))); + // strip the file extension and unwrap URL encoding to leave HTML encoded name + $title = substr($file, 0, -3); + if(urldecode($title) !== 'Home') { + $pages[] = [ + 'resource_id' => $resource_id, + 'title' => urldecode($title), + 'url' => $title, + 'link_id' => 'id_' . substr($resource_id, 0, 10) . '_' . $i + ]; + $i++; + } } } @@ -75,7 +92,7 @@ function wiki_create_wiki($channel, $observer_hash, $wiki, $acl) { $resource_id = random_string(); $r = q("SELECT mid FROM item WHERE resource_id = '%s' AND resource_type = '%s' AND uid = %d LIMIT 1", dbesc($resource_id), - dbesc(WIKI_ITEM_RESOURCE_TYPE), + dbesc(WIKI_ITEM_RESOURCE_TYPE), intval($channel['channel_id']) ); if (count($r)) @@ -123,6 +140,9 @@ function wiki_create_wiki($channel, $observer_hash, $wiki, $acl) { if (!set_iconfig($arr, 'wiki', 'urlName', $wiki['urlName'], true)) { return array('item' => null, 'success' => false); } + if (!set_iconfig($arr, 'wiki', 'mimeType', $wiki['mimeType'], true)) { + return array('item' => null, 'success' => false); + } $post = item_store($arr); $item_id = $post['item_id']; @@ -152,8 +172,8 @@ function wiki_delete_wiki($resource_id) { function wiki_get_wiki($resource_id) { $item = q("SELECT * FROM item WHERE resource_type = '%s' AND resource_id = '%s' AND item_deleted = 0 limit 1", - dbesc(WIKI_ITEM_RESOURCE_TYPE), - dbesc($resource_id) + dbesc(WIKI_ITEM_RESOURCE_TYPE), + dbesc($resource_id) ); if (!$item) { return array('wiki' => null, 'path' => null); @@ -163,17 +183,21 @@ function wiki_get_wiki($resource_id) { $rawName = get_iconfig($w, 'wiki', 'rawName'); $htmlName = get_iconfig($w, 'wiki', 'htmlName'); $urlName = get_iconfig($w, 'wiki', 'urlName'); + $mimeType = get_iconfig($w, 'wiki', 'mimeType'); + $path = get_iconfig($w, 'wiki', 'path'); if (!realpath(__DIR__ . '/../' . $path)) { return array('wiki' => null, 'path' => null); } // Path to wiki exists $abs_path = realpath(__DIR__ . '/../' . $path); - return array( 'wiki' => $w, - 'path' => $abs_path, - 'rawName' => $rawName, - 'htmlName' => $htmlName, - 'urlName' => $urlName + return array( + 'wiki' => $w, + 'path' => $abs_path, + 'rawName' => $rawName, + 'htmlName' => $htmlName, + 'urlName' => $urlName, + 'mimeType' => $mimeType ); } } @@ -220,7 +244,8 @@ function wiki_create_page($name, $resource_id) { if (!$w['path']) { return array('page' => null, 'wiki' => null, 'message' => 'Wiki not found.', 'success' => false); } - $page = array('rawName' => $name, 'htmlName' => escape_tags($name), 'urlName' => urlencode(escape_tags($name)), 'fileName' => urlencode(escape_tags($name)).'.md'); + + $page = array('rawName' => $name, 'htmlName' => escape_tags($name), 'urlName' => urlencode(escape_tags($name)), 'fileName' => urlencode(escape_tags($name)) . wiki_get_file_ext($w)); $page_path = $w['path'] . '/' . $page['fileName']; if (is_file($page_path)) { return array('page' => null, 'wiki' => null, 'message' => 'Page already exists.', 'success' => false); @@ -242,11 +267,11 @@ function wiki_rename_page($arr) { if (!$w['path']) { return array('message' => 'Wiki not found.', 'success' => false); } - $page_path_old = $w['path'].'/'.$pageUrlName.'.md'; + $page_path_old = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w); if (!is_readable($page_path_old) === true) { return array('message' => 'Cannot read wiki page: ' . $page_path_old, 'success' => false); } - $page = array('rawName' => $pageNewName, 'htmlName' => escape_tags($pageNewName), 'urlName' => urlencode(escape_tags($pageNewName)), 'fileName' => urlencode(escape_tags($pageNewName)).'.md'); + $page = array('rawName' => $pageNewName, 'htmlName' => escape_tags($pageNewName), 'urlName' => urlencode(escape_tags($pageNewName)), 'fileName' => urlencode(escape_tags($pageNewName)) . wiki_get_file_ext($w)); $page_path_new = $w['path'] . '/' . $page['fileName'] ; if (is_file($page_path_new)) { return array('message' => 'Page already exists.', 'success' => false); @@ -267,7 +292,7 @@ function wiki_get_page_content($arr) { if (!$w['path']) { return array('content' => null, 'message' => 'Error reading wiki', 'success' => false); } - $page_path = $w['path'].'/'.$pageUrlName.'.md'; + $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w); if (is_readable($page_path) === true) { if(filesize($page_path) === 0) { $content = ''; @@ -278,7 +303,7 @@ function wiki_get_page_content($arr) { } } // TODO: Check that the files are all text files - return array('content' => json_encode($content), 'message' => '', 'success' => true); + return array('content' => json_encode($content), 'mimeType' => $w['mimeType'], 'message' => '', 'success' => true); } } @@ -289,7 +314,7 @@ function wiki_page_history($arr) { if (!$w['path']) { return array('history' => null, 'message' => 'Error reading wiki', 'success' => false); } - $page_path = $w['path'].'/'.$pageUrlName.'.md'; + $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w); if (!is_readable($page_path) === true) { return array('history' => null, 'message' => 'Cannot read wiki page: ' . $page_path, 'success' => false); } @@ -314,12 +339,14 @@ function wiki_save_page($arr) { if (!$w['path']) { return array('message' => 'Error reading wiki', 'success' => false); } - $page_path = $w['path'].'/'.$pageUrlName.'.md'; + + $fileName = $pageUrlName . wiki_get_file_ext($w); + $page_path = $w['path'] . '/' . $fileName; if (is_writable($page_path) === true) { if(!file_put_contents($page_path, $content)) { return array('message' => 'Error writing to page file', 'success' => false); } - return array('message' => '', 'success' => true); + return array('message' => '', 'filename' => $filename, 'success' => true); } else { return array('message' => 'Page file not writable', 'success' => false); } @@ -332,7 +359,7 @@ function wiki_delete_page($arr) { if (!$w['path']) { return array('message' => 'Error reading wiki', 'success' => false); } - $page_path = $w['path'].'/'.$pageUrlName.'.md'; + $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w); if (is_writable($page_path) === true) { if(!unlink($page_path)) { return array('message' => 'Error deleting page file', 'success' => false); @@ -354,7 +381,7 @@ function wiki_revert_page($arr) { if (!$w['path']) { return array('content' => $content, 'message' => 'Error reading wiki', 'success' => false); } - $page_path = $w['path'].'/'.$pageUrlName.'.md'; + $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w); if (is_writable($page_path) === true) { $reponame = ((array_key_exists('title', $w['wiki'])) ? urlencode($w['wiki']['title']) : 'repo'); @@ -366,7 +393,7 @@ function wiki_revert_page($arr) { try { $git->setIdentity($observer['xchan_name'], $observer['xchan_addr']); foreach ($git->git->tree($commitHash) as $object) { - if ($object['type'] == 'blob' && $object['file'] === $pageUrlName.'.md' ) { + if ($object['type'] == 'blob' && $object['file'] === $pageUrlName . wiki_get_file_ext($w)) { $content = $git->git->cat->blob($object['hash']); } } @@ -391,7 +418,7 @@ function wiki_compare_page($arr) { if (!$w['path']) { return array('message' => 'Error reading wiki', 'success' => false); } - $page_path = $w['path'].'/'.$pageUrlName.'.md'; + $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w); if (is_readable($page_path) === true) { $reponame = ((array_key_exists('title', $w['wiki'])) ? urlencode($w['wiki']['title']) : 'repo'); if($reponame === '') { @@ -401,12 +428,12 @@ function wiki_compare_page($arr) { $compareContent = $currentContent = ''; try { foreach ($git->git->tree($currentCommit) as $object) { - if ($object['type'] == 'blob' && $object['file'] === $pageUrlName.'.md' ) { + if ($object['type'] == 'blob' && $object['file'] === $pageUrlName . wiki_get_file_ext($w)) { $currentContent = $git->git->cat->blob($object['hash']); } } foreach ($git->git->tree($compareCommit) as $object) { - if ($object['type'] == 'blob' && $object['file'] === $pageUrlName.'.md' ) { + if ($object['type'] == 'blob' && $object['file'] === $pageUrlName . wiki_get_file_ext($w)) { $compareContent = $git->git->cat->blob($object['hash']); } } @@ -469,15 +496,6 @@ function wiki_git_commit($arr) { } } -function wiki_generate_page_filename($name) { - $file = urlencode(escape_tags($name)); - if( $file === '') { - return null; - } else { - return $file . '.md'; - } -} - function wiki_convert_links($s, $wikiURL) { if (strpos($s,'[[') !== false) { @@ -505,7 +523,6 @@ function wiki_convert_links($s, $wikiURL) { * @return string */ function wiki_generate_toc($s) { - if (strpos($s,'[toc]') !== false) { //$toc_md = wiki_toc($s); // Generate Markdown-formatted list prior to HTML render $toc_md = '<ul id="wiki-toc"></ul>'; // use the available jQuery plugin http://ndabas.github.io/toc/ @@ -547,6 +564,13 @@ function wiki_bbcode($s) { return $s; } +function wiki_get_file_ext($arr) { + if($arr['mimeType'] == 'text/bbcode') + return '.bb'; + else + return '.md'; +} + // This function is derived from // http://stackoverflow.com/questions/32068537/generate-table-of-contents-from-markdown-in-php function wiki_toc($content) { diff --git a/include/zot.php b/include/zot.php index 5c9fb4e82..c80081cc8 100644 --- a/include/zot.php +++ b/include/zot.php @@ -110,20 +110,21 @@ function zot_get_hublocs($hash) { * @param string $extra * @returns string json encoded zot packet */ -function zot_build_packet($channel, $type = 'notify', $recipients = null, $remote_key = null, $secret = null, $extra = null) { +function zot_build_packet($channel, $type = 'notify', $recipients = null, $remote_key = null, $methods = '', $secret = null, $extra = null) { - $data = array( + $data = [ 'type' => $type, - 'sender' => array( + 'sender' => [ 'guid' => $channel['channel_guid'], 'guid_sig' => base64url_encode(rsa_sign($channel['channel_guid'],$channel['channel_prvkey'])), 'url' => z_root(), 'url_sig' => base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey'])), 'sitekey' => get_config('system','pubkey') - ), + ], 'callback' => '/post', - 'version' => ZOT_REVISION - ); + 'version' => ZOT_REVISION, + 'encryption' => crypto_methods() + ]; if ($recipients) { for ($x = 0; $x < count($recipients); $x ++) @@ -146,122 +147,67 @@ function zot_build_packet($channel, $type = 'notify', $recipients = null, $remot // Hush-hush ultra top-secret mode - if ($remote_key) { - $data = crypto_encapsulate(json_encode($data),$remote_key); + if($remote_key) { + $algorithm = zot_best_algorithm($methods); + $data = crypto_encapsulate(json_encode($data),$remote_key, $algorithm); } return json_encode($data); } /** - * @brief - * - * @see z_post_url() - * - * @param string $url - * @param array $data - * @return array see z_post_url() for returned data format - */ -function zot_zot($url, $data) { - return z_post_url($url, array('data' => $data)); -} - -/** - * @brief Look up information about channel. - * - * @param string $webbie - * does not have to be host qualified e.g. 'foo' is treated as 'foo\@thishub' - * @param array $channel - * (optional), if supplied permissions will be enumerated specifically for $channel - * @param boolean $autofallback - * fallback/failover to http if https connection cannot be established. Default is true. - * - * @return array see z_post_url() and \ref Zotlabs::Zot::Finger "\\Zotlabs\\Zot\\Finger" + * @brief choose best encryption function from those available on both sites + * + * @param string $methods + * comma separated list of encryption methods + * @return string first match from our site method preferences crypto_methods() array + * of a method which is common to both sites; or 'aes256cbc' if no matches are found. */ -function zot_finger($webbie, $channel = null, $autofallback = true) { - - if (strpos($webbie,'@') === false) { - $address = $webbie; - $host = App::get_hostname(); - } else { - $address = substr($webbie,0,strpos($webbie,'@')); - $host = substr($webbie,strpos($webbie,'@')+1); - if(strpos($host,'/')) - $host = substr($host,0,strpos($host,'/')); - } - - $xchan_addr = $address . '@' . $host; - if ((! $address) || (! $xchan_addr)) { - logger('zot_finger: no address :' . $webbie); - return array('success' => false); - } - logger('using xchan_addr: ' . $xchan_addr, LOGGER_DATA, LOG_DEBUG); +function zot_best_algorithm($methods) { - // potential issue here; the xchan_addr points to the primary hub. - // The webbie we were called with may not, so it might not be found - // unless we query for hubloc_addr instead of xchan_addr + if(\Zotlabs\Lib\System::get_server_role() !== 'pro') + return 'aes256cbc'; - $r = q("select xchan.*, hubloc.* from xchan - left join hubloc on xchan_hash = hubloc_hash - where xchan_addr = '%s' and hubloc_primary = 1 limit 1", - dbesc($xchan_addr) - ); - - if ($r) { - $url = $r[0]['hubloc_url']; - - if ($r[0]['hubloc_network'] && $r[0]['hubloc_network'] !== 'zot') { - logger('zot_finger: alternate network: ' . $webbie); - logger('url: '.$url.', net: '.var_export($r[0]['hubloc_network'],true), LOGGER_DATA, LOG_DEBUG); - return array('success' => false); + if($methods) { + $x = explode(',',$methods); + if($x) { + $y = crypto_methods(); + if($y) { + foreach($y as $yv) { + $yv = trim($yv); + if(in_array($yv,$x)) { + return($yv); + } + } + } } - } else { - $url = 'https://' . $host; } - $rhs = '/.well-known/zot-info'; - $https = ((strpos($url,'https://') === 0) ? true : false); - - logger('zot_finger: ' . $address . ' at ' . $url, LOGGER_DEBUG); - - if ($channel) { - $postvars = array( - 'address' => $address, - 'target' => $channel['channel_guid'], - 'target_sig' => $channel['channel_guid_sig'], - 'key' => $channel['channel_pubkey'] - ); - - $result = z_post_url($url . $rhs,$postvars); - - if ((! $result['success']) && ($autofallback)) { - if ($https) { - logger('zot_finger: https failed. falling back to http'); - $result = z_post_url('http://' . $host . $rhs,$postvars); - } - } - } else { - $rhs .= '?f=&address=' . urlencode($address); + return 'aes256cbc'; +} - $result = z_fetch_url($url . $rhs); - if ((! $result['success']) && ($autofallback)) { - if ($https) { - logger('zot_finger: https failed. falling back to http'); - $result = z_fetch_url('http://' . $host . $rhs); - } - } - } - if (! $result['success']) - logger('zot_finger: no results'); - return $result; +/** + * @brief + * + * @see z_post_url() + * + * @param string $url + * @param array $data + * @return array see z_post_url() for returned data format + */ +function zot_zot($url, $data) { + return z_post_url($url, array('data' => $data)); } /** * @brief Refreshes after permission changed or friending, etc. * + * The top half of this function is similar to \Zotlabs\Zot\Finger::run() and could potentially be + * consolidated. + * * zot_refresh is typically invoked when somebody has changed permissions of a channel and they are notified * to fetch new permissions via a finger/discovery operation. This may result in a new connection * (abook entry) being added to a local channel and it may result in auto-permissions being granted. @@ -283,6 +229,7 @@ function zot_finger($webbie, $channel = null, $autofallback = true) { * * @returns boolean true if successful, else false */ + function zot_refresh($them, $channel = null, $force = false) { if (array_key_exists('xchan_network', $them) && ($them['xchan_network'] !== 'zot')) { @@ -298,7 +245,8 @@ function zot_refresh($them, $channel = null, $force = false) { if ($them['hubloc_url']) { $url = $them['hubloc_url']; - } else { + } + else { $r = null; // if they re-installed the server we could end up with the wrong record - pointing to the old install. @@ -334,7 +282,7 @@ function zot_refresh($them, $channel = null, $force = false) { $token = random_string(); - $postvars = array(); + $postvars = []; $postvars['token'] = $token; @@ -395,10 +343,13 @@ function zot_refresh($them, $channel = null, $force = false) { if($channel) { if($j['permissions']['data']) { - $permissions = crypto_unencapsulate(array( + $permissions = crypto_unencapsulate( + [ 'data' => $j['permissions']['data'], 'key' => $j['permissions']['key'], - 'iv' => $j['permissions']['iv']), + 'iv' => $j['permissions']['iv'], + 'alg' => $j['permissions']['alg'] + ], $channel['channel_prvkey']); if($permissions) $permissions = json_decode($permissions,true); @@ -424,6 +375,10 @@ function zot_refresh($them, $channel = null, $force = false) { $next_birthday = NULL_DATE; } + + // Keep original perms to check if we need to notify them + $previous_perms = get_all_perms($channel['channel_id'],$x['hash']); + $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", dbesc($x['hash']), intval($channel['channel_id']) @@ -487,10 +442,6 @@ function zot_refresh($them, $channel = null, $force = false) { } } - // Keep original perms to check if we need to notify them - $previous_perms = get_all_perms($channel['channel_id'],$x['hash']); - - $closeness = get_pconfig($channel['channel_id'],'system','new_abook_closeness'); if($closeness === false) $closeness = 80; @@ -520,12 +471,14 @@ function zot_refresh($them, $channel = null, $force = false) { if($new_connection) { if(! \Zotlabs\Access\Permissions::PermsCompare($new_perms,$previous_perms)) Zotlabs\Daemon\Master::Summon(array('Notifier','permission_create',$new_connection[0]['abook_id'])); - Zotlabs\Lib\Enotify::submit(array( + Zotlabs\Lib\Enotify::submit( + [ 'type' => NOTIFY_INTRO, 'from_xchan' => $x['hash'], 'to_xchan' => $channel['channel_hash'], - 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'], - )); + 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'] + ] + ); if(intval($permissions['view_stream'])) { if(intval(get_pconfig($channel['channel_id'],'perm_limits','send_stream') & PERMS_PENDING) @@ -535,6 +488,7 @@ function zot_refresh($them, $channel = null, $force = false) { /** If there is a default group for this channel, add this connection to it */ + $default_group = $channel['channel_default_group']; if($default_group) { require_once('include/group.php'); @@ -580,6 +534,7 @@ function zot_refresh($them, $channel = null, $force = false) { * @returns array|null null if site is blacklisted or not found, otherwise an * array with an hubloc record */ + function zot_gethub($arr, $multiple = false) { if($arr['guid'] && $arr['guid_sig'] && $arr['url'] && $arr['url_sig']) { @@ -592,7 +547,7 @@ function zot_gethub($arr, $multiple = false) { $limit = (($multiple) ? '' : ' limit 1 '); $sitekey = ((array_key_exists('sitekey',$arr) && $arr['sitekey']) ? " and hubloc_sitekey = '" . protect_sprintf($arr['sitekey']) . "' " : ''); - $r = q("select * from hubloc + $r = q("select hubloc.*, site.site_crypto from hubloc left join site on hubloc_url = site_url where hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_url = '%s' and hubloc_url_sig = '%s' $sitekey $limit", @@ -629,9 +584,10 @@ function zot_gethub($arr, $multiple = false) { * * \b success boolean true or false * * \b message (optional) error string only if success is false */ + function zot_register_hub($arr) { - $result = array('success' => false); + $result = [ 'success' => false ]; if($arr['url'] && $arr['url_sig'] && $arr['guid'] && $arr['guid_sig']) { @@ -690,6 +646,7 @@ function zot_register_hub($arr) { * * \e boolean \b success boolean true or false * * \e string \b message (optional) error string only if success is false */ + function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { call_hooks('import_xchan', $arr); @@ -788,7 +745,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { $what .= 'xchan '; $changed = true; } - } else { + } + else { $import_photos = true; if((($arr['site']['directory_mode'] === 'standalone') @@ -824,7 +782,7 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { $changed = true; } - if ($import_photos) { + if($import_photos) { require_once('include/photo/photo_driver.php'); @@ -833,9 +791,9 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { $local = q("select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1", dbesc($xchan_hash) ); - if ($local) { + if($local) { $ph = z_fetch_url($arr['photo'], true); - if ($ph['success']) { + if($ph['success']) { $hash = import_channel_photo($ph['body'], $arr['photo_mimetype'], $local[0]['channel_account_id'], $local[0]['channel_id']); @@ -873,11 +831,12 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { false ); } - } else { + } + else { $photos = import_xchan_photo($arr['photo'], $xchan_hash); } - if ($photos) { - if ($photos[4]) { + if($photos) { + if($photos[4]) { // importing the photo failed somehow. Leave the photo_date alone so we can try again at a later date. // This often happens when somebody joins the matrix with a bad cert. $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' @@ -888,7 +847,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { dbesc($photos[3]), dbesc($xchan_hash) ); - } else { + } + else { $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", dbescdate(datetime_convert('UTC','UTC',$arr['photo_updated'])), @@ -945,7 +905,8 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { $what .= 'profile '; $changed = true; } - } else { + } + else { logger('import_xchan: profile not available - hiding'); // they may have made it private $r = q("delete from xprof where xprof_hash = '%s'", @@ -998,16 +959,17 @@ function import_xchan($arr,$ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { * @param array $arr - output of z_post_url() * @param array $outq - The queue structure attached to this request */ + function zot_process_response($hub, $arr, $outq) { - if (! $arr['success']) { + if(! $arr['success']) { logger('zot_process_response: failed: ' . $hub); return; } $x = json_decode($arr['body'], true); - if (! $x) { + if(! $x) { logger('zot_process_response: No json from ' . $hub); logger('zot_process_response: headers: ' . print_r($arr['header'],true), LOGGER_DATA, LOG_DEBUG); } @@ -1065,6 +1027,7 @@ function zot_process_response($hub, $arr, $outq) { * decrypted and json decoded notify packet from remote site * @return array from zot_import() */ + function zot_fetch($arr) { logger('zot_fetch: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); @@ -1082,16 +1045,18 @@ function zot_fetch($arr) { } foreach($ret_hubs as $ret_hub) { - $data = array( - 'type' => 'pickup', - 'url' => z_root(), - 'callback_sig' => base64url_encode(rsa_sign(z_root() . '/post',get_config('system','prvkey'))), - 'callback' => z_root() . '/post', - 'secret' => $arr['secret'], - 'secret_sig' => base64url_encode(rsa_sign($arr['secret'],get_config('system','prvkey'))) - ); - $datatosend = json_encode(crypto_encapsulate(json_encode($data),$ret_hub['hubloc_sitekey'])); + $data = [ + 'type' => 'pickup', + 'url' => z_root(), + 'callback_sig' => base64url_encode(rsa_sign(z_root() . '/post', get_config('system','prvkey'))), + 'callback' => z_root() . '/post', + 'secret' => $arr['secret'], + 'secret_sig' => base64url_encode(rsa_sign($arr['secret'], get_config('system','prvkey'))) + ]; + + $algorithm = zot_best_algorithm($ret_hub['site_crypto']); + $datatosend = json_encode(crypto_encapsulate(json_encode($data),$ret_hub['hubloc_sitekey'], $algorithm)); $fetch = zot_zot($url,$datatosend); @@ -1142,6 +1107,11 @@ function zot_import($arr, $sender_url) { $data = json_decode(crypto_unencapsulate($data,get_config('system','prvkey')),true); } + if(! is_array($data)) { + logger('decode error'); + return array(); + } + if(! $data['success']) { if($data['message']) logger('remote pickup failed: ' . $data['message']); @@ -1167,6 +1137,12 @@ function zot_import($arr, $sender_url) { logger('zot_import: notify: ' . print_r($i['notify'],true), LOGGER_DATA, LOG_DEBUG); + if(! is_array($i['notify'])) { + logger('decode error'); + continue; + } + + $hub = zot_gethub($i['notify']['sender']); if((! $hub) || ($hub['hubloc_url'] != $sender_url)) { logger('zot_import: potential forgery: wrong site for sender: ' . $sender_url . ' != ' . print_r($i['notify'],true)); @@ -1357,6 +1333,7 @@ function zot_import($arr, $sender_url) { * @param array $msg * @return NULL|array */ + function public_recips($msg) { require_once('include/channel.php'); @@ -1566,6 +1543,7 @@ function allowed_public_recips($msg) { * @param boolean $request (optional) default false * @return array */ + function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $request = false) { $result = array(); @@ -1875,6 +1853,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $ * * \e int \b mid * @param int $uid */ + function remove_community_tag($sender, $arr, $uid) { if(! (activity_match($arr['verb'], ACTIVITY_TAG) && ($arr['obj_type'] == ACTIVITY_OBJ_TAGTERM))) @@ -1945,6 +1924,7 @@ function remove_community_tag($sender, $arr, $uid) { * @param array $orig * @param int $uid */ + function update_imported_item($sender, $item, $orig, $uid) { // If this is a comment being updated, remove any privacy information @@ -1985,6 +1965,7 @@ function update_imported_item($sender, $item, $orig, $uid) { * @param boolean $relay * @return boolean|int post_id */ + function delete_imported_item($sender, $item, $uid, $relay) { logger('delete_imported_item invoked', LOGGER_DEBUG); @@ -2002,13 +1983,14 @@ function delete_imported_item($sender, $item, $uid, $relay) { intval($uid) ); - if ($r) { - if ($r[0]['author_xchan'] === $sender['hash'] || $r[0]['owner_xchan'] === $sender['hash'] || $r[0]['source_xchan'] === $sender['hash']) + if($r) { + if($r[0]['author_xchan'] === $sender['hash'] || $r[0]['owner_xchan'] === $sender['hash'] || $r[0]['source_xchan'] === $sender['hash']) $ownership_valid = true; $post_id = $r[0]['id']; $item_found = true; - } else { + } + else { // perhaps the item is still in transit and the delete notification got here before the actual item did. Store it with the deleted flag set. // item_store() won't try to deliver any notifications or start delivery chains if this flag is set. @@ -2017,25 +1999,24 @@ function delete_imported_item($sender, $item, $uid, $relay) { logger('delete received for non-existent item - storing item data.'); - /** @BUG $arr is undefined here, so this is dead code */ - if ($arr['author_xchan'] === $sender['hash'] || $arr['owner_xchan'] === $sender['hash'] || $arr['source_xchan'] === $sender['hash']) { + if($item['author_xchan'] === $sender['hash'] || $item['owner_xchan'] === $sender['hash'] || $item['source_xchan'] === $sender['hash']) { $ownership_valid = true; - $item_result = item_store($arr); + $item_result = item_store($item); $post_id = $item_result['item_id']; } } - if ($ownership_valid === false) { + if($ownership_valid === false) { logger('delete_imported_item: failed: ownership issue'); return false; } require_once('include/items.php'); - if ($item_found) { - if (intval($r[0]['item_deleted'])) { + if($item_found) { + if(intval($r[0]['item_deleted'])) { logger('delete_imported_item: item was already deleted'); - if (! $relay) + if(! $relay) return false; // This is a bit hackish, but may have to suffice until the notification/delivery loop is optimised @@ -2146,6 +2127,7 @@ function process_mail_delivery($sender, $arr, $deliveries) { * * \e string \b hash a xchan_hash * @param array $arr */ + function process_rating_delivery($sender, $arr) { logger('process_rating_delivery: ' . print_r($arr,true)); @@ -2205,6 +2187,7 @@ function process_rating_delivery($sender, $arr) { * @param array $arr * @param array $deliveries (unused) */ + function process_profile_delivery($sender, $arr, $deliveries) { logger('process_profile_delivery', LOGGER_DEBUG); @@ -2301,6 +2284,7 @@ function check_location_move($sender_hash,$locations) { * @param boolean $absolute (optional) default false * @return array */ + function sync_locations($sender, $arr, $absolute = false) { $ret = array(); @@ -2548,7 +2532,7 @@ function zot_encode_locations($channel) { if(intval($channel['channel_removed']) && $hub['hubloc_url'] === z_root()) $hub['hubloc_deleted'] = 1; - $ret[] = array( + $ret[] = [ 'host' => $hub['hubloc_host'], 'address' => $hub['hubloc_addr'], 'primary' => (intval($hub['hubloc_primary']) ? true : false), @@ -2557,7 +2541,7 @@ function zot_encode_locations($channel) { 'callback' => $hub['hubloc_callback'], 'sitekey' => $hub['hubloc_sitekey'], 'deleted' => (intval($hub['hubloc_deleted']) ? true : false) - ); + ]; } } @@ -2574,6 +2558,7 @@ function zot_encode_locations($channel) { * @param number $suppress_update default 0 * @return boolean $updated if something changed */ + function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLAGS_UPDATED, $suppress_update = 0) { logger('import_directory_profile', LOGGER_DEBUG); @@ -2708,6 +2693,7 @@ function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLA * @param string $hash * @param array $keywords */ + function import_directory_keywords($hash, $keywords) { $existing = array(); @@ -2752,6 +2738,7 @@ function import_directory_keywords($hash, $keywords) { * @param string $addr * @param int $flags (optional) default 0 */ + function update_modtime($hash, $guid, $addr, $flags = 0) { $dirmode = intval(get_config('system', 'directory_mode')); @@ -2784,6 +2771,7 @@ function update_modtime($hash, $guid, $addr, $flags = 0) { * @param string $pubkey * @return boolean true if updated or inserted */ + function import_site($arr, $pubkey) { if( (! is_array($arr)) || (! $arr['url']) || (! $arr['url_sig'])) return false; @@ -2851,6 +2839,7 @@ function import_site($arr, $pubkey) { $site_location = htmlspecialchars($arr['location'],ENT_COMPAT,'UTF-8',false); $site_realm = htmlspecialchars($arr['realm'],ENT_COMPAT,'UTF-8',false); $site_project = htmlspecialchars($arr['project'],ENT_COMPAT,'UTF-8',false); + $site_crypto = ((array_key_exists('encryption',$arr) && is_array($arr['encryption'])) ? htmlspecialchars(implode(',',$arr['encryption']),ENT_COMPAT,'UTF-8',false) : ''); $site_version = ((array_key_exists('version',$arr)) ? htmlspecialchars($arr['version'],ENT_COMPAT,'UTF-8',false) : ''); // You can have one and only one primary directory per realm. @@ -2872,6 +2861,7 @@ function import_site($arr, $pubkey) { || ($siterecord['site_register'] != $register_policy) || ($siterecord['site_project'] != $site_project) || ($siterecord['site_realm'] != $site_realm) + || ($siterecord['site_crypto'] != $site_crypto) || ($siterecord['site_version'] != $site_version) ) { $update = true; @@ -2880,7 +2870,7 @@ function import_site($arr, $pubkey) { // logger('import_site: stored: ' . print_r($siterecord,true)); - $r = q("update site set site_dead = 0, site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s', site_type = %d, site_project = '%s', site_version = '%s' + $r = q("update site set site_dead = 0, site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s', site_type = %d, site_project = '%s', site_version = '%s', site_crypto = '%s' where site_url = '%s'", dbesc($site_location), intval($site_directory), @@ -2893,6 +2883,7 @@ function import_site($arr, $pubkey) { intval(SITE_TYPE_ZOT), dbesc($site_project), dbesc($site_version), + dbesc($site_crypto), dbesc($url) ); if(! $r) { @@ -2910,8 +2901,8 @@ function import_site($arr, $pubkey) { else { $update = true; - $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage, site_realm, site_type, site_project, site_version ) - values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s', '%s', %d, '%s', '%s' )", + $r = q("insert into site ( site_location, site_url, site_access, site_flags, site_update, site_directory, site_register, site_sellpage, site_realm, site_type, site_project, site_version, site_crypto ) + values ( '%s', '%s', %d, %d, '%s', '%s', %d, '%s', '%s', %d, '%s', '%s', '%s' )", dbesc($site_location), dbesc($url), intval($access_policy), @@ -2923,7 +2914,8 @@ function import_site($arr, $pubkey) { dbesc($site_realm), intval(SITE_TYPE_ZOT), dbesc($site_project), - dbesc($site_version) + dbesc($site_version), + dbesc($site_crypto) ); if(! $r) { logger('import_site: record create failed. ' . print_r($arr,true)); @@ -2942,6 +2934,7 @@ function import_site($arr, $pubkey) { * @param array $packet (optional) default null * @param boolean $groups_changed (optional) default false */ + function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { if(get_config('system','server_role') === 'basic') @@ -2977,7 +2970,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { if(intval($channel['channel_removed'])) return; - $h = q("select * from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0", + $h = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash = '%s' and hubloc_deleted = 0", dbesc($channel['channel_hash']) ); @@ -3064,7 +3057,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { foreach($synchubs as $hub) { $hash = random_string(); - $n = zot_build_packet($channel,'notify',$env_recips,$hub['hubloc_sitekey'],$hash); + $n = zot_build_packet($channel,'notify',$env_recips,$hub['hubloc_sitekey'],$hub['site_crypto'],$hash); queue_insert(array( 'hash' => $hash, 'account_id' => $channel['channel_account_id'], @@ -3090,6 +3083,7 @@ function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { * @param array $deliveries * @return array */ + function process_channel_sync_delivery($sender, $arr, $deliveries) { if(get_config('system','server_role') === 'basic') @@ -3564,6 +3558,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) { * * \e string \b xchan_url * @return string */ + function get_rpost_path($observer) { if(! $observer) return ''; @@ -3579,6 +3574,7 @@ function get_rpost_path($observer) { * @param array $x * @return boolean|string return false or a hash */ + function import_author_zot($x) { $hash = make_xchan_hash($x['guid'],$x['guid_sig']); @@ -3618,6 +3614,7 @@ function import_author_zot($x) { * @param array $data * @return array */ + function zot_reply_message_request($data) { $ret = array('success' => false); @@ -3654,7 +3651,7 @@ function zot_reply_message_request($data) { if ($messages) { $env_recips = null; - $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_error = 0 and hubloc_deleted = 0", + $r = q("select hubloc.*, site.site_crypto from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and hubloc_error = 0 and hubloc_deleted = 0", dbesc($sender_hash) ); if (! $r) { @@ -3676,7 +3673,7 @@ function zot_reply_message_request($data) { * create a notify packet and drop the actual message packet in the queue for pickup */ - $n = zot_build_packet($c[0],'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash,array('message_id' => $data['message_id'])); + $n = zot_build_packet($c[0],'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hub['site_crypto'],$hash,array('message_id' => $data['message_id'])); queue_insert(array( 'hash' => $hash, @@ -3913,6 +3910,11 @@ function zotinfo($arr) { $permissions['connected'] = true; } + // encrypt this with the default aes256cbc since we cannot be sure at this point which + // algorithms are preferred for communications with the remote site; notably + // because ztarget refers to an xchan and we don't necessarily know the origination + // location. + $ret['permissions'] = (($ztarget && $zkey) ? crypto_encapsulate(json_encode($permissions),$zkey) : $permissions); if($permissions['view_profile']) @@ -3943,6 +3945,8 @@ function zotinfo($arr) { $ret['site']['directory_url'] = z_root() . '/dirsearch'; + $ret['site']['encryption'] = crypto_methods(); + // hide detailed site information if you're off the grid if($dirmode != DIRECTORY_MODE_STANDALONE) { @@ -3980,17 +3984,17 @@ function zotinfo($arr) { $r = q("select * from addon where hidden = 0"); if($r) foreach($r as $rr) - $visible_plugins[] = $rr['name']; + $visible_plugins[] = $rr['aname']; } - $ret['site']['plugins'] = $visible_plugins; - $ret['site']['sitehash'] = get_config('system','location_hash'); - $ret['site']['sitename'] = get_config('system','sitename'); - $ret['site']['sellpage'] = get_config('system','sellpage'); - $ret['site']['location'] = get_config('system','site_location'); - $ret['site']['realm'] = get_directory_realm(); - $ret['site']['project'] = Zotlabs\Lib\System::get_platform_name() . ' ' . Zotlabs\Lib\System::get_server_role(); - $ret['site']['version'] = Zotlabs\Lib\System::get_project_version(); + $ret['site']['plugins'] = $visible_plugins; + $ret['site']['sitehash'] = get_config('system','location_hash'); + $ret['site']['sitename'] = get_config('system','sitename'); + $ret['site']['sellpage'] = get_config('system','sellpage'); + $ret['site']['location'] = get_config('system','site_location'); + $ret['site']['realm'] = get_directory_realm(); + $ret['site']['project'] = Zotlabs\Lib\System::get_platform_name() . ' ' . Zotlabs\Lib\System::get_server_role(); + $ret['site']['version'] = Zotlabs\Lib\System::get_project_version(); } @@ -4175,7 +4179,7 @@ function update_hub_connected($hub,$sitekey = '') { dbesc($sitekey) ); if(intval($hub['hubloc_orphancheck'])) { - q("update hubloc set hubloc_orhpancheck = 0 where hubloc_id = %d and hubloc_sitekey = '%s' ", + q("update hubloc set hubloc_orphancheck = 0 where hubloc_id = %d and hubloc_sitekey = '%s' ", intval($hub['hubloc_id']), dbesc($sitekey) ); @@ -4317,7 +4321,15 @@ function zot_reply_pickup($data) { } } - $encrypted = crypto_encapsulate(json_encode($ret),$sitekey); + // this is a bit of a hack because we don't have the hubloc_url here, only the callback url. + // worst case is we'll end up using aes256cbc if they've got a different post endpoint + + $x = q("select site_crypto from site where site_url = '%s' limit 1", + dbesc(str_replace('/post','',$data['callback'])) + ); + $algorithm = zot_best_algorithm(($x) ? $x[0]['site_crypto'] : ''); + + $encrypted = crypto_encapsulate(json_encode($ret),$sitekey,$algorithm); json_return_and_die($encrypted); /* pickup: end */ |