aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Zotlabs/Daemon/Notifier.php4
-rw-r--r--Zotlabs/Web/HTTPSig.php21
-rw-r--r--include/queue_fn.php29
-rw-r--r--include/zot.php165
4 files changed, 204 insertions, 15 deletions
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php
index b168db5ae..957b859af 100644
--- a/Zotlabs/Daemon/Notifier.php
+++ b/Zotlabs/Daemon/Notifier.php
@@ -618,8 +618,8 @@ class Notifier {
$packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
}
if($packet_type === 'keychange') {
- $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
$pmsg = get_pconfig($channel['channel_id'],'system','keychange');
+ $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
}
elseif($packet_type === 'request') {
$env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : '');
@@ -640,7 +640,7 @@ class Notifier {
}
else {
$env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : '');
- $packet = zot_build_packet($channel,'notify',$env,(($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash);
+ $packet = zot6_build_packet($channel,'notify',$env, json_encode($encoded_item), (($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash);
queue_insert(
[
'hash' => $hash,
diff --git a/Zotlabs/Web/HTTPSig.php b/Zotlabs/Web/HTTPSig.php
index 63033ce5e..a27edb73d 100644
--- a/Zotlabs/Web/HTTPSig.php
+++ b/Zotlabs/Web/HTTPSig.php
@@ -137,7 +137,22 @@ class HTTPSig {
}
}
- logger('Content_Valid: ' . $result['content_valid']);
+
+ if(in_array('x-zot-digest',$signed_headers)) {
+ $result['content_signed'] = true;
+ $digest = explode('=', $headers['x-zot-digest']);
+ if($digest[0] === 'SHA-256')
+ $hashalg = 'sha256';
+ if($digest[0] === 'SHA-512')
+ $hashalg = 'sha512';
+
+ // The explode operation will have stripped the '=' padding, so compare against unpadded base64
+ if(rtrim(base64_encode(hash($hashalg,$_POST['data'],true)),'=') === $digest[1]) {
+ $result['content_valid'] = true;
+ }
+ }
+
+ logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false'));
return $result;
@@ -194,8 +209,8 @@ class HTTPSig {
. '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
if($crypt_key) {
- $x = crypto_encapsulate($headerval,$crypt_key,$crypt_alg);
- $headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'];
+ $x = crypto_encapsulate($headerval,$crypt_key,$crypt_algo);
+ $headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"';
}
if($auth) {
diff --git a/include/queue_fn.php b/include/queue_fn.php
index 5fb0d5f1e..798ac36db 100644
--- a/include/queue_fn.php
+++ b/include/queue_fn.php
@@ -121,7 +121,7 @@ function queue_deliver($outq, $immediate = false) {
$base = null;
$h = parse_url($outq['outq_posturl']);
- if($h)
+ if($h !== false)
$base = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : '');
if(($base) && ($base !== z_root()) && ($immediate)) {
@@ -160,6 +160,9 @@ function queue_deliver($outq, $immediate = false) {
+
+
+
$arr = array('outq' => $outq, 'base' => $base, 'handled' => false, 'immediate' => $immediate);
call_hooks('queue_deliver',$arr);
if($arr['handled'])
@@ -216,7 +219,29 @@ function queue_deliver($outq, $immediate = false) {
// normal zot delivery
logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG);
- $result = zot_zot($outq['outq_posturl'],$outq['outq_notify']);
+
+ $channel = null;
+
+ if($outq['outq_msg'] && $outq['outq_channel']) {
+ $channel = channelx_by_n($outq['outq_channel']);
+ }
+
+ $host_crypto = null;
+
+ if($channel && $base) {
+ $h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' order by hubloc_id desc limit 1",
+ dbesc($base)
+ );
+ if($h) {
+ $host_crypto = $h[0];
+ }
+ }
+
+ $msg = $outq['outq_notify'];
+
+ $result = zot_zot($outq['outq_posturl'],$msg,$channel,$host_crypto);
+
+
if($result['success']) {
logger('deliver: remote zot delivery succeeded to ' . $outq['outq_posturl']);
zot_process_response($outq['outq_posturl'],$result, $outq);
diff --git a/include/zot.php b/include/zot.php
index 8e3d03ad8..1042f09d9 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -158,6 +158,85 @@ function zot_build_packet($channel, $type = 'notify', $recipients = null, $remot
return json_encode($data);
}
+
+/**
+ * @brief Builds a zot6 notification packet.
+ *
+ * Builds a zot6 notification packet that you can either store in the queue with
+ * a message array or call zot_zot to immediately zot it to the other side.
+ *
+ * @param array $channel
+ * sender channel structure
+ * @param string $type
+ * packet type: one of 'ping', 'pickup', 'purge', 'refresh', 'keychange', 'force_refresh', 'notify', 'auth_check'
+ * @param array $recipients
+ * envelope information, array ( 'guid' => string, 'guid_sig' => string ); empty for public posts
+ * @param string $remote_key
+ * optional public site key of target hub used to encrypt entire packet
+ * NOTE: remote_key and encrypted packets are required for 'auth_check' packets, optional for all others
+ * @param string $methods
+ * optional comma separated list of encryption methods @ref zot_best_algorithm()
+ * @param string $secret
+ * random string, required for packets which require verification/callback
+ * e.g. 'pickup', 'purge', 'notify', 'auth_check'. Packet types 'ping', 'force_refresh', and 'refresh' do not require verification
+ * @param string $extra
+ * @returns string json encoded zot packet
+ */
+function zot6_build_packet($channel, $type = 'notify', $recipients = null, $msg = '', $remote_key = null, $methods = '', $secret = null, $extra = null) {
+
+ $sig_method = get_config('system','signature_algorithm','sha256');
+
+ $data = [
+ 'type' => $type,
+ 'sender' => [
+ 'guid' => $channel['channel_guid'],
+ 'guid_sig' => base64url_encode(rsa_sign($channel['channel_guid'],$channel['channel_prvkey'],$sig_method)),
+ 'url' => z_root(),
+ 'url_sig' => base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey'],$sig_method)),
+ 'sitekey' => get_config('system','pubkey')
+ ],
+ 'callback' => '/post',
+ 'version' => Zotlabs\Lib\System::get_zot_revision(),
+ 'encryption' => crypto_methods(),
+ 'signing' => signing_methods()
+ ];
+
+ if ($recipients) {
+ for ($x = 0; $x < count($recipients); $x ++)
+ unset($recipients[$x]['hash']);
+
+ $data['recipients'] = $recipients;
+ }
+
+ if($msg) {
+ $data['msg'] = $msg;
+ }
+
+ if ($secret) {
+ $data['secret'] = preg_replace('/[^0-9a-fA-F]/','',$secret);
+ $data['secret_sig'] = base64url_encode(rsa_sign($secret,$channel['channel_prvkey'],$sig_method));
+ }
+
+ if ($extra) {
+ foreach ($extra as $k => $v)
+ $data[$k] = $v;
+ }
+
+ logger('zot6_build_packet: ' . print_r($data,true), LOGGER_DATA, LOG_DEBUG);
+
+ // Hush-hush ultra top-secret mode
+
+ if($remote_key) {
+ $algorithm = zot_best_algorithm($methods);
+ $data = crypto_encapsulate(json_encode($data),$remote_key, $algorithm);
+ }
+
+ return json_encode($data);
+}
+
+
+
+
/**
* @brief Choose best encryption function from those available on both sites.
*
@@ -209,10 +288,23 @@ function zot_best_algorithm($methods) {
*
* @param string $url
* @param array $data
+ * @param array $channel (optional if using zot6 delivery)
+ * @param array $crypto (optional if encrypted httpsig, requires hubloc_sitekey and site_crypto elements)
* @return array see z_post_url() for returned data format
*/
-function zot_zot($url, $data) {
- return z_post_url($url, array('data' => $data));
+function zot_zot($url, $data, $channel = null,$crypto = null) {
+
+ $headers = [];
+
+ if($channel) {
+ $headers['X-Zot-Token'] = random_string();
+ $hash = \Zotlabs\Web\HTTPSig::generate_digest($data,false);
+ $headers['X-Zot-Digest'] = 'SHA-256=' . $hash;
+ $h = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,false,'sha512',(($crypto) ? $crypto['hubloc_sitekey'] : ''), (($crypto) ? zot_best_algorithm($crypto['site_crypto']) : ''));
+ }
+
+ $redirects = 0;
+ return z_post_url($url, array('data' => $data),$redirects,((empty($h)) ? [] : [ 'headers' => $h ]));
}
/**
@@ -4967,21 +5059,78 @@ function zot_reply_refresh($sender, $recipients) {
}
+function zot6_check_sig() {
+
+ $ret = [ 'success' => false ];
+
+ logger('server: ' . print_r($_SERVER,true), LOGGER_DATA);
+
+ if(array_key_exists('HTTP_SIGNATURE',$_SERVER)) {
+ $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER['HTTP_SIGNATURE']);
+ if($sigblock) {
+ $keyId = $sigblock['keyId'];
+
+ if($keyId) {
+ $r = q("select hubloc.*, site_crypto from hubloc left join site on hubloc_url = site_url
+ where hubloc_addr = '%s' ",
+ dbesc(str_replace('acct:','',$keyId))
+ );
+ if($r) {
+ foreach($r as $hubloc) {
+ $verified = \Zotlabs\Web\HTTPSig::verify('',$hubloc['xchan_pubkey']);
+ if($verified && $verified['header_signed'] && $verified['header_valid'] && $verified['content_signed'] && $verified['content_valid']) {
+ $ret['hubloc'] = $hubloc;
+ $ret['success'] = true;
+ return $ret;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return $ret;
+}
+
function zot_reply_notify($data) {
$ret = array('success' => false);
logger('notify received from ' . $data['sender']['url']);
- $async = get_config('system','queued_fetch');
+ // handle zot6 delivery
+
+ $zret = zot6_check_sig();
+ if($zret['success'] && $zret['hubloc'] && $zret['hubloc']['hubloc_guid'] === $data['sender']['guid'] && $data['msg']) {
+ logger('zot6_delivery',LOGGER_DEBUG);
+ logger('zot6_data: ' . print_r($data,true),LOGGER_DATA);
+
+ $ret['collected'] = true;
+
+ $import = [ 'success' => true, 'pickup' => [ [ 'notify' => $data, 'message' => json_decode($data['msg'],true) ] ] ];
- if($async) {
- // add to receive queue
- // qreceive_add($data);
+ logger('zot6_import: ' . print_r($import,true), LOGGER_DATA);
+
+ $x = zot_import([ 'success' => true, 'body' => json_encode($import) ], $data['sender']['url']);
+ if($x) {
+ $x = crypto_encapsulate(json_encode($x),$zret['hubloc']['hubloc_sitekey'],zot_best_algorithm($zret['hubloc']['site_crypto']));
+ $ret['delivery_report'] = $x;
+ }
}
else {
- $x = zot_fetch($data);
- $ret['delivery_report'] = $x;
+
+ // handle traditional zot delivery
+
+ $async = get_config('system','queued_fetch');
+
+ if($async) {
+ // add to receive queue
+ // qreceive_add($data);
+ }
+ else {
+ $x = zot_fetch($data);
+ $ret['delivery_report'] = $x;
+ }
}
$ret['success'] = true;