diff options
-rw-r--r-- | Zotlabs/Daemon/Notifier.php | 8 | ||||
-rw-r--r-- | Zotlabs/Daemon/Ratenotif.php | 2 | ||||
-rw-r--r-- | Zotlabs/Module/Dirsearch.php | 4 | ||||
-rw-r--r-- | Zotlabs/Module/Wiki.php | 53 | ||||
-rw-r--r-- | Zotlabs/Zot/Auth.php | 6 | ||||
-rwxr-xr-x | boot.php | 2 | ||||
-rw-r--r-- | doc/hook/crypto_methods.bb | 5 | ||||
-rw-r--r-- | doc/hook/other_encapsulate.bb | 7 | ||||
-rw-r--r-- | doc/hook/other_unencapsulate.bb | 5 | ||||
-rw-r--r-- | doc/hooklist.bb | 9 | ||||
-rw-r--r-- | include/conversation.php | 2 | ||||
-rw-r--r-- | include/crypto.php | 115 | ||||
-rw-r--r-- | include/wiki.php | 29 | ||||
-rw-r--r-- | include/zot.php | 321 | ||||
-rw-r--r-- | view/css/mod_wiki.css | 7 | ||||
-rwxr-xr-x | view/tpl/siteinfo.tpl | 2 | ||||
-rw-r--r-- | view/tpl/wiki.tpl | 41 | ||||
-rw-r--r-- | view/tpl/wikilist.tpl | 3 |
18 files changed, 410 insertions, 211 deletions
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index 36edbc057..63ced4f56 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -491,7 +491,7 @@ class Notifier { // Now we have collected recipients (except for external mentions, FIXME) // Let's reduce this to a set of hubs. - $r = q("select * from hubloc where hubloc_hash in (" . implode(',',$recipients) . ") + $r = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash in (" . implode(',',$recipients) . ") and hubloc_error = 0 and hubloc_deleted = 0" ); @@ -603,8 +603,8 @@ class Notifier { $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null)); } elseif($packet_type === 'request') { - $packet = zot_build_packet($channel,$packet_type,$env_recips,$hub['hubloc_sitekey'],$hash, - array('message_id' => $request_message_id) + $packet = zot_build_packet($channel,$packet_type,$env_recips,$hub['hubloc_sitekey'],$hub['site_crypto'], + $hash, array('message_id' => $request_message_id) ); } @@ -618,7 +618,7 @@ class Notifier { )); } else { - $packet = zot_build_packet($channel,'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null),$hash); + $packet = zot_build_packet($channel,'notify',$env_recips,(($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash); queue_insert(array( 'hash' => $hash, 'account_id' => $target_item['aid'], diff --git a/Zotlabs/Daemon/Ratenotif.php b/Zotlabs/Daemon/Ratenotif.php index 1cba5e26d..a94b89004 100644 --- a/Zotlabs/Daemon/Ratenotif.php +++ b/Zotlabs/Daemon/Ratenotif.php @@ -77,7 +77,7 @@ class Ratenotif { continue; $hash = random_string(); - $n = zot_build_packet($channel,'notify',null,null,$hash); + $n = zot_build_packet($channel,'notify',null,null,'',$hash); queue_insert(array( 'hash' => $hash, diff --git a/Zotlabs/Module/Dirsearch.php b/Zotlabs/Module/Dirsearch.php index 9b2057203..e6cf5449a 100644 --- a/Zotlabs/Module/Dirsearch.php +++ b/Zotlabs/Module/Dirsearch.php @@ -410,13 +410,13 @@ class Dirsearch extends \Zotlabs\Web\Controller { $rand = db_getfunc('rand'); $realm = get_directory_realm(); if($realm == DIRECTORY_REALM) { - $r = q("select * from site where site_access != 0 and site_register !=0 and ( site_realm = '%s' or site_realm = '') and site_type = %d order by $rand", + $r = q("select * from site where site_access != 0 and site_register !=0 and ( site_realm = '%s' or site_realm = '') and site_type = %d and site_dead = 0 order by $rand", dbesc($realm), intval(SITE_TYPE_ZOT) ); } else { - $r = q("select * from site where site_access != 0 and site_register !=0 and site_realm = '%s' and site_type = %d order by $rand", + $r = q("select * from site where site_access != 0 and site_register !=0 and site_realm = '%s' and site_type = %d and site_dead = 0 order by $rand", dbesc($realm), intval(SITE_TYPE_ZOT) ); diff --git a/Zotlabs/Module/Wiki.php b/Zotlabs/Module/Wiki.php index edd783a62..5cf62d2fb 100644 --- a/Zotlabs/Module/Wiki.php +++ b/Zotlabs/Module/Wiki.php @@ -38,6 +38,7 @@ class Wiki extends \Zotlabs\Web\Controller { require_once('include/wiki.php'); require_once('include/acl_selectors.php'); require_once('include/conversation.php'); + require_once('include/bbcode.php'); // TODO: Combine the interface configuration into a unified object // Something like $interface = array('new_page_button' => false, 'new_wiki_button' => false, ...) @@ -202,11 +203,20 @@ class Wiki extends \Zotlabs\Web\Controller { notice(t('Error retrieving page content') . EOL); goaway('/'.argv(0).'/'.argv(1).'/'.$wikiUrlName); } - $content = ($p['content'] !== '' ? htmlspecialchars_decode($p['content'],ENT_COMPAT) : '"# New page\n"'); + + $mimeType = $p['mimeType']; + + $rawContent = $p['mimeType'] == 'text/bbcode' ? htmlspecialchars_decode(json_decode($p['content']),ENT_COMPAT) : htmlspecialchars_decode($p['content'],ENT_COMPAT); + $content = ($p['content'] !== '' ? $rawContent : '"# New page\n"'); // Render the Markdown-formatted page content in HTML - require_once('library/markdown.php'); - $html = wiki_generate_toc(zidify_text(purify_html(Markdown(wiki_bbcode(json_decode($content)))))); - $renderedContent = wiki_convert_links($html,argv(0).'/'.argv(1).'/'.$wikiUrlName); + if($mimeType == 'text/bbcode') { + $renderedContent = bbcode($content); + } + else { + require_once('library/markdown.php'); + $html = wiki_generate_toc(zidify_text(purify_html(Markdown(wiki_bbcode(json_decode($content)))))); + $renderedContent = wiki_convert_links($html,argv(0).'/'.argv(1).'/'.$wikiUrlName); + } $hide_editor = false; $showPageControls = $wiki_editor; $showNewWikiButton = $wiki_owner; @@ -220,14 +230,13 @@ class Wiki extends \Zotlabs\Web\Controller { } $wikiModalID = random_string(3); - $wikiModal = replace_macros( - get_markup_template('generic_modal.tpl'), array( - '$id' => $wikiModalID, - '$title' => t('Revision Comparison'), - '$ok' => t('Revert'), - '$cancel' => t('Cancel') - ) - ); + + $wikiModal = replace_macros(get_markup_template('generic_modal.tpl'), array( + '$id' => $wikiModalID, + '$title' => t('Revision Comparison'), + '$ok' => t('Revert'), + '$cancel' => t('Cancel') + )); $o .= replace_macros(get_markup_template('wiki.tpl'),array( '$wikiheaderName' => $wikiheaderName, @@ -251,6 +260,7 @@ class Wiki extends \Zotlabs\Web\Controller { '$deny_cid' => $x['deny_cid'], '$deny_gid' => $x['deny_gid'], '$bang' => $x['bang'], + '$mimeType' => $mimeType, '$content' => $content, '$renderedContent' => $renderedContent, '$wikiName' => array('wikiName', t('Enter the name of your new wiki:'), '', ''), @@ -278,6 +288,7 @@ class Wiki extends \Zotlabs\Web\Controller { function post() { require_once('include/wiki.php'); + require_once('include/bbcode.php'); $nick = argv(1); $owner = channelx_by_nick($nick); @@ -293,13 +304,21 @@ class Wiki extends \Zotlabs\Web\Controller { // Render mardown-formatted text in HTML for preview if((argc() > 2) && (argv(2) === 'preview')) { $content = $_POST['content']; - $resource_id = $_POST['resource_id']; - require_once('library/markdown.php'); - $content = wiki_bbcode($content); - $html = wiki_generate_toc(zidify_text(purify_html(Markdown($content)))); + $resource_id = $_POST['resource_id']; $w = wiki_get_wiki($resource_id); $wikiURL = argv(0).'/'.argv(1).'/'.$w['urlName']; - $html = wiki_convert_links($html,$wikiURL); + + $mimeType = $w['mimeType']; + + if($mimeType == 'text/bbcode') { + $html = bbcode($content); + } + else { + require_once('library/markdown.php'); + $content = wiki_bbcode($content); + $html = wiki_generate_toc(zidify_text(purify_html(Markdown($content)))); + $html = wiki_convert_links($html,$wikiURL); + } json_return_and_die(array('html' => $html, 'success' => true)); } diff --git a/Zotlabs/Zot/Auth.php b/Zotlabs/Zot/Auth.php index 0837be21a..d4d3bee1d 100644 --- a/Zotlabs/Zot/Auth.php +++ b/Zotlabs/Zot/Auth.php @@ -149,9 +149,13 @@ class Auth { // The actual channel sending the packet ($c[0]) is not important, but this provides a // generic zot packet with a sender which can be verified + $x = q("select site_crypto from site where site_url = '%s' limit 1", + dbesc($hubloc['hubloc_url']) + ); + $p = zot_build_packet($channel,$type = 'auth_check', array(array('guid' => $hubloc['hubloc_guid'],'guid_sig' => $hubloc['hubloc_guid_sig'])), - $hubloc['hubloc_sitekey'], $this->sec); + $hubloc['hubloc_sitekey'], (($x) ? $x[0]['site_crypto'] : ''), $this->sec); $this->Debug('auth check packet created using sitekey ' . $hubloc['hubloc_sitekey']); $this->Debug('packet contents: ' . $p); @@ -49,7 +49,7 @@ require_once('include/zid.php'); define ( 'PLATFORM_NAME', 'hubzilla' ); define ( 'STD_VERSION', '1.15.2' ); -define ( 'ZOT_REVISION', '1.1' ); +define ( 'ZOT_REVISION', '1.2' ); define ( 'DB_UPDATE_VERSION', 1185 ); diff --git a/doc/hook/crypto_methods.bb b/doc/hook/crypto_methods.bb new file mode 100644 index 000000000..1b16f567d --- /dev/null +++ b/doc/hook/crypto_methods.bb @@ -0,0 +1,5 @@ +[h2]crypto_mthods[/h2] + +Passed an array of crypto methods in local priority order. + +You may change the order and add new methods or disable existing methods. 'aes256cbc' is always supported as a fallback and currently removing this has no effect.
\ No newline at end of file diff --git a/doc/hook/other_encapsulate.bb b/doc/hook/other_encapsulate.bb new file mode 100644 index 000000000..ea0cdf622 --- /dev/null +++ b/doc/hook/other_encapsulate.bb @@ -0,0 +1,7 @@ +[h2]other_encapsulate[/h2] + +Passed an array of 'data', 'pubkey', 'alg', 'result' when encrypting data with an algorithm (alg) which is unknown to the system. Hooks are expected to identify their algorithm, encrypt data with pubkey and place the result in 'result'. + + + + diff --git a/doc/hook/other_unencapsulate.bb b/doc/hook/other_unencapsulate.bb new file mode 100644 index 000000000..c8b0b617f --- /dev/null +++ b/doc/hook/other_unencapsulate.bb @@ -0,0 +1,5 @@ +[h2]other_unencapsulate[/h2] + +Passed an array of 'data', 'prvkey', 'alg', 'result' when decrypting data with an algorithm (alg) which is unknown to the system. Hooks are expected to identify their algorithm, decrypt data with prvkey and place the result in 'result'. + + diff --git a/doc/hooklist.bb b/doc/hooklist.bb index 5226e7de6..52af9608c 100644 --- a/doc/hooklist.bb +++ b/doc/hooklist.bb @@ -145,6 +145,9 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the [zrl=[baseurl]/help/hook/cron_weekly]cron_weekly[/zrl] Called when weekly scheduled tasks are executed +[zrl=[baseurl]/help/hook/crypto_methods]crypto_methods[/zrl] + Called when generating a list of crypto algorithms in the locally preferred order + [zrl=[baseurl]/help/hook/directory_item]directory_item[/zrl] Called when generating a directory listing for display @@ -386,6 +389,12 @@ Hooks allow plugins/addons to "hook into" the code at many points and alter the [zrl=[baseurl]/help/hook/oembed_probe]oembed_probe[/zrl] Called when performing an oembed content lookup +[zrl=[baseurl]/help/hook/other_encapsulate]other_encapsulate[/zrl] + Called when encrypting content for which the algorithm is unknown (see also crypto_methods) + +[zrl=[baseurl]/help/hook/other_unencapsulate]other_unencapsulate[/zrl] + Called when decrypting content for which the algorithm is unknown (see also crypto_methods) + [zrl=[baseurl]/help/hook/page_content_top]page_content_top[/zrl] Called when we generate a webpage (before calling the module content function) diff --git a/include/conversation.php b/include/conversation.php index 16eacd73e..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'), CRYPTO_ALGORITHM)); + $item['body'] = z_obscure($item['body']); } } diff --git a/include/crypto.php b/include/crypto.php index c67c4a1ef..4b78bb63d 100644 --- a/include/crypto.php +++ b/include/crypto.php @@ -48,27 +48,118 @@ 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); + 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); + 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); + 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); + 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 +180,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']; + } } @@ -315,7 +422,7 @@ function convert_salmon_key($key) { function z_obscure($s) { - return json_encode(crypto_encapsulate($s,get_config('system','pubkey'),CRYPTO_ALGORITHM)); + return json_encode(crypto_encapsulate($s,get_config('system','pubkey'))); } function z_unobscure($s) { diff --git a/include/wiki.php b/include/wiki.php index 8fbabcbef..dd5dbbe11 100644 --- a/include/wiki.php +++ b/include/wiki.php @@ -245,7 +245,7 @@ function wiki_create_page($name, $resource_id) { 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)) . wiki_get_mimetype($w)); + $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); @@ -267,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 . wiki_get_mimetype($w); + $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)) . wiki_get_mimetype($w)); + $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); @@ -292,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 . wiki_get_mimetype($w); + $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_file_ext($w); if (is_readable($page_path) === true) { if(filesize($page_path) === 0) { $content = ''; @@ -303,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); } } @@ -314,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 . wiki_get_mimetype($w); + $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); } @@ -340,7 +340,7 @@ function wiki_save_page($arr) { return array('message' => 'Error reading wiki', 'success' => false); } - $fileName = $pageUrlName . wiki_get_mimetype($w); + $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)) { @@ -359,7 +359,7 @@ function wiki_delete_page($arr) { if (!$w['path']) { return array('message' => 'Error reading wiki', 'success' => false); } - $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_mimetype($w); + $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); @@ -381,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 . wiki_get_mimetype($w); + $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'); @@ -393,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 . wiki_get_mimetype($w)) { + if ($object['type'] == 'blob' && $object['file'] === $pageUrlName . wiki_get_file_ext($w)) { $content = $git->git->cat->blob($object['hash']); } } @@ -418,7 +418,7 @@ function wiki_compare_page($arr) { if (!$w['path']) { return array('message' => 'Error reading wiki', 'success' => false); } - $page_path = $w['path'] . '/' . $pageUrlName . wiki_get_mimetype($w); + $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 === '') { @@ -428,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 . wiki_get_mimetype($w)) { + 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 . wiki_get_mimetype($w)) { + if ($object['type'] == 'blob' && $object['file'] === $pageUrlName . wiki_get_file_ext($w)) { $compareContent = $git->git->cat->blob($object['hash']); } } @@ -523,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/ @@ -565,7 +564,7 @@ function wiki_bbcode($s) { return $s; } -function wiki_get_mimetype($arr) { +function wiki_get_file_ext($arr) { if($arr['mimeType'] == 'text/bbcode') return '.bb'; else diff --git a/include/zot.php b/include/zot.php index ee4836d6c..379a9b04c 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, CRYPTO_ALGORITHM); + 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 + * @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_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" - */ -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,11 +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'], - 'alg' => $j['permissions']['alg']), + 'alg' => $j['permissions']['alg'] + ], $channel['channel_prvkey']); if($permissions) $permissions = json_decode($permissions,true); @@ -521,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) @@ -536,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'); @@ -581,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']) { @@ -593,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", @@ -630,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']) { @@ -691,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); @@ -789,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') @@ -825,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'); @@ -834,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']); @@ -874,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' @@ -889,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'])), @@ -946,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'", @@ -999,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); } @@ -1066,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); @@ -1083,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'], CRYPTO_ALGORITHM)); + $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); @@ -1143,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']); @@ -1168,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)); @@ -1358,6 +1333,7 @@ function zot_import($arr, $sender_url) { * @param array $msg * @return NULL|array */ + function public_recips($msg) { require_once('include/channel.php'); @@ -1567,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(); @@ -1876,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))) @@ -1946,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 @@ -1986,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); @@ -2003,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. @@ -2018,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 @@ -2147,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)); @@ -2206,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); @@ -2302,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(); @@ -2549,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), @@ -2558,7 +2541,7 @@ function zot_encode_locations($channel) { 'callback' => $hub['hubloc_callback'], 'sitekey' => $hub['hubloc_sitekey'], 'deleted' => (intval($hub['hubloc_deleted']) ? true : false) - ); + ]; } } @@ -2575,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); @@ -2709,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(); @@ -2753,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')); @@ -2785,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; @@ -2852,7 +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)) ? implode(',', htmlspecialchars($arr['encryption'],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. @@ -2947,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') @@ -2982,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']) ); @@ -3069,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'], @@ -3095,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') @@ -3569,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 ''; @@ -3584,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']); @@ -3623,6 +3614,7 @@ function import_author_zot($x) { * @param array $data * @return array */ + function zot_reply_message_request($data) { $ret = array('success' => false); @@ -3659,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 hulob_url = site_url where hubloc_hash = '%s' and hubloc_error = 0 and hubloc_deleted = 0", dbesc($sender_hash) ); if (! $r) { @@ -3681,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, @@ -3918,7 +3910,12 @@ function zotinfo($arr) { $permissions['connected'] = true; } - $ret['permissions'] = (($ztarget && $zkey) ? crypto_encapsulate(json_encode($permissions),$zkey, CRYPTO_ALGORITHM) : $permissions); + // 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']) $ret['profile'] = $profile; @@ -3948,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) { @@ -3988,14 +3987,14 @@ function zotinfo($arr) { $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(); } @@ -4322,7 +4321,15 @@ function zot_reply_pickup($data) { } } - $encrypted = crypto_encapsulate(json_encode($ret),$sitekey, CRYPTO_ALGORITHM); + // 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 */ diff --git a/view/css/mod_wiki.css b/view/css/mod_wiki.css index 1abb0b3b4..b29957090 100644 --- a/view/css/mod_wiki.css +++ b/view/css/mod_wiki.css @@ -1,9 +1,14 @@ -#ace-editor { +#ace-editor { position: relative; width: 100%; height: 500px; } +#editor { + width: 100%; + height: 500px; +} + .fade.in { -webkit-transition: opacity 0.5s 0.5s ease; -moz-transition: opacity 0.5s 0.5s ease; diff --git a/view/tpl/siteinfo.tpl b/view/tpl/siteinfo.tpl index 0bba31f78..a5b99fd83 100755 --- a/view/tpl/siteinfo.tpl +++ b/view/tpl/siteinfo.tpl @@ -20,7 +20,7 @@ <h2>{{$prj_header}}</h2> -<div>{{$prj_name}}</div> +<div>{{$prj_name}} ({{$z_server_role}})</div> {{if $prj_version}} <div>{{$prj_version}}</div> diff --git a/view/tpl/wiki.tpl b/view/tpl/wiki.tpl index bdce4f4be..726494883 100644 --- a/view/tpl/wiki.tpl +++ b/view/tpl/wiki.tpl @@ -42,7 +42,11 @@ </ul> <div class="tab-content" id="wiki-page-tabs"> <div id="edit-pane" class="tab-pane fade"> + {{if !$mimeType || $mimeType == 'text/markdown'}} <div id="ace-editor"></div> + {{else}} + <textarea id="editor">{{$content}}</textarea> + {{/if}} {{if $showCommitMsg}} {{if $showPageControls}} <div> @@ -50,7 +54,7 @@ <div class="input-group"> <input class="widget-input" name="{{$commitMsg.0}}" id="id_{{$commitMsg.0}}" type="text" value="{{$commitMsg.2}}"{{if $commitMsg.5}} {{$commitMsg.5}}{{/if}}> <div class="input-group-btn"> - <button id="save-page" type="button" class="btn btn-primary btn-sm disabled">Save</button> + <button id="save-page" type="button" class="btn btn-primary btn-sm{{if !$mimeType || $mimeType == 'text/markdown'}} disabled{{/if}}">Save</button> </div> </div> </div> @@ -98,7 +102,7 @@ <script> window.wiki_resource_id = '{{$resource_id}}'; window.wiki_page_name = '{{$page}}'; - window.wiki_page_content = {{$content}}; + window.wiki_page_content = {{if !$mimeType || $mimeType == 'text/markdown'}}{{$content}}{{else}}`{{$content}}`{{/if}}; window.wiki_page_commit = '{{$commit}}'; if (window.wiki_page_name === 'Home') { @@ -135,6 +139,7 @@ event.preventDefault(); }); + {{if !$mimeType || $mimeType == 'text/markdown'}} var editor = ace.edit("ace-editor"); editor.setOptions({ theme: "ace/theme/github", @@ -153,12 +158,26 @@ {{if !$showPageControls}} editor.setReadOnly(true); // Disable editing if the viewer lacks edit permission {{/if}} + + + {{else}} + window.editor = editor = $('#editor'); + {{/if}} + $('#edit-pane-tab').click(function (ev) { setTimeout(function() {window.editor.focus();}, 500); // Return the focus to the editor allowing immediate text entry }); $('#wiki-get-preview').click(function (ev) { - $.post("wiki/{{$channel}}/preview", {content: editor.getValue(), resource_id: window.wiki_resource_id}, function (data) { + $.post("wiki/{{$channel}}/preview", { + {{if !$mimeType || $mimeType == 'text/markdown'}} + content: editor.getValue(), + {{else}} + content: editor.val(), + {{/if}} + resource_id: window.wiki_resource_id + }, + function (data) { if (data.success) { $('#wiki-preview').html(data.html); $("#wiki-toc").toc({content: "#wiki-preview", headings: "h1,h2,h3,h4"}); @@ -207,7 +226,12 @@ ev.preventDefault(); return false; } - var currentContent = editor.getValue(); + {{if !$mimeType || $mimeType == 'text/markdown'}} + var currentContent = editor.getValue(); + {{else}} + var currentContent = editor.val(); + {{/if}} + if (window.wiki_page_content === currentContent) { window.console.log('No edits to save.'); ev.preventDefault(); @@ -224,8 +248,12 @@ window.console.log('Page saved successfully.'); window.wiki_page_content = currentContent; $('#id_commitMsg').val(''); // Clear the commit message box + + {{if !$mimeType || $mimeType == 'text/markdown'}} $('#save-page').addClass('disabled'); // Disable the save button window.editor.getSession().getUndoManager().markClean(); // Reset the undo history for the editor + {{/if}} + window.editor.focus(); // Return focus to the editor for continued editing // $('#wiki-get-history').click(); } else { @@ -400,6 +428,7 @@ $('#new-wiki-button').hide(); {{/if}} // using input event instead of change since it's called with some timeout + {{if !$mimeType || $mimeType == 'text/markdown'}} window.editor.on("input", function() { if(window.editor.getSession().getUndoManager().isClean()) { $('#save-page').addClass('disabled'); @@ -407,6 +436,10 @@ $('#save-page').removeClass('disabled'); } }); + {{else}} + window.editor.bbco_autocomplete('bbcode'); + {{/if}} + }); </script> diff --git a/view/tpl/wikilist.tpl b/view/tpl/wikilist.tpl index c7cdfaa43..68aa41e7c 100644 --- a/view/tpl/wikilist.tpl +++ b/view/tpl/wikilist.tpl @@ -9,8 +9,7 @@ <div id="new-wiki-form-wrapper" class="section-content-tools-wrapper"> <form id="new-wiki-form" action="wiki/{{$channel}}/create/wiki" method="post" class="acl-form" data-form_id="new-wiki-form" data-allow_cid='{{$allow_cid}}' data-allow_gid='{{$allow_gid}}' data-deny_cid='{{$deny_cid}}' data-deny_gid='{{$deny_gid}}'> {{include file="field_input.tpl" field=$wikiName}} - {{* include file="field_select.tpl" field=$mimeType *}} - <input type="hidden" name="mimeType" value="text/markdown"> + {{include file="field_select.tpl" field=$mimeType}} {{include file="field_checkbox.tpl" field=$notify}} <div> <div class="btn-group pull-right"> |