aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Zotlabs/Daemon/Deliver.php7
-rw-r--r--Zotlabs/Daemon/Notifier.php64
-rw-r--r--Zotlabs/Lib/ActivityStreams.php191
-rw-r--r--Zotlabs/Lib/DReport.php84
-rw-r--r--Zotlabs/Lib/JSalmon.php50
-rw-r--r--Zotlabs/Lib/Libzot.php74
-rw-r--r--Zotlabs/Lib/Zotfinger.php23
-rw-r--r--Zotlabs/Module/Channel.php44
-rw-r--r--Zotlabs/Module/Connedit.php5
-rw-r--r--Zotlabs/Module/Dreport.php20
-rw-r--r--Zotlabs/Module/Item.php28
-rw-r--r--Zotlabs/Module/Wfinger.php6
-rw-r--r--Zotlabs/Update/_1226.php78
-rw-r--r--Zotlabs/Update/_1227.php30
-rw-r--r--Zotlabs/Update/_1228.php37
-rw-r--r--Zotlabs/Zot6/HTTPSig.php46
-rw-r--r--Zotlabs/Zot6/Receiver.php2
-rw-r--r--Zotlabs/Zot6/Zot6Handler.php11
-rw-r--r--include/channel.php82
-rw-r--r--include/crypto.php9
-rwxr-xr-xinclude/items.php25
-rw-r--r--include/network.php4
-rw-r--r--include/queue_fn.php98
-rw-r--r--include/text.php44
-rw-r--r--include/xchan.php5
-rw-r--r--include/zot.php10
-rw-r--r--install/schema_mysql.sql6
-rw-r--r--install/schema_postgres.sql6
28 files changed, 910 insertions, 179 deletions
diff --git a/Zotlabs/Daemon/Deliver.php b/Zotlabs/Daemon/Deliver.php
index b809cba91..43f426eb7 100644
--- a/Zotlabs/Daemon/Deliver.php
+++ b/Zotlabs/Daemon/Deliver.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Daemon;
+use Zotlabs\Lib\DReport;
+
require_once('include/zot.php');
require_once('include/queue_fn.php');
@@ -58,11 +60,12 @@ class Deliver {
foreach($dresult as $xx) {
if(is_array($xx) && array_key_exists('message_id',$xx)) {
- if(delivery_report_is_storable($xx)) {
- q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s','%s','%s','%s','%s' ) ",
+ if(DReport::is_storable($xx)) {
+ q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
dbesc($xx['message_id']),
dbesc($xx['location']),
dbesc($xx['recipient']),
+ dbesc(($xx['name']) ? $xx['name'] : EMPTY_STR),
dbesc($xx['status']),
dbesc(datetime_convert($xx['date'])),
dbesc($xx['sender'])
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php
index f74c8f11c..8b81c49da 100644
--- a/Zotlabs/Daemon/Notifier.php
+++ b/Zotlabs/Daemon/Notifier.php
@@ -2,6 +2,8 @@
namespace Zotlabs\Daemon;
+use Zotlabs\Lib\Libzot;
+
require_once('include/queue_fn.php');
require_once('include/html2plain.php');
require_once('include/conversation.php');
@@ -344,7 +346,16 @@ class Notifier {
return;
$encoded_item = encode_item($target_item);
-
+
+ // activitystreams version
+ $m = get_iconfig($target_item,'activitystreams','signed_data');
+ if($m) {
+ $activity = json_decode($m,true);
+ }
+ else {
+ $activity = \Zotlabs\Lib\Activity::encode_activity($target_item);
+ }
+
// Send comments to the owner to re-deliver to everybody in the conversation
// We only do this if the item in question originated on this site. This prevents looping.
// To clarify, a site accepting a new comment is responsible for sending it to the owner for relay.
@@ -561,7 +572,7 @@ class Notifier {
logger('notifier_hub: ' . $hub['hubloc_url'],LOGGER_DEBUG);
- if($hub['hubloc_network'] !== 'zot') {
+ if(! in_array($hub['hubloc_network'], [ 'zot','zot6' ])) {
$narr = [
'channel' => $channel,
'upstream' => $upstream,
@@ -610,20 +621,27 @@ class Notifier {
continue;
}
- // default: zot protocol
+ if(! in_array($hub['hubloc_network'], [ 'zot','zot6' ])) {
+ continue;
+ }
- $hash = random_string();
+ $hash = new_uuid();
$packet = null;
$pmsg = '';
if($packet_type === 'refresh' || $packet_type === 'purge') {
- $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
+ if($hub['hubloc_network'] === 'zot6') {
+ $packet = Libzot::build_packet($channel, $packet_type, ids_to_array($packet_recips,'hash'));
+ }
+ else {
+ $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
+ }
}
- if($packet_type === 'keychange') {
+ if($packet_type === 'keychange' && $hub['hubloc_network'] === 'zot') {
$pmsg = get_pconfig($channel['channel_id'],'system','keychange');
$packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
}
- elseif($packet_type === 'request') {
+ elseif($packet_type === 'request' && $hub['hubloc_network'] === 'zot') {
$env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : '');
$packet = zot_build_packet($channel,$packet_type,$env,$hub['hubloc_sitekey'],$hub['site_crypto'],
$hash, array('message_id' => $request_message_id)
@@ -636,6 +654,7 @@ class Notifier {
'account_id' => $channel['channel_account_id'],
'channel_id' => $channel['channel_id'],
'posturl' => $hub['hubloc_callback'],
+ 'driver' => $hub['hubloc_network'],
'notify' => $packet,
'msg' => (($pmsg) ? json_encode($pmsg) : '')
));
@@ -643,18 +662,32 @@ class Notifier {
else {
$env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : '');
- // currently zot6 delivery is only performed on normal items and not sync items or mail or anything else
- // Eventually we will do this for all deliveries, but for now ensure this is precisely what we are dealing
- // with before switching to zot6 as the primary zot6 handler checks for the existence of a message delivery report
- // to trigger dequeue'ing
- $z6 = (($encoded_item && $encoded_item['type'] === 'activity' && (! array_key_exists('allow_cid',$encoded_item))) ? true : false);
- if($z6) {
- $packet = zot6_build_packet($channel,'notify',$env, json_encode($encoded_item), (($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash);
+ if($hub['hubloc_network'] === 'zot6') {
+ $zenv = [];
+ if($env) {
+ foreach($env as $e) {
+ $zenv[] = $e['hash'];
+ }
+ }
+
+ $packet_type = (($upstream || $uplink) ? 'response' : 'activity');
+ $packet = Libzot::build_packet($channel,$packet_type,$zenv,$activity,'activitystreams',(($private) ? $hub['hubloc_sitekey'] : null),$hub['site_crypto']);
}
else {
- $packet = zot_build_packet($channel,'notify',$env, (($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash);
+ // currently zot6 delivery is only performed on normal items and not sync items or mail or anything else
+ // Eventually we will do this for all deliveries, but for now ensure this is precisely what we are dealing
+ // with before switching to zot6 as the primary zot6 handler checks for the existence of a message delivery report
+ // to trigger dequeue'ing
+
+ $z6 = (($encoded_item && $encoded_item['type'] === 'activity' && (! array_key_exists('allow_cid',$encoded_item))) ? true : false);
+ if($z6) {
+ $packet = zot6_build_packet($channel,'notify',$env, json_encode($encoded_item), (($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash);
+ }
+ else {
+ $packet = zot_build_packet($channel,'notify',$env, (($private) ? $hub['hubloc_sitekey'] : null), $hub['site_crypto'],$hash);
+ }
}
queue_insert(
@@ -663,6 +696,7 @@ class Notifier {
'account_id' => $target_item['aid'],
'channel_id' => $target_item['uid'],
'posturl' => $hub['hubloc_callback'],
+ 'driver' => $hub['hubloc_network'],
'notify' => $packet,
'msg' => json_encode($encoded_item)
]
diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php
index 37e717f58..a322637fd 100644
--- a/Zotlabs/Lib/ActivityStreams.php
+++ b/Zotlabs/Lib/ActivityStreams.php
@@ -7,22 +7,25 @@ namespace Zotlabs\Lib;
*
* Parses an ActivityStream JSON string.
*/
+
class ActivityStreams {
- public $raw = null;
- public $data;
- public $valid = false;
- public $id = '';
- public $type = '';
- public $actor = null;
- public $obj = null;
- public $tgt = null;
- public $origin = null;
- public $owner = null;
- public $signer = null;
- public $ldsig = null;
- public $sigok = false;
- public $recips = null;
+ public $raw = null;
+ public $data = null;
+ public $valid = false;
+ public $deleted = false;
+ public $id = '';
+ public $parent_id = '';
+ public $type = '';
+ public $actor = null;
+ public $obj = null;
+ public $tgt = null;
+ public $origin = null;
+ public $owner = null;
+ public $signer = null;
+ public $ldsig = null;
+ public $sigok = false;
+ public $recips = null;
public $raw_recips = null;
/**
@@ -35,16 +38,49 @@ class ActivityStreams {
function __construct($string) {
$this->raw = $string;
- $this->data = json_decode($string, true);
+
+ if(is_array($string)) {
+ $this->data = $string;
+ }
+ else {
+ $this->data = json_decode($string, true);
+ }
if($this->data) {
+
+ // verify and unpack JSalmon signature if present
+
+ if(is_array($this->data) && array_key_exists('signed',$this->data)) {
+ $ret = JSalmon::verify($this->data);
+ $tmp = JSalmon::unpack($this->data['data']);
+ if($ret && $ret['success']) {
+ if($ret['signer']) {
+ $saved = json_encode($this->data,JSON_UNESCAPED_SLASHES);
+ $this->data = $tmp;
+ $this->data['signer'] = $ret['signer'];
+ $this->data['signed_data'] = $saved;
+ if($ret['hubloc']) {
+ $this->data['hubloc'] = $ret['hubloc'];
+ }
+ }
+ }
+ }
+
$this->valid = true;
+
+ if(array_key_exists('type',$this->data) && array_key_exists('actor',$this->data) && array_key_exists('object',$this->data)) {
+ if($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
+ $this->deleted = $this->data['actor'];
+ $this->valid = false;
+ }
+ }
+
}
if($this->is_valid()) {
$this->id = $this->get_property_obj('id');
$this->type = $this->get_primary_type();
- $this->actor = $this->get_compound_property('actor');
+ $this->actor = $this->get_actor('actor','','');
$this->obj = $this->get_compound_property('object');
$this->tgt = $this->get_compound_property('target');
$this->origin = $this->get_compound_property('origin');
@@ -53,14 +89,31 @@ class ActivityStreams {
$this->ldsig = $this->get_compound_property('signature');
if($this->ldsig) {
$this->signer = $this->get_compound_property('creator',$this->ldsig);
- if($this->signer && $this->signer['publicKey'] && $this->signer['publicKey']['publicKeyPem']) {
- $this->sigok = \Zotlabs\Lib\LDSignatures::verify($this->data,$this->signer['publicKey']['publicKeyPem']);
+ if($this->signer && is_array($this->signer) && array_key_exists('publicKey',$this->signer) && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) {
+ $this->sigok = LDSignatures::verify($this->data,$this->signer['publicKey']['publicKeyPem']);
}
}
- if(($this->type === 'Note') && (! $this->obj)) {
+ if(! $this->obj) {
$this->obj = $this->data;
$this->type = 'Create';
+ if(! $this->actor) {
+ $this->actor = $this->get_actor('attributedTo',$this->obj);
+ }
+ }
+
+ if($this->obj && is_array($this->obj) && $this->obj['actor'])
+ $this->obj['actor'] = $this->get_actor('actor',$this->obj);
+ if($this->tgt && is_array($this->tgt) && $this->tgt['actor'])
+ $this->tgt['actor'] = $this->get_actor('actor',$this->tgt);
+
+ $this->parent_id = $this->get_property_obj('inReplyTo');
+
+ if((! $this->parent_id) && is_array($this->obj)) {
+ $this->parent_id = $this->obj['inReplyTo'];
+ }
+ if((! $this->parent_id) && is_array($this->obj)) {
+ $this->parent_id = $this->obj['id'];
}
}
}
@@ -190,44 +243,122 @@ class ActivityStreams {
$base = (($base) ? $base : $this->data);
$propname = (($prefix) ? $prefix . ':' : '') . $property;
+ if(! is_array($base)) {
+ btlogger('not an array: ' . print_r($base,true));
+ return null;
+ }
+
return ((array_key_exists($propname, $base)) ? $base[$propname] : null);
}
+
/**
* @brief Fetches a property from an URL.
*
* @param string $url
* @return NULL|mixed
*/
+
function fetch_property($url) {
+ return self::fetch($url);
+ }
+
+ static function fetch($url) {
$redirects = 0;
if(! check_siteallowed($url)) {
logger('blacklisted: ' . $url);
return null;
}
-
+ logger('fetch: ' . $url, LOGGER_DEBUG);
$x = z_fetch_url($url, true, $redirects,
- ['headers' => [ 'Accept: application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ]]);
- if($x['success'])
+ [ 'headers' => [ 'Accept: application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ]]);
+ if($x['success']) {
+ $y = json_decode($x['body'],true);
+ logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
return json_decode($x['body'], true);
+ }
+ else {
+ logger('fetch failed: ' . $url);
+ }
+ return null;
+ }
+
+ static function is_an_actor($s) {
+ return(in_array($s,[ 'Application','Group','Service','Person','Service' ]));
+ }
+
+ /**
+ * @brief
+ *
+ * @param string $property
+ * @param array $base
+ * @param string $namespace (optional) default empty
+ * @return NULL|mixed
+ */
+
+ function get_actor($property,$base='',$namespace = '') {
+ $x = $this->get_property_obj($property, $base, $namespace);
+ if($this->is_url($x)) {
+
+ // SECURITY: If we have already stored the actor profile, re-generate it
+ // from cached data - don't refetch it from the network
+ $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1",
+ dbesc($x)
+ );
+ if($r) {
+ $y = Activity::encode_person($r[0]);
+ $y['cached'] = true;
+ return $y;
+ }
+ }
+ $actor = $this->get_compound_property($property,$base,$namespace,true);
+ if(is_array($actor) && self::is_an_actor($actor['type'])) {
+ if(array_key_exists('id',$actor) && (! array_key_exists('inbox',$actor))) {
+ $actor = $this->fetch_property($actor['id']);
+ }
+ return $actor;
+ }
return null;
}
+
/**
* @brief
*
* @param string $property
* @param array $base
* @param string $namespace (optional) default empty
+ * @param boolean $first (optional) default false, if true and result is a sequential array return only the first element
* @return NULL|mixed
*/
- function get_compound_property($property, $base = '', $namespace = '') {
+ function get_compound_property($property, $base = '', $namespace = '', $first = false) {
$x = $this->get_property_obj($property, $base, $namespace);
if($this->is_url($x)) {
$x = $this->fetch_property($x);
}
+ // verify and unpack JSalmon signature if present
+
+ if(is_array($x) && array_key_exists('signed',$x)) {
+ $ret = JSalmon::verify($x);
+ $tmp = JSalmon::unpack($x['data']);
+ if($ret && $ret['success']) {
+ if($ret['signer']) {
+ $saved = json_encode($x,JSON_UNESCAPED_SLASHES);
+ $x = $tmp;
+ $x['signer'] = $ret['signer'];
+ $x['signed_data'] = $saved;
+ if($ret['hubloc']) {
+ $x['hubloc'] = $ret['hubloc'];
+ }
+ }
+ }
+ }
+ if($first && is_array($x) && array_key_exists(0,$x)) {
+ return $x[0];
+ }
+
return $x;
}
@@ -273,4 +404,18 @@ class ActivityStreams {
return $x;
}
+
+ static function is_as_request() {
+
+ $x = getBestSupportedMimeType([
+ 'application/ld+json;profile="https://www.w3.org/ns/activitystreams"',
+ 'application/activity+json',
+ 'application/ld+json;profile="http://www.w3.org/ns/activitystreams"'
+ ]);
+
+ return(($x) ? true : false);
+
+ }
+
+
} \ No newline at end of file
diff --git a/Zotlabs/Lib/DReport.php b/Zotlabs/Lib/DReport.php
index a68d6c18f..21b320cac 100644
--- a/Zotlabs/Lib/DReport.php
+++ b/Zotlabs/Lib/DReport.php
@@ -14,6 +14,7 @@ class DReport {
$this->location = $location;
$this->sender = $sender;
$this->recipient = $recipient;
+ $this->name = EMPTY_STR;
$this->message_id = $message_id;
$this->status = $status;
$this->date = datetime_convert();
@@ -24,8 +25,8 @@ class DReport {
$this->date = datetime_convert();
}
- function addto_recipient($name) {
- $this->recipient = $this->recipient . ' ' . $name;
+ function set_name($name) {
+ $this->name = $name;
}
function addto_update($status) {
@@ -37,6 +38,7 @@ class DReport {
$this->location = $arr['location'];
$this->sender = $arr['sender'];
$this->recipient = $arr['recipient'];
+ $this->name = $arr['name'];
$this->message_id = $arr['message_id'];
$this->status = $arr['status'];
$this->date = $arr['date'];
@@ -47,9 +49,87 @@ class DReport {
'location' => $this->location,
'sender' => $this->sender,
'recipient' => $this->recipient,
+ 'name' => $this->name,
'message_id' => $this->message_id,
'status' => $this->status,
'date' => $this->date
);
}
+
+ /**
+ * @brief decide whether to store a returned delivery report
+ *
+ * @param array $dr
+ * @return boolean
+ */
+
+ static function is_storable($dr) {
+
+ if(get_config('system', 'disable_dreport'))
+ return false;
+
+ /**
+ * @hooks dreport_is_storable
+ * Called before storing a dreport record to determine whether to store it.
+ * * \e array
+ */
+
+ call_hooks('dreport_is_storable', $dr);
+
+ // let plugins accept or reject - if neither, continue on
+ if(array_key_exists('accept',$dr) && intval($dr['accept']))
+ return true;
+ if(array_key_exists('reject',$dr) && intval($dr['reject']))
+ return false;
+
+ if(! ($dr['sender']))
+ return false;
+
+ // Is the sender one of our channels?
+
+ $c = q("select channel_id from channel where channel_hash = '%s' limit 1",
+ dbesc($dr['sender'])
+ );
+ if(! $c)
+ return false;
+
+
+ // is the recipient one of our connections, or do we want to store every report?
+
+
+ $rxchan = $dr['recipient'];
+ $pcf = get_pconfig($c[0]['channel_id'],'system','dreport_store_all');
+ if($pcf)
+ return true;
+
+ // We always add ourself as a recipient to private and relayed posts
+ // So if a remote site says they can't find us, that's no big surprise
+ // and just creates a lot of extra report noise
+
+ if(($dr['location'] !== z_root()) && ($dr['sender'] === $rxchan) && ($dr['status'] === 'recipient_not_found'))
+ return false;
+
+ // If you have a private post with a recipient list, every single site is going to report
+ // back a failed delivery for anybody on that list that isn't local to them. We're only
+ // concerned about this if we have a local hubloc record which says we expected them to
+ // have a channel on that site.
+
+ $r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and hubloc_url = '%s'",
+ dbesc($rxchan),
+ dbesc($dr['location'])
+ );
+ if((! $r) && ($dr['status'] === 'recipient_not_found'))
+ return false;
+
+ $r = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1",
+ dbesc($rxchan),
+ intval($c[0]['channel_id'])
+ );
+ if($r)
+ return true;
+
+ return false;
+ }
+
+
}
diff --git a/Zotlabs/Lib/JSalmon.php b/Zotlabs/Lib/JSalmon.php
index 43d5f9d09..f35bf6235 100644
--- a/Zotlabs/Lib/JSalmon.php
+++ b/Zotlabs/Lib/JSalmon.php
@@ -2,15 +2,13 @@
namespace Zotlabs\Lib;
+use Zotlabs\Zot6\HTTPSig;
class JSalmon {
- static function sign($data,$key_id,$key) {
+ static function sign($data,$key_id,$key,$data_type = 'application/x-zot+json') {
- $arr = $data;
- $data = json_encode($data,JSON_UNESCAPED_SLASHES);
- $data = base64url_encode($data, false); // do not strip padding
- $data_type = 'application/x-zot+json';
+ $data = base64url_encode(json_encode($data,true),true); // strip padding
$encoding = 'base64url';
$algorithm = 'RSA-SHA256';
@@ -18,9 +16,9 @@ class JSalmon {
// precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
- $precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
+ $precomputed = '.' . base64url_encode($data_type,true) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng';
- $signature = base64url_encode(rsa_sign($data . $precomputed, $key), false);
+ $signature = base64url_encode(rsa_sign($data . $precomputed, $key), true);
return ([
'signed' => true,
@@ -30,9 +28,45 @@ class JSalmon {
'alg' => $algorithm,
'sigs' => [
'value' => $signature,
- 'key_id' => base64url_encode($key_id)
+ 'key_id' => base64url_encode($key_id, true)
]
]);
}
+
+ static function verify($x) {
+
+ logger('verify');
+ $ret = [ 'results' => [] ];
+
+ if(! is_array($x)) {
+ return $false;
+ }
+ if(! ( array_key_exists('signed',$x) && $x['signed'])) {
+ return $false;
+ }
+
+ $signed_data = preg_replace('/\s+/','',$x['data']) . '.'
+ . base64url_encode($x['data_type'],true) . '.'
+ . base64url_encode($x['encoding'],true) . '.'
+ . base64url_encode($x['alg'],true);
+
+ $key = HTTPSig::get_key(EMPTY_STR,base64url_decode($x['sigs']['key_id']));
+ logger('key: ' . print_r($key,true));
+ if($key['portable_id'] && $key['public_key']) {
+ if(rsa_verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) {
+ logger('verified');
+ $ret = [ 'success' => true, 'signer' => $key['portable_id'], 'hubloc' => $key['hubloc'] ];
+ }
+ }
+
+ return $ret;
+
+ }
+
+ static function unpack($data) {
+ return json_decode(base64url_decode($data),true);
+ }
+
+
} \ No newline at end of file
diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php
index 2c726aff4..f0248a85b 100644
--- a/Zotlabs/Lib/Libzot.php
+++ b/Zotlabs/Lib/Libzot.php
@@ -109,7 +109,7 @@ class Libzot {
$data = [
'type' => $type,
'encoding' => $encoding,
- 'sender' => $channel['channel_hash'],
+ 'sender' => $channel['channel_portable_id'],
'site_id' => self::make_xchan_hash(z_root(), get_config('system','pubkey')),
'version' => System::get_zot_revision(),
];
@@ -329,8 +329,14 @@ class Libzot {
return false;
if($channel && $record['data']['permissions']) {
- $old_read_stream_perm = their_perms_contains($channel['channel_id'],$x['hash'],'view_stream');
- set_abconfig($channel['channel_id'],$x['hash'],'system','their_perms',$record['data']['permissions']);
+ $permissions = explode(',',$record['data']['permissions']);
+ if($permissions && is_array($permissions)) {
+ $old_read_stream_perm = get_abconfig($channel['channel_id'],$x['hash'],'their_perms','view_stream');
+
+ foreach($permissions as $p) {
+ set_abconfig($channel['channel_id'],$x['hash'],'their_perms',$p,'1');
+ }
+ }
if(array_key_exists('profile',$record['data']) && array_key_exists('next_birthday',$record['data']['profile'])) {
$next_birthday = datetime_convert('UTC','UTC',$record['data']['profile']['next_birthday']);
@@ -350,7 +356,7 @@ class Libzot {
);
if($r) {
-
+logger('4');
// connection exists
// if the dob is the same as what we have stored (disregarding the year), keep the one
@@ -379,14 +385,16 @@ class Libzot {
else {
$p = Permissions::connect_perms($channel['channel_id']);
- $my_perms = Permissions::serialise($p['perms']);
+ $my_perms = $p['perms'];
$automatic = $p['automatic'];
// new connection
if($my_perms) {
- set_abconfig($channel['channel_id'],$x['hash'],'system','my_perms',$my_perms);
+ foreach($my_perms as $k => $v) {
+ set_abconfig($channel['channel_id'],$x['hash'],'my_perms',$k,$v);
+ }
}
$closeness = get_pconfig($channel['channel_id'],'system','new_abook_closeness');
@@ -409,7 +417,7 @@ class Libzot {
if($y) {
logger("New introduction received for {$channel['channel_name']}");
- $new_perms = get_all_perms($channel['channel_id'],$x['hash']);
+ $new_perms = get_all_perms($channel['channel_id'],$x['hash'],false);
// Send a clone sync packet and a permissions update if permissions have changed
@@ -425,7 +433,7 @@ class Libzot {
[
'type' => NOTIFY_INTRO,
'from_xchan' => $x['hash'],
- 'to_xchan' => $channel['channel_hash'],
+ 'to_xchan' => $channel['channel_portable_id'],
'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id']
]
);
@@ -776,7 +784,7 @@ class Libzot {
// see if this is a channel clone that's hosted locally - which we treat different from other xchans/connections
- $local = q("select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1",
+ $local = q("select channel_account_id, channel_id from channel where channel_portable_id = '%s' limit 1",
dbesc($xchan_hash)
);
if($local) {
@@ -966,6 +974,7 @@ class Libzot {
}
$x = crypto_unencapsulate($x, get_config('system','prvkey'));
+
if(! is_array($x)) {
$x = json_decode($x,true);
}
@@ -1129,7 +1138,7 @@ class Libzot {
if($recip_arr) {
stringify_array_elms($recip_arr,true);
$recips = implode(',',$recip_arr);
- $r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) and channel_removed = 0 ");
+ $r = q("select channel_portable_id as hash from channel where channel_portable_id in ( " . $recips . " ) and channel_removed = 0 ");
}
if(! $r) {
@@ -1303,12 +1312,12 @@ class Libzot {
$r = [];
- $c = q("select channel_id, channel_hash from channel where channel_removed = 0");
+ $c = q("select channel_id, channel_portable_id from channel where channel_removed = 0");
if($c) {
foreach($c as $cc) {
if(perm_is_allowed($cc['channel_id'],$msg['sender'],$perm)) {
- $r[] = $cc['channel_hash'];
+ $r[] = $cc['channel_portable_id'];
}
}
}
@@ -1316,7 +1325,7 @@ class Libzot {
if($include_sys) {
$sys = get_sys_channel();
if($sys)
- $r[] = $sys['channel_hash'];
+ $r[] = $sys['channel_portable_id'];
}
@@ -1332,7 +1341,7 @@ class Libzot {
if($tag['type'] === 'Mention' && (strpos($tag['href'],z_root()) !== false)) {
$address = basename($tag['href']);
if($address) {
- $z = q("select channel_hash as hash from channel where channel_address = '%s'
+ $z = q("select channel_portable_id as hash from channel where channel_address = '%s'
and channel_removed = 0 limit 1",
dbesc($address)
);
@@ -1353,7 +1362,7 @@ class Libzot {
$thread_parent = self::find_parent($msg,$act);
if($thread_parent) {
- $z = q("select channel_hash as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) ",
+ $z = q("select channel_portable_id as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) ",
dbesc($thread_parent),
dbesc($thread_parent)
);
@@ -1427,7 +1436,7 @@ class Libzot {
* access checks.
*/
- if($sender === $channel['channel_hash'] && $arr['author_xchan'] === $channel['channel_hash'] && $arr['mid'] === $arr['parent_mid']) {
+ if($sender === $channel['channel_portable_id'] && $arr['author_xchan'] === $channel['channel_portable_id'] && $arr['mid'] === $arr['parent_mid']) {
$DR->update('self delivery ignored');
$result[] = $DR->get();
continue;
@@ -1709,7 +1718,7 @@ class Libzot {
$stored = (($item_result && $item_result['item']) ? $item_result['item'] : false);
if((is_array($stored)) && ($stored['id'] != $stored['parent'])
- && ($stored['author_xchan'] === $channel['channel_hash'])) {
+ && ($stored['author_xchan'] === $channel['channel_hash'] || $stored['author_xchan'] === $channel['channel_portable_id'])) {
retain_item($stored['item']['parent']);
}
@@ -1809,9 +1818,9 @@ class Libzot {
}
logger('FOF Activity received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG);
- logger('FOF Activity recipient: ' . $channel['channel_hash'], LOGGER_DATA, LOG_DEBUG);
+ logger('FOF Activity recipient: ' . $channel['channel_portable_id'], LOGGER_DATA, LOG_DEBUG);
- $result = self::process_delivery($arr['owner_xchan'],$arr, [ $channel['channel_hash'] ],false,false,true);
+ $result = self::process_delivery($arr['owner_xchan'],$arr, [ $channel['channel_portable_id'] ],false,false,true);
if ($result) {
$ret = array_merge($ret, $result);
}
@@ -2047,7 +2056,7 @@ class Libzot {
$DR = new DReport(z_root(),$sender,$d,$arr['mid']);
- $r = q("select * from channel where channel_hash = '%s' limit 1",
+ $r = q("select * from channel where channel_portable_id = '%s' limit 1",
dbesc($d['hash'])
);
@@ -2202,7 +2211,7 @@ class Libzot {
$loc = $locations[0];
- $r = q("select * from channel where channel_hash = '%s' limit 1",
+ $r = q("select * from channel where channel_portable_id = '%s' limit 1",
dbesc($sender_hash)
);
@@ -2210,7 +2219,7 @@ class Libzot {
return;
if($loc['url'] !== z_root()) {
- $x = q("update channel set channel_moved = '%s' where channel_hash = '%s' limit 1",
+ $x = q("update channel set channel_moved = '%s' where channel_portable_id = '%s' limit 1",
dbesc($loc['url']),
dbesc($sender_hash)
);
@@ -2246,7 +2255,7 @@ class Libzot {
static function encode_locations($channel) {
$ret = [];
- $x = self::get_hublocs($channel['channel_hash']);
+ $x = self::get_hublocs($channel['channel_portable_id']);
if($x && count($x)) {
foreach($x as $hub) {
@@ -2557,6 +2566,9 @@ class Libzot {
static function zotinfo($arr) {
+ logger('arr: ' . print_r($arr,true));
+
+
$ret = [];
$zhash = ((x($arr,'guid_hash')) ? $arr['guid_hash'] : '');
@@ -2593,13 +2605,13 @@ class Libzot {
$r = null;
if(strlen($zhash)) {
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
- where channel_hash = '%s' limit 1",
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
+ where channel_portable_id = '%s' limit 1",
dbesc($zhash)
);
}
elseif(strlen($zguid) && strlen($zguid_sig)) {
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
where channel_guid = '%s' and channel_guid_sig = '%s' limit 1",
dbesc($zguid),
dbesc($zguid_sig)
@@ -2607,7 +2619,7 @@ class Libzot {
}
elseif(strlen($zaddr)) {
if(strpos($zaddr,'[system]') === false) { /* normal address lookup */
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1",
dbesc($zaddr),
dbesc($zaddr)
@@ -2627,10 +2639,10 @@ class Libzot {
*
*/
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
where channel_system = 1 order by channel_id limit 1");
if(! $r) {
- $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash
+ $r = q("select channel.*, xchan.* from channel left join xchan on channel_portable_id = xchan_hash
where channel_removed = 0 order by channel_id limit 1");
}
}
@@ -2749,7 +2761,7 @@ class Libzot {
];
$ret['channel_role'] = get_pconfig($e['channel_id'],'system','permissions_role','custom');
- $ret['protocols'] = [ 'zot6' ];
+ $ret['protocols'] = [ 'zot', 'zot6' ];
$ret['searchable'] = $searchable;
$ret['adult_content'] = $adult_channel;
$ret['public_forum'] = $public_forum;
@@ -2774,7 +2786,7 @@ class Libzot {
if(! $ret['follow_url'])
$ret['follow_url'] = z_root() . '/follow?f=&url=%s';
- $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false);
+ $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false,false);
if($ztarget_hash) {
$permissions['connected'] = false;
diff --git a/Zotlabs/Lib/Zotfinger.php b/Zotlabs/Lib/Zotfinger.php
index 537e440d4..d094fdc8d 100644
--- a/Zotlabs/Lib/Zotfinger.php
+++ b/Zotlabs/Lib/Zotfinger.php
@@ -2,7 +2,7 @@
namespace Zotlabs\Lib;
-use Zotlabs\Web\HTTPSig;
+use Zotlabs\Zot6\HTTPSig;
class Zotfinger {
@@ -12,10 +12,19 @@ class Zotfinger {
return false;
}
- if($channel) {
+ $m = parse_url($resource);
+
+ $data = json_encode([ 'zot_token' => random_string() ]);
+
+ if($channel && $m) {
+
$headers = [
- 'Accept' => 'application/x-zot+json',
- 'X-Zot-Token' => random_string(),
+ 'Accept' => 'application/x-zot+json',
+ 'Content-Type' => 'application/x-zot+json',
+ 'X-Zot-Token' => random_string(),
+ 'Digest' => HTTPSig::generate_digest_header($data),
+ 'Host' => $m['host'],
+ '(request-target)' => 'post ' . get_request_string($resource)
];
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
}
@@ -27,7 +36,9 @@ class Zotfinger {
$redirects = 0;
- $x = z_fetch_url($resource,false,$redirects, [ 'headers' => $h ] );
+ $x = z_post_url($resource,$data,$redirects, [ 'headers' => $h ] );
+
+ logger('fetch: ' . print_r($x,true));
if($x['success']) {
@@ -39,6 +50,8 @@ class Zotfinger {
$result['data'] = json_decode(crypto_unencapsulate($result['data'],get_config('system','prvkey')),true);
}
+ logger('decrypted: ' . print_r($result,true));
+
return $result;
}
diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php
index f1537ed15..12d87885f 100644
--- a/Zotlabs/Module/Channel.php
+++ b/Zotlabs/Module/Channel.php
@@ -6,6 +6,8 @@ namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\PermissionDescription;
+use Zotlabs\Zot6\HTTPSig;
+use Zotlabs\Lib\Libzot;
require_once('include/items.php');
require_once('include/security.php');
@@ -44,6 +46,48 @@ class Channel extends Controller {
$channel = App::get_channel();
if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
+ $which = $channel['channel_address'];
+ $profile = argv(1);
+ }
+
+ $channel = channelx_by_nick($which);
+ if(! $channel) {
+ http_status_exit(404, 'Not found');
+ }
+
+ // handle zot6 channel discovery
+
+ if(Libzot::is_zot_request()) {
+
+ $sigdata = HTTPSig::verify(file_get_contents('php://input'));
+
+ if($sigdata && $sigdata['signer'] && $sigdata['header_valid']) {
+ $data = json_encode(Libzot::zotinfo([ 'address' => $channel['channel_address'], 'target_url' => $sigdata['signer'] ]));
+ $s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1",
+ dbesc($sigdata['signer'])
+ );
+
+ if($s) {
+ $data = json_encode(crypto_encapsulate($data,$s[0]['hubloc_sitekey'],Libzot::best_algorithm($s[0]['site_crypto'])));
+ }
+ }
+ else {
+ $data = json_encode(Libzot::zotinfo([ 'address' => $channel['channel_address'] ]));
+ }
+
+ $headers = [
+ 'Content-Type' => 'application/x-zot+json',
+ 'Digest' => HTTPSig::generate_digest_header($data),
+ '(request-target)' => strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']
+ ];
+ $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel));
+ HTTPSig::set_headers($h);
+ echo $data;
+ killme();
+ }
+
+
+ if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) {
$which = $channel['channel_address'];
$profile = argv(1);
}
diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php
index 3d7ee449a..a9f643306 100644
--- a/Zotlabs/Module/Connedit.php
+++ b/Zotlabs/Module/Connedit.php
@@ -8,6 +8,7 @@ namespace Zotlabs\Module;
*/
use Zotlabs\Lib\Apps;
+use Zotlabs\Lib\Libzot;
require_once('include/socgraph.php');
require_once('include/selectors.php');
@@ -475,6 +476,10 @@ class Connedit extends \Zotlabs\Web\Controller {
if(! zot_refresh($orig_record[0],\App::get_channel()))
notice( t('Refresh failed - channel is currently unavailable.') );
}
+ elseif($orig_record[0]['xchan_network'] === 'zot6') {
+ if(! Libzot::refresh($orig_record[0],\App::get_channel()))
+ notice( t('Refresh failed - channel is currently unavailable.') );
+ }
else {
// if you are on a different network we'll force a refresh of the connection basic info
diff --git a/Zotlabs/Module/Dreport.php b/Zotlabs/Module/Dreport.php
index 76e07b147..16ae7941f 100644
--- a/Zotlabs/Module/Dreport.php
+++ b/Zotlabs/Module/Dreport.php
@@ -17,9 +17,17 @@ class Dreport extends \Zotlabs\Web\Controller {
$mid = ((argc() > 1) ? argv(1) : '');
+ if(strpos($mid,'b64.') === 0)
+ $mid = @base64url_decode(substr($mid,4));
+
+
if($mid === 'push') {
$table = 'push';
$mid = ((argc() > 2) ? argv(2) : '');
+
+ if(strpos($mid,'b64.') === 0)
+ $mid = @base64url_decode(substr($mid,4));
+
if($mid) {
$i = q("select id from item where mid = '%s' and uid = %d and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ",
dbesc($mid),
@@ -38,6 +46,9 @@ class Dreport extends \Zotlabs\Web\Controller {
if($mid === 'mail') {
$table = 'mail';
$mid = ((argc() > 2) ? argv(2) : '');
+ if(strpos($mid,'b64.') === 0)
+ $mid = @base64url_decode(substr($mid,4));
+
}
@@ -80,7 +91,6 @@ class Dreport extends \Zotlabs\Web\Controller {
}
for($x = 0; $x < count($r); $x++ ) {
- $r[$x]['name'] = escape_tags(substr($r[$x]['dreport_recip'],strpos($r[$x]['dreport_recip'],' ')));
// This has two purposes: 1. make the delivery report strings translateable, and
// 2. assign an ordering to item delivery results so we can group them and provide
@@ -138,14 +148,14 @@ class Dreport extends \Zotlabs\Web\Controller {
$entries = array();
foreach($r as $rr) {
$entries[] = [
- 'name' => $rr['name'],
+ 'name' => escape_tags($rr['dreport_name'] ?: $rr['dreport_recip']),
'result' => escape_tags($rr['dreport_result']),
'time' => escape_tags(datetime_convert('UTC',date_default_timezone_get(),$rr['dreport_time']))
];
}
$o = replace_macros(get_markup_template('dreport.tpl'), array(
- '$title' => sprintf( t('Delivery report for %1$s'),substr($mid,0,32)) . '...',
+ '$title' => sprintf( t('Delivery report for %1$s'),basename($mid)) . '...',
'$table' => $table,
'$mid' => urlencode($mid),
'$options' => t('Options'),
@@ -162,9 +172,9 @@ class Dreport extends \Zotlabs\Web\Controller {
private static function dreport_gravity_sort($a,$b) {
if($a['gravity'] == $b['gravity']) {
- if($a['name'] === $b['name'])
+ if($a['dreport_name'] === $b['dreport_name'])
return strcmp($a['dreport_time'],$b['dreport_time']);
- return strcmp($a['name'],$b['name']);
+ return strcmp($a['dreport_name'],$b['dreport_name']);
}
return (($a['gravity'] > $b['gravity']) ? 1 : (-1));
}
diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php
index 2ee639874..464daa516 100644
--- a/Zotlabs/Module/Item.php
+++ b/Zotlabs/Module/Item.php
@@ -392,6 +392,7 @@ class Item extends \Zotlabs\Web\Controller {
$verb = $orig_post['verb'];
$app = $orig_post['app'];
$title = escape_tags(trim($_REQUEST['title']));
+ $summary = trim($_REQUEST['summary']);
$body = trim($_REQUEST['body']);
$item_flags = $orig_post['item_flags'];
@@ -454,6 +455,7 @@ class Item extends \Zotlabs\Web\Controller {
$coord = notags(trim($_REQUEST['coord']));
$verb = notags(trim($_REQUEST['verb']));
$title = escape_tags(trim($_REQUEST['title']));
+ $summary = trim($_REQUEST['summary']);
$body = trim($_REQUEST['body']);
$body .= trim($_REQUEST['attachment']);
$postopts = '';
@@ -505,12 +507,14 @@ class Item extends \Zotlabs\Web\Controller {
&& ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false);
if($preview) {
+ $summary = z_input_filter($summary,$mimetype,$execflag);
$body = z_input_filter($body,$mimetype,$execflag);
}
- $arr = [ 'profile_uid' => $profile_uid, 'content' => $body, 'mimetype' => $mimetype ];
+ $arr = [ 'profile_uid' => $profile_uid, 'summary' => $summary, 'content' => $body, 'mimetype' => $mimetype ];
call_hooks('post_content',$arr);
+ $summary = $arr['summary'];
$body = $arr['content'];
$mimetype = $arr['mimetype'];
@@ -531,9 +535,23 @@ class Item extends \Zotlabs\Web\Controller {
// we may need virtual or template classes to implement the possible alternatives
+ if(strpos($body,'[/summary]') !== false) {
+ $match = '';
+ $cnt = preg_match("/\[summary\](.*?)\[\/summary\]/ism",$body,$match);
+ if($cnt) {
+ $summary .= $match[1];
+ }
+ $body_content = preg_replace("/^(.*?)\[summary\](.*?)\[\/summary\](.*?)$/ism", '',$body);
+ $body = trim($body_content);
+ }
+
+ $summary = cleanup_bbcode($summary);
+
$body = cleanup_bbcode($body);
// Look for tags and linkify them
+
+ $results = linkify_tags($a, $summary, ($uid) ? $uid : $profile_uid);
$results = linkify_tags($a, $body, ($uid) ? $uid : $profile_uid);
if($results) {
@@ -579,6 +597,9 @@ class Item extends \Zotlabs\Web\Controller {
if(! $preview) {
fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny);
+ fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($summary,'[/crypt]')) ? $_POST['media_str'] : $summary),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny);
+
+
fix_attached_file_permissions($channel,$observer['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny);
}
@@ -711,7 +732,8 @@ class Item extends \Zotlabs\Web\Controller {
$notify_type = (($parent) ? 'comment-new' : 'wall-new' );
if(! $mid) {
- $mid = (($message_id) ? $message_id : item_message_id());
+ $uuid = (($message_id) ? $message_id : item_message_id());
+ $mid = z_root() . '/item/' . $uuid;
}
@@ -766,6 +788,7 @@ class Item extends \Zotlabs\Web\Controller {
$datarray['aid'] = $channel['channel_account_id'];
$datarray['uid'] = $profile_uid;
+ $datarray['uuid'] = $uuid;
$datarray['owner_xchan'] = (($owner_hash) ? $owner_hash : $owner_xchan['xchan_hash']);
$datarray['author_xchan'] = $observer['xchan_hash'];
$datarray['created'] = $created;
@@ -778,6 +801,7 @@ class Item extends \Zotlabs\Web\Controller {
$datarray['parent_mid'] = $parent_mid;
$datarray['mimetype'] = $mimetype;
$datarray['title'] = $title;
+ $datarray['summary'] = $summary;
$datarray['body'] = $body;
$datarray['app'] = $app;
$datarray['location'] = $location;
diff --git a/Zotlabs/Module/Wfinger.php b/Zotlabs/Module/Wfinger.php
index 1866bce40..e4591df12 100644
--- a/Zotlabs/Module/Wfinger.php
+++ b/Zotlabs/Module/Wfinger.php
@@ -205,6 +205,12 @@ class Wfinger extends \Zotlabs\Web\Controller {
],
[
+ 'rel' => 'http://purl.org/zot/protocol/6.0',
+ 'type' => 'application/x-zot+json',
+ 'href' => channel_url($r[0])
+ ],
+
+ [
'rel' => 'http://purl.org/openwebauth/v1',
'type' => 'application/x-zot+json',
'href' => z_root() . '/owa',
diff --git a/Zotlabs/Update/_1226.php b/Zotlabs/Update/_1226.php
new file mode 100644
index 000000000..6e5a0e319
--- /dev/null
+++ b/Zotlabs/Update/_1226.php
@@ -0,0 +1,78 @@
+<?php
+
+namespace Zotlabs\Update;
+
+use Zotlabs\Lib\Libzot;
+
+class _1226 {
+
+ function run() {
+
+ q("START TRANSACTION");
+
+ if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
+ $r1 = q("ALTER TABLE channel ADD channel_portable_id text NOT NULL DEFAULT '' ");
+ $r2 = q("create index \"channel_portable_id_idx\" on channel (\"channel_portable_id\")");
+
+ $r = ($r1 && $r2);
+ }
+ else {
+ $r = q("ALTER TABLE `channel` ADD `channel_portable_id` char(191) NOT NULL DEFAULT '' ,
+ ADD INDEX `channel_portable_id` (`channel_portable_id`)");
+ }
+
+ if($r) {
+ q("COMMIT");
+ self::upgrade();
+ return UPDATE_SUCCESS;
+ }
+
+ q("ROLLBACK");
+ return UPDATE_FAILED;
+ }
+
+
+ static function upgrade() {
+
+ $r = q("select * from channel where channel_portable_id = '' ");
+
+ if($r) {
+ foreach($r as $rv) {
+
+ $zhash = Libzot::make_xchan_hash($rv['channel_guid'],$rv['channel_pubkey']);
+ q("update channel set channel_portable_id = '%s' where channel_id = %d",
+ dbesc($zhash),
+ intval($rv['channel_id'])
+ );
+ $x = q("select * from xchan where xchan_hash = '%s' limit 1",
+ dbesc($rv['channel_hash'])
+ );
+ if($x) {
+ $rec = $x[0];
+ $rec['xchan_hash'] = $zhash;
+ $rec['xchan_guid_sig'] = 'sha256.' . $rec['xchan_guid_sig'];
+ $rec['xchan_network'] = 'zot6';
+
+ xchan_store_lowlevel($rec);
+ }
+ $x = q("select * from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' limit 1",
+ dbesc($rv['channel_hash']),
+ dbesc(z_root())
+ );
+ if($x) {
+ $rec = $x[0];
+ $rec['hubloc_hash'] = $zhash;
+ $rec['hubloc_guid_sig'] = 'sha256.' . $rec['hubloc_guid_sig'];
+ $rec['hubloc_network'] = 'zot6';
+ $rec['hubloc_url_sig'] = 'sha256.' . $rec['hubloc_url_sig'];
+ $rec['hubloc_callback'] = z_root() . '/zot';
+ $rec['hubloc_id_url'] = channel_url($rv);
+ $rec['hubloc_site_id'] = Libzot::make_xchan_hash(z_root(),get_config('system','pubkey'));
+ hubloc_store_lowlevel($rec);
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/Zotlabs/Update/_1227.php b/Zotlabs/Update/_1227.php
new file mode 100644
index 000000000..b5dbb2286
--- /dev/null
+++ b/Zotlabs/Update/_1227.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Zotlabs\Update;
+
+
+class _1227 {
+
+ function run() {
+
+ q("START TRANSACTION");
+
+ if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
+ $r = q("ALTER TABLE dreport ADD dreport_name text NOT NULL DEFAULT '' ");
+ }
+ else {
+ $r = q("ALTER TABLE `dreport` ADD `dreport_name` char(191) NOT NULL DEFAULT ''");
+ }
+
+ if($r) {
+ q("COMMIT");
+ return UPDATE_SUCCESS;
+ }
+
+ q("ROLLBACK");
+ return UPDATE_FAILED;
+ }
+
+}
+
+
diff --git a/Zotlabs/Update/_1228.php b/Zotlabs/Update/_1228.php
new file mode 100644
index 000000000..b9ba1d86f
--- /dev/null
+++ b/Zotlabs/Update/_1228.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Zotlabs\Update;
+
+
+class _1228 {
+
+ function run() {
+
+ q("START TRANSACTION");
+
+ if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
+ $r1 = q("ALTER TABLE item ADD uuid text NOT NULL DEFAULT '' ");
+ $r2 = q("create index \"uuid_idx\" on channel (\"uuid\")");
+ $r3 = q("ALTER TABLE item add summary TEXT NOT NULL");
+
+ $r = ($r1 && $r2 && $r3);
+ }
+ else {
+ $r1 = q("ALTER TABLE `item` ADD `uuid` char(191) NOT NULL DEFAULT '' ,
+ ADD INDEX `uuid` (`uuid`)");
+ $r2 = q("ALTER TABLE `item` ADD `summary` mediumtext NOT NULL");
+ $r = ($r1 && $r2);
+ }
+
+ if($r) {
+ q("COMMIT");
+ self::upgrade();
+ return UPDATE_SUCCESS;
+ }
+
+ q("ROLLBACK");
+ return UPDATE_FAILED;
+ }
+
+}
+
diff --git a/Zotlabs/Zot6/HTTPSig.php b/Zotlabs/Zot6/HTTPSig.php
index a0f0d3500..72785b1e9 100644
--- a/Zotlabs/Zot6/HTTPSig.php
+++ b/Zotlabs/Zot6/HTTPSig.php
@@ -48,12 +48,14 @@ class HTTPSig {
$h = new HTTPHeaders($data['header']);
$headers = $h->fetcharr();
$body = $data['body'];
+ $headers['(request-target)'] = $data['request_target'];
}
else {
$headers = [];
$headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'];
$headers['content-type'] = $_SERVER['CONTENT_TYPE'];
+ $headers['content-length'] = $_SERVER['CONTENT_LENGTH'];
foreach($_SERVER as $k => $v) {
if(strpos($k,'HTTP_') === 0) {
@@ -121,6 +123,17 @@ class HTTPSig {
if(array_key_exists($h,$headers)) {
$signed_data .= $h . ': ' . $headers[$h] . "\n";
}
+ if($h === 'date') {
+ $d = new \DateTime($headers[$h]);
+ $d->setTimeZone(new \DateTimeZone('UTC'));
+ $dplus = datetime_convert('UTC','UTC','now + 1 day');
+ $dminus = datetime_convert('UTC','UTC','now - 1 day');
+ $c = $d->format('Y-m-d H:i:s');
+ if($c > $dplus || $c < $dminus) {
+ logger('bad time: ' . $c);
+ return $result;
+ }
+ }
}
$signed_data = rtrim($signed_data,"\n");
@@ -147,8 +160,15 @@ class HTTPSig {
logger('verified: ' . $x, LOGGER_DEBUG);
- if(! $x)
+ if(! $x) {
+ logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($key['public_key']) ? '' : ' no key'));
+ $sig_block['signature'] = base64_encode($sig_block['signature']);
+ logger('affected sigblock: ' . print_r($sig_block,true));
+ logger('signed_data: ' . print_r($signed_data,true));
+ logger('headers: ' . print_r($headers,true));
+ logger('server: ' . print_r($_SERVER,true));
return $result;
+ }
$result['portable_id'] = $key['portable_id'];
$result['header_valid'] = true;
@@ -180,7 +200,9 @@ class HTTPSig {
return [ 'public_key' => $key ];
}
- $key = self::get_webfinger_key($id);
+ if(strpos($id,'#') === false) {
+ $key = self::get_webfinger_key($id);
+ }
if(! $key) {
$key = self::get_activitystreams_key($id);
@@ -216,25 +238,29 @@ class HTTPSig {
function get_activitystreams_key($id) {
+ // remove fragment
+
+ $url = ((strpos($id,'#')) ? substr($id,0,strpos($id,'#')) : $id);
+
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
- dbesc(str_replace('acct:','',$id)),
- dbesc($id)
+ dbesc(str_replace('acct:','',$url)),
+ dbesc($url)
);
if($x && $x[0]['xchan_pubkey']) {
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
}
- $r = ActivityStreams::fetch_property($id);
+ $r = ActivityStreams::fetch($id);
if($r) {
- if(array_key_exists('publicKey',$j) && array_key_exists('publicKeyPem',$j['publicKey']) && array_key_exists('id',$j['publicKey'])) {
- if($j['publicKey']['id'] === $id || $j['id'] === $id) {
- return [ 'public_key' => self::convertKey($j['publicKey']['publicKeyPem']), 'portable_id' => '', 'hubloc' => [] ];
+ if(array_key_exists('publicKey',$r) && array_key_exists('publicKeyPem',$r['publicKey']) && array_key_exists('id',$r['publicKey'])) {
+ if($r['publicKey']['id'] === $id || $r['id'] === $id) {
+ $portable_id = ((array_key_exists('owner',$r['publicKey'])) ? $r['publicKey']['owner'] : EMPTY_STR);
+ return [ 'public_key' => self::convertKey($r['publicKey']['publicKeyPem']), 'portable_id' => $portable_id, 'hubloc' => [] ];
}
}
}
-
return false;
}
@@ -409,6 +435,8 @@ class HTTPSig {
$headers = '';
$fields = '';
+ logger('signing: ' . print_r($head,true), LOGGER_DATA);
+
if($head) {
foreach($head as $k => $v) {
$headers .= strtolower($k) . ': ' . trim($v) . "\n";
diff --git a/Zotlabs/Zot6/Receiver.php b/Zotlabs/Zot6/Receiver.php
index 4f26e2b0c..66559c9a5 100644
--- a/Zotlabs/Zot6/Receiver.php
+++ b/Zotlabs/Zot6/Receiver.php
@@ -4,7 +4,7 @@ namespace Zotlabs\Zot6;
use Zotlabs\Lib\Config;
use Zotlabs\Lib\Libzot;
-use Zotlabs\Web\HTTPSig;
+
class Receiver {
diff --git a/Zotlabs/Zot6/Zot6Handler.php b/Zotlabs/Zot6/Zot6Handler.php
index 5597921cc..e320e7825 100644
--- a/Zotlabs/Zot6/Zot6Handler.php
+++ b/Zotlabs/Zot6/Zot6Handler.php
@@ -70,9 +70,10 @@ class Zot6Handler implements IHandler {
// This would be a permissions update, typically for one connection
foreach ($recipients as $recip) {
+
$r = q("select channel.*,xchan.* from channel
- left join xchan on channel_hash = xchan_hash
- where channel_hash ='%s' limit 1",
+ left join xchan on channel_portable_id = xchan_hash
+ where xchan_hash ='%s' limit 1",
dbesc($recip)
);
@@ -140,7 +141,7 @@ class Zot6Handler implements IHandler {
$arr = $data['recipients'][0];
- $c = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_hash = '%s' limit 1",
+ $c = q("select * from channel left join xchan on channel_portable_id = xchan_hash where channel_portable_id = '%s' limit 1",
dbesc($arr['portable_id'])
);
if (! $c) {
@@ -230,8 +231,8 @@ class Zot6Handler implements IHandler {
// basically this means "unfriend"
foreach ($recipients as $recip) {
$r = q("select channel.*,xchan.* from channel
- left join xchan on channel_hash = xchan_hash
- where channel_hash = '%s' and channel_guid_sig = '%s' limit 1",
+ left join xchan on channel_portable_id = xchan_hash
+ where channel_portable_id = '%s' limit 1",
dbesc($recip)
);
if ($r) {
diff --git a/include/channel.php b/include/channel.php
index 22cdb9fe7..1e5570f6b 100644
--- a/include/channel.php
+++ b/include/channel.php
@@ -10,6 +10,7 @@ use Zotlabs\Access\Permissions;
use Zotlabs\Daemon\Master;
use Zotlabs\Lib\System;
use Zotlabs\Render\Comanche;
+use Zotlabs\Lib\Libzot;
require_once('include/zot.php');
require_once('include/crypto.php');
@@ -232,6 +233,7 @@ function create_identity($arr) {
$sig = base64url_encode(rsa_sign($guid,$key['prvkey']));
$hash = make_xchan_hash($guid,$sig);
+ $zhash = Libzot::make_xchan_hash($guid,$key['pubkey']);
// Force a few things on the short term until we can provide a theme or app with choice
@@ -265,6 +267,7 @@ function create_identity($arr) {
'channel_guid' => $guid,
'channel_guid_sig' => $sig,
'channel_hash' => $hash,
+ 'channel_portable_id' => $zhash,
'channel_prvkey' => $key['prvkey'],
'channel_pubkey' => $key['pubkey'],
'channel_pageflags' => intval($pageflags),
@@ -345,30 +348,76 @@ function create_identity($arr) {
if(! $r)
logger('Unable to store hub location');
+ $r = hubloc_store_lowlevel(
+ [
+ 'hubloc_guid' => $guid,
+ 'hubloc_guid_sig' => 'sha256.' . $sig,
+ 'hubloc_hash' => $zhash,
+ 'hubloc_id_url' => channel_url($ret['channel']),
+ 'hubloc_addr' => channel_reddress($ret['channel']),
+ 'hubloc_primary' => intval($primary),
+ 'hubloc_url' => z_root(),
+ 'hubloc_url_sig' => 'sha256.' . base64url_encode(rsa_sign(z_root(),$ret['channel']['channel_prvkey'])),
+ 'hubloc_site_id' => Libzot::make_xchan_hash(z_root(),get_config('system','pubkey')),
+ 'hubloc_host' => App::get_hostname(),
+ 'hubloc_callback' => z_root() . '/zot',
+ 'hubloc_sitekey' => get_config('system','pubkey'),
+ 'hubloc_network' => 'zot6',
+ 'hubloc_updated' => datetime_convert()
+ ]
+ );
+ if(! $r)
+ logger('Unable to store hub location');
+
+
$newuid = $ret['channel']['channel_id'];
$r = xchan_store_lowlevel(
[
- 'xchan_hash' => $hash,
- 'xchan_guid' => $guid,
- 'xchan_guid_sig' => $sig,
- 'xchan_pubkey' => $key['pubkey'],
+ 'xchan_hash' => $hash,
+ 'xchan_guid' => $guid,
+ 'xchan_guid_sig' => $sig,
+ 'xchan_pubkey' => $key['pubkey'],
'xchan_photo_mimetype' => (($photo_type) ? $photo_type : 'image/png'),
- 'xchan_photo_l' => z_root() . "/photo/profile/l/{$newuid}",
- 'xchan_photo_m' => z_root() . "/photo/profile/m/{$newuid}",
- 'xchan_photo_s' => z_root() . "/photo/profile/s/{$newuid}",
- 'xchan_addr' => channel_reddress($ret['channel']),
- 'xchan_url' => z_root() . '/channel/' . $ret['channel']['channel_address'],
- 'xchan_follow' => z_root() . '/follow?f=&url=%s',
- 'xchan_connurl' => z_root() . '/poco/' . $ret['channel']['channel_address'],
- 'xchan_name' => $ret['channel']['channel_name'],
- 'xchan_network' => 'zot',
- 'xchan_photo_date' => datetime_convert(),
- 'xchan_name_date' => datetime_convert(),
- 'xchan_system' => $system
+ 'xchan_photo_l' => z_root() . "/photo/profile/l/{$newuid}",
+ 'xchan_photo_m' => z_root() . "/photo/profile/m/{$newuid}",
+ 'xchan_photo_s' => z_root() . "/photo/profile/s/{$newuid}",
+ 'xchan_addr' => channel_reddress($ret['channel']),
+ 'xchan_url' => z_root() . '/channel/' . $ret['channel']['channel_address'],
+ 'xchan_follow' => z_root() . '/follow?f=&url=%s',
+ 'xchan_connurl' => z_root() . '/poco/' . $ret['channel']['channel_address'],
+ 'xchan_name' => $ret['channel']['channel_name'],
+ 'xchan_network' => 'zot',
+ 'xchan_photo_date' => datetime_convert(),
+ 'xchan_name_date' => datetime_convert(),
+ 'xchan_system' => $system
]
);
+ $r = xchan_store_lowlevel(
+ [
+ 'xchan_hash' => $zhash,
+ 'xchan_guid' => $guid,
+ 'xchan_guid_sig' => 'sha256.' . $sig,
+ 'xchan_pubkey' => $key['pubkey'],
+ 'xchan_photo_mimetype' => (($photo_type) ? $photo_type : 'image/png'),
+ 'xchan_photo_l' => z_root() . "/photo/profile/l/{$newuid}",
+ 'xchan_photo_m' => z_root() . "/photo/profile/m/{$newuid}",
+ 'xchan_photo_s' => z_root() . "/photo/profile/s/{$newuid}",
+ 'xchan_addr' => channel_reddress($ret['channel']),
+ 'xchan_url' => z_root() . '/channel/' . $ret['channel']['channel_address'],
+ 'xchan_follow' => z_root() . '/follow?f=&url=%s',
+ 'xchan_connurl' => z_root() . '/poco/' . $ret['channel']['channel_address'],
+ 'xchan_name' => $ret['channel']['channel_name'],
+ 'xchan_network' => 'zot6',
+ 'xchan_photo_date' => datetime_convert(),
+ 'xchan_name_date' => datetime_convert(),
+ 'xchan_system' => $system
+ ]
+ );
+
+
+
// Not checking return value.
// It's ok for this to fail if it's an imported channel, and therefore the hash is a duplicate
@@ -2355,6 +2404,7 @@ function channel_store_lowlevel($arr) {
'channel_guid' => ((array_key_exists('channel_guid',$arr)) ? $arr['channel_guid'] : ''),
'channel_guid_sig' => ((array_key_exists('channel_guid_sig',$arr)) ? $arr['channel_guid_sig'] : ''),
'channel_hash' => ((array_key_exists('channel_hash',$arr)) ? $arr['channel_hash'] : ''),
+ 'channel_portable_id' => ((array_key_exists('channel_portable_id',$arr)) ? $arr['channel_portable_id'] : ''),
'channel_timezone' => ((array_key_exists('channel_timezone',$arr)) ? $arr['channel_timezone'] : 'UTC'),
'channel_location' => ((array_key_exists('channel_location',$arr)) ? $arr['channel_location'] : ''),
'channel_theme' => ((array_key_exists('channel_theme',$arr)) ? $arr['channel_theme'] : ''),
diff --git a/include/crypto.php b/include/crypto.php
index 1040ac29b..fc1029e55 100644
--- a/include/crypto.php
+++ b/include/crypto.php
@@ -225,9 +225,14 @@ function crypto_unencapsulate($data,$prvkey) {
if(! $data)
return;
- $alg = ((array_key_exists('alg',$data)) ? $data['alg'] : 'aes256cbc');
- if($alg === 'aes256cbc')
+ $alg = ((is_array($data) && array_key_exists('encrypted',$data)) ? $data['alg'] : '');
+ if(! $alg) {
+ return $data;
+ }
+
+ if($alg === 'aes256cbc') {
return aes_unencapsulate($data,$prvkey);
+ }
return other_unencapsulate($data,$prvkey,$alg);
diff --git a/include/items.php b/include/items.php
index cae380b01..3d707a492 100755
--- a/include/items.php
+++ b/include/items.php
@@ -393,7 +393,11 @@ function post_activity_item($arr, $allow_code = false, $deliver = true) {
if(! array_key_exists('mimetype',$arr))
$arr['mimetype'] = 'text/bbcode';
- $arr['mid'] = ((x($arr,'mid')) ? $arr['mid'] : item_message_id());
+
+ if(! $arr['mid']) {
+ $arr['uuid'] = ((x($arr,'uuid')) ? $arr['uuid'] : item_message_id());
+ }
+ $arr['mid'] = ((x($arr,'mid')) ? $arr['mid'] : z_root() . '/item/' . $arr['uuid']);
$arr['parent_mid'] = ((x($arr,'parent_mid')) ? $arr['parent_mid'] : $arr['mid']);
$arr['thr_parent'] = ((x($arr,'thr_parent')) ? $arr['thr_parent'] : $arr['mid']);
@@ -597,6 +601,7 @@ function get_item_elements($x,$allow_code = false) {
$arr = array();
$arr['body'] = $x['body'];
+ $arr['summary'] = $x['summary'];
$maxlen = get_max_import_size();
@@ -605,6 +610,11 @@ function get_item_elements($x,$allow_code = false) {
logger('get_item_elements: message length exceeds max_import_size: truncated');
}
+ if($maxlen && mb_strlen($arr['summary']) > $maxlen) {
+ $arr['summary'] = mb_substr($arr['summary'],0,$maxlen,'UTF-8');
+ logger('get_item_elements: message summary length exceeds max_import_size: truncated');
+ }
+
$arr['created'] = datetime_convert('UTC','UTC',$x['created']);
$arr['edited'] = datetime_convert('UTC','UTC',$x['edited']);
@@ -629,6 +639,7 @@ function get_item_elements($x,$allow_code = false) {
if(mb_strlen($arr['title']) > 255)
$arr['title'] = mb_substr($arr['title'],0,255);
+ $arr['uuid'] = (($x['uuid']) ? htmlspecialchars($x['uuid'], ENT_COMPAT,'UTF-8',false) : '');
$arr['app'] = (($x['app']) ? htmlspecialchars($x['app'], ENT_COMPAT,'UTF-8',false) : '');
$arr['route'] = (($x['route']) ? htmlspecialchars($x['route'], ENT_COMPAT,'UTF-8',false) : '');
$arr['mid'] = (($x['message_id']) ? htmlspecialchars($x['message_id'], ENT_COMPAT,'UTF-8',false) : '');
@@ -749,9 +760,10 @@ function get_item_elements($x,$allow_code = false) {
// Do this after signature checking as the original signature
// was generated on the escaped content.
- if($arr['mimetype'] === 'text/markdown')
+ if($arr['mimetype'] === 'text/markdown') {
+ $arr['summary'] = MarkdownSoap::unescape($arr['summary']);
$arr['body'] = MarkdownSoap::unescape($arr['body']);
-
+ }
if(array_key_exists('revision',$x)) {
// extended export encoding
@@ -1063,6 +1075,7 @@ function encode_item($item,$mirror = false) {
$x['item_blocked'] = $item['item_blocked'];
}
+ $x['uuid'] = $item['uuid'];
$x['message_id'] = $item['mid'];
$x['message_top'] = $item['parent_mid'];
$x['message_parent'] = $item['thr_parent'];
@@ -1073,6 +1086,7 @@ function encode_item($item,$mirror = false) {
$x['commented'] = $item['commented'];
$x['mimetype'] = $item['mimetype'];
$x['title'] = $item['title'];
+ $x['summary'] = $item['summary'];
$x['body'] = $item['body'];
$x['app'] = $item['app'];
$x['verb'] = $item['verb'];
@@ -1631,6 +1645,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
}
$arr['title'] = ((array_key_exists('title',$arr) && strlen($arr['title'])) ? trim($arr['title']) : '');
+ $arr['summary'] = ((array_key_exists('summary',$arr) && strlen($arr['summary'])) ? trim($arr['summary']) : '');
$arr['body'] = ((array_key_exists('body',$arr) && strlen($arr['body'])) ? trim($arr['body']) : '');
$arr['allow_cid'] = ((x($arr,'allow_cid')) ? trim($arr['allow_cid']) : '');
@@ -1639,6 +1654,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
$arr['deny_gid'] = ((x($arr,'deny_gid')) ? trim($arr['deny_gid']) : '');
$arr['postopts'] = ((x($arr,'postopts')) ? trim($arr['postopts']) : '');
$arr['route'] = ((x($arr,'route')) ? trim($arr['route']) : '');
+ $arr['uuid'] = ((x($arr,'uuid')) ? trim($arr['uuid']) : '');
$arr['item_private'] = ((x($arr,'item_private')) ? intval($arr['item_private']) : 0 );
$arr['item_wall'] = ((x($arr,'item_wall')) ? intval($arr['item_wall']) : 0 );
$arr['item_type'] = ((x($arr,'item_type')) ? intval($arr['item_type']) : 0 );
@@ -1651,6 +1667,7 @@ function item_store($arr, $allow_exec = false, $deliver = true) {
// apply the input filter here
+ $arr['summary'] = trim(z_input_filter($arr['summary'],$arr['mimetype'],$allow_exec));
$arr['body'] = trim(z_input_filter($arr['body'],$arr['mimetype'],$allow_exec));
item_sign($arr);
@@ -2096,6 +2113,7 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
// apply the input filter here
+ $arr['summary'] = trim(z_input_filter($arr['summary'],$arr['mimetype'],$allow_exec));
$arr['body'] = trim(z_input_filter($arr['body'],$arr['mimetype'],$allow_exec));
item_sign($arr);
@@ -2172,6 +2190,7 @@ function item_store_update($arr, $allow_exec = false, $deliver = true) {
$arr['route'] = ((array_key_exists('route',$arr)) ? trim($arr['route']) : $orig[0]['route']);
$arr['location'] = ((x($arr,'location')) ? notags(trim($arr['location'])) : $orig[0]['location']);
+ $arr['uuid'] = ((x($arr,'uuid')) ? notags(trim($arr['uuid'])) : $orig[0]['uuid']);
$arr['coord'] = ((x($arr,'coord')) ? notags(trim($arr['coord'])) : $orig[0]['coord']);
$arr['verb'] = ((x($arr,'verb')) ? notags(trim($arr['verb'])) : $orig[0]['verb']);
$arr['obj_type'] = ((x($arr,'obj_type')) ? notags(trim($arr['obj_type'])) : $orig[0]['obj_type']);
diff --git a/include/network.php b/include/network.php
index d37da05f7..183a47105 100644
--- a/include/network.php
+++ b/include/network.php
@@ -153,7 +153,7 @@ function z_fetch_url($url, $binary = false, $redirects = 0, $opts = array()) {
// Pull out multiple headers, e.g. proxy and continuation headers
// allow for HTTP/2.x without fixing code
- while(preg_match('/^HTTP\/[1-2].+? [1-5][0-9][0-9]/',$base)) {
+ while(preg_match('/^HTTP\/[1-3].+? [1-5][0-9][0-9]/',$base)) {
$chunk = substr($base,0,strpos($base,"\r\n\r\n")+4);
$header .= $chunk;
$base = substr($base,strlen($chunk));
@@ -319,7 +319,7 @@ function z_post_url($url, $params, $redirects = 0, $opts = array()) {
// Pull out multiple headers, e.g. proxy and continuation headers
// allow for HTTP/2.x without fixing code
- while(preg_match('/^HTTP\/[1-2].+? [1-5][0-9][0-9]/',$base)) {
+ while(preg_match('/^HTTP\/[1-3].+? [1-5][0-9][0-9]/',$base)) {
$chunk = substr($base,0,strpos($base,"\r\n\r\n")+4);
$header .= $chunk;
$base = substr($base,strlen($chunk));
diff --git a/include/queue_fn.php b/include/queue_fn.php
index f05bac5b0..f7e2922c6 100644
--- a/include/queue_fn.php
+++ b/include/queue_fn.php
@@ -1,5 +1,9 @@
<?php /** @file */
+use Zotlabs\Lib\Libzot;
+use Zotlabs\Zot6\Receiver;
+use Zotlabs\Zot6\Zot6Handler;
+
function update_queue_item($id, $add_priority = 0) {
logger('queue: requeue item ' . $id,LOGGER_DEBUG);
$x = q("select outq_created, outq_posturl from outq where outq_hash = '%s' limit 1",
@@ -226,37 +230,85 @@ function queue_deliver($outq, $immediate = false) {
logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG);
- $channel = null;
+ if($outq['outq_driver'] === 'zot6') {
+
+ if($outq['outq_posturl'] === z_root() . '/zot') {
+ // local delivery
+ $zot = new Receiver(new Zot6Handler(),$outq['outq_notify']);
+ $result = $zot->run(true);
+ logger('returned_json: ' . json_encode($result,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOGGER_DATA);
+ logger('deliver: local zot6 delivery succeeded to ' . $outq['outq_posturl']);
+ Libzot::process_response($outq['outq_posturl'],[ 'success' => true, 'body' => json_encode($result) ], $outq);
+ }
+ else {
+ logger('remote');
+ $channel = null;
+
+ if($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' and hubloc_network = 'zot6' order by hubloc_id desc limit 1",
+ dbesc($base)
+ );
+ if($h) {
+ $host_crypto = $h[0];
+ }
+ }
+
+ $msg = $outq['outq_notify'];
+
+ $result = Libzot::zot($outq['outq_posturl'],$msg,$channel,$host_crypto);
+
+ if($result['success']) {
+ logger('deliver: remote zot6 delivery succeeded to ' . $outq['outq_posturl']);
+ Libzot::process_response($outq['outq_posturl'],$result, $outq);
+ }
+ else {
+ logger('deliver: remote zot6 delivery failed to ' . $outq['outq_posturl']);
+ logger('deliver: remote zot6 delivery fail data: ' . print_r($result,true), LOGGER_DATA);
+ update_queue_item($outq['outq_hash'],10);
+ }
- if($outq['outq_msg'] && $outq['outq_channel']) {
- $channel = channelx_by_n($outq['outq_channel']);
+ }
+ return;
}
+ else {
- $host_crypto = null;
+ $channel = 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];
+ if($outq['outq_msg'] && $outq['outq_channel']) {
+ $channel = channelx_by_n($outq['outq_channel']);
}
- }
- $msg = $outq['outq_notify'];
+ $host_crypto = null;
- $result = zot_zot($outq['outq_posturl'],$msg,$channel,$host_crypto);
+ 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'];
- if($result['success']) {
- logger('deliver: remote zot delivery succeeded to ' . $outq['outq_posturl']);
- zot_process_response($outq['outq_posturl'],$result, $outq);
- }
- else {
- logger('deliver: remote zot delivery failed to ' . $outq['outq_posturl']);
- logger('deliver: remote zot delivery fail data: ' . print_r($result,true), LOGGER_DATA);
- update_queue_item($outq['outq_hash'],10);
+ $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);
+ }
+ else {
+ logger('deliver: remote zot delivery failed to ' . $outq['outq_posturl']);
+ logger('deliver: remote zot delivery fail data: ' . print_r($result,true), LOGGER_DATA);
+ update_queue_item($outq['outq_hash'],10);
+ }
+ return;
}
- return;
-}
+} \ No newline at end of file
diff --git a/include/text.php b/include/text.php
index 076c98407..646bfe749 100644
--- a/include/text.php
+++ b/include/text.php
@@ -3,8 +3,11 @@
* @file include/text.php
*/
-use \Zotlabs\Lib as Zlib;
-use \Michelf\MarkdownExtra;
+use Zotlabs\Lib as Zlib;
+
+use Michelf\MarkdownExtra;
+use Ramsey\Uuid\Uuid;
+use Ramsey\Uuid\Exception\UnsatisfiedDependencyException;
require_once("include/bbcode.php");
@@ -571,18 +574,9 @@ function alt_pager($i, $more = '', $less = '') {
* @return string a unique id
*/
function item_message_id() {
- do {
- $dups = false;
- $hash = random_string();
- $mid = $hash . '@' . App::get_hostname();
- $r = q("SELECT id FROM item WHERE mid = '%s' LIMIT 1",
- dbesc($mid));
- if($r)
- $dups = true;
- } while($dups == true);
+ return new_uuid();
- return $mid;
}
/**
@@ -593,17 +587,9 @@ function item_message_id() {
* @return string a uniqe hash
*/
function photo_new_resource() {
- do {
- $found = false;
- $resource = hash('md5', uniqid(mt_rand(), true));
- $r = q("SELECT id FROM photo WHERE resource_id = '%s' LIMIT 1",
- dbesc($resource));
- if($r)
- $found = true;
- } while($found === true);
+ return new_uuid();
- return $resource;
}
/**
@@ -3480,3 +3466,19 @@ function print_val($v) {
return $v;
}
+
+/**
+ * @brief Generate a unique ID.
+ *
+ * @return string
+ */
+function new_uuid() {
+
+ try {
+ $hash = Uuid::uuid4()->toString();
+ } catch (UnsatisfiedDependencyException $e) {
+ $hash = random_string(48);
+ }
+
+ return $hash;
+}
diff --git a/include/xchan.php b/include/xchan.php
index eb5f1b4a3..4cbfb42c5 100644
--- a/include/xchan.php
+++ b/include/xchan.php
@@ -5,6 +5,11 @@ use Zotlabs\Zot6\HTTPSig;
function xchan_store_lowlevel($arr) {
+ if(! $arr['xchan_hash']) {
+ logger('No xchan_hash');
+ return false;
+ }
+
$store = [
'xchan_hash' => ((array_key_exists('xchan_hash',$arr)) ? $arr['xchan_hash'] : ''),
'xchan_guid' => ((array_key_exists('xchan_guid',$arr)) ? $arr['xchan_guid'] : ''),
diff --git a/include/zot.php b/include/zot.php
index 49fc89e33..756a5bde6 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -8,6 +8,8 @@
*
*/
+use Zotlabs\Lib\DReport;
+
require_once('include/crypto.php');
require_once('include/items.php');
require_once('include/queue_fn.php');
@@ -1120,7 +1122,7 @@ function zot_process_response($hub, $arr, $outq) {
foreach($x['delivery_report'] as $xx) {
call_hooks('dreport_process',$xx);
- if(is_array($xx) && array_key_exists('message_id',$xx) && delivery_report_is_storable($xx)) {
+ if(is_array($xx) && array_key_exists('message_id',$xx) && DReport::is_storable($xx)) {
q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan ) values ( '%s', '%s','%s','%s','%s','%s' ) ",
dbesc($xx['message_id']),
dbesc($xx['location']),
@@ -1748,7 +1750,7 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
}
$channel = $r[0];
- $DR->addto_recipient($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
+ $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
/* blacklisted channels get a permission denied, no special message to tip them off */
@@ -2297,7 +2299,7 @@ function process_mail_delivery($sender, $arr, $deliveries) {
}
$channel = $r[0];
- $DR->addto_recipient($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
+ $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
/* blacklisted channels get a permission denied, no special message to tip them off */
@@ -3987,7 +3989,7 @@ function process_channel_sync_delivery($sender, $arr, $deliveries) {
if(array_key_exists('item',$arr) && is_array($arr['item'][0])) {
$DR = new Zotlabs\Lib\DReport(z_root(),$d['hash'],$d['hash'],$arr['item'][0]['message_id'],'channel sync processed');
- $DR->addto_recipient($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
+ $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>');
}
else
$DR = new Zotlabs\Lib\DReport(z_root(),$d['hash'],$d['hash'],'sync packet','channel sync delivered');
diff --git a/install/schema_mysql.sql b/install/schema_mysql.sql
index ef7e2a516..c820fca25 100644
--- a/install/schema_mysql.sql
+++ b/install/schema_mysql.sql
@@ -247,6 +247,7 @@ CREATE TABLE IF NOT EXISTS `channel` (
`channel_guid` char(191) NOT NULL DEFAULT '',
`channel_guid_sig` text NOT NULL,
`channel_hash` char(191) NOT NULL DEFAULT '',
+ `channel_portable_id` char(191) NOT NULL DEFAULT '',
`channel_timezone` char(128) NOT NULL DEFAULT 'UTC',
`channel_location` char(191) NOT NULL DEFAULT '',
`channel_theme` char(191) NOT NULL DEFAULT '',
@@ -306,6 +307,7 @@ CREATE TABLE IF NOT EXISTS `channel` (
KEY `channel_default_gid` (`channel_default_group`),
KEY `channel_guid` (`channel_guid`),
KEY `channel_hash` (`channel_hash`),
+ KEY `channel_portable_id` (`channel_portable_id`),
KEY `channel_expire_days` (`channel_expire_days`),
KEY `channel_deleted` (`channel_deleted`),
KEY `channel_active` (`channel_active`),
@@ -403,6 +405,7 @@ CREATE TABLE IF NOT EXISTS `dreport` (
`dreport_site` char(191) NOT NULL DEFAULT '',
`dreport_recip` char(191) NOT NULL DEFAULT '',
`dreport_result` char(191) NOT NULL DEFAULT '',
+ `dreport_name` char(191) NOT NULL DEFAULT '',
`dreport_time` datetime NOT NULL DEFAULT '0001-01-01 00:00:00',
`dreport_xchan` char(191) NOT NULL DEFAULT '',
`dreport_queue` char(191) NOT NULL DEFAULT '',
@@ -577,6 +580,7 @@ CREATE TABLE IF NOT EXISTS `issue` (
CREATE TABLE IF NOT EXISTS `item` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ `uuid` char(191) NOT NULL DEFAULT '',
`mid` char(191) NOT NULL DEFAULT '',
`aid` int(10) unsigned NOT NULL DEFAULT 0 ,
`uid` int(10) unsigned NOT NULL DEFAULT 0 ,
@@ -595,6 +599,7 @@ CREATE TABLE IF NOT EXISTS `item` (
`source_xchan` char(191) NOT NULL DEFAULT '',
`mimetype` char(191) NOT NULL DEFAULT '',
`title` text NOT NULL,
+ `summary` mediumtext NOT NULL,
`body` mediumtext NOT NULL,
`html` mediumtext NOT NULL,
`app` char(191) NOT NULL DEFAULT '',
@@ -649,6 +654,7 @@ CREATE TABLE IF NOT EXISTS `item` (
`item_pending_remove` tinyint(1) NOT NULL DEFAULT 0 ,
`item_blocked` tinyint(1) NOT NULL DEFAULT 0 ,
PRIMARY KEY (`id`),
+ KEY `uuid` (`uuid`),
KEY `parent` (`parent`),
KEY `created` (`created`),
KEY `edited` (`edited`),
diff --git a/install/schema_postgres.sql b/install/schema_postgres.sql
index cb4476628..3bc256377 100644
--- a/install/schema_postgres.sql
+++ b/install/schema_postgres.sql
@@ -242,6 +242,7 @@ CREATE TABLE "channel" (
"channel_guid" text NOT NULL DEFAULT '',
"channel_guid_sig" text NOT NULL,
"channel_hash" text NOT NULL DEFAULT '',
+ "channel_portable_id" text NOT NULL DEFAULT '',
"channel_timezone" varchar(128) NOT NULL DEFAULT 'UTC',
"channel_location" text NOT NULL DEFAULT '',
"channel_theme" text NOT NULL DEFAULT '',
@@ -284,6 +285,7 @@ create index "channel_max_friend_req" on channel ("channel_max_friend_req");
create index "channel_default_gid" on channel ("channel_default_group");
create index "channel_guid" on channel ("channel_guid");
create index "channel_hash" on channel ("channel_hash");
+create index "channel_portable_id" on channel ("channel_portable_id");
create index "channel_expire_days" on channel ("channel_expire_days");
create index "channel_deleted" on channel ("channel_deleted");
create index "channel_active" on channel ("channel_active");
@@ -375,6 +377,7 @@ CREATE TABLE IF NOT EXISTS "dreport" (
"dreport_site" varchar(255) NOT NULL DEFAULT '',
"dreport_recip" varchar(255) NOT NULL DEFAULT '',
"dreport_result" varchar(255) NOT NULL DEFAULT '',
+ "dreport_name" varchar(255) NOT NULL DEFAULT '',
"dreport_time" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
"dreport_xchan" varchar(255) NOT NULL DEFAULT '',
"dreport_queue" varchar(255) NOT NULL DEFAULT '',
@@ -548,6 +551,7 @@ create index "issue_component" on issue ("issue_component");
CREATE TABLE "item" (
"id" serial NOT NULL,
+ "uuid" text NOT NULL DEFAULT '',
"mid" text NOT NULL DEFAULT '',
"aid" bigint NOT NULL DEFAULT '0',
"uid" bigint NOT NULL DEFAULT '0',
@@ -566,6 +570,7 @@ CREATE TABLE "item" (
"source_xchan" text NOT NULL DEFAULT '',
"mimetype" text NOT NULL DEFAULT '',
"title" text NOT NULL,
+ "summary" text NOT NULL,
"body" text NOT NULL,
"html" text NOT NULL,
"app" text NOT NULL DEFAULT '',
@@ -623,6 +628,7 @@ CREATE TABLE "item" (
PRIMARY KEY ("id")
);
create index "item_uid" on item ("uid");
+create index "item_uuid" on item ("uuid");
create index "item_parent" on item ("parent");
create index "item_created" on item ("created");
create index "item_edited" on item ("edited");