this is brutal
This commit is contained in:
parent
e7f1d350c9
commit
bb8b3b9291
@ -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,30 +243,50 @@ 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
|
||||
*
|
||||
@ -222,12 +295,70 @@ class ActivityStreams {
|
||||
* @param string $namespace (optional) default empty
|
||||
* @return NULL|mixed
|
||||
*/
|
||||
function get_compound_property($property, $base = '', $namespace = '') {
|
||||
|
||||
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 = '', $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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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(),
|
||||
];
|
||||
@ -324,14 +324,19 @@ class Libzot {
|
||||
logger('zot-info: ' . print_r($record,true), LOGGER_DATA, LOG_DEBUG);
|
||||
|
||||
$x = self::import_xchan($record['data'], (($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED));
|
||||
logger('1');
|
||||
|
||||
if(! $x['success'])
|
||||
return false;
|
||||
logger('2');
|
||||
|
||||
if($channel && $record['data']['permissions']) {
|
||||
logger('3');
|
||||
$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 $k => $v) {
|
||||
set_abconfig($channel['channel_id'],$x['hash'],'their_perms',$k,$v);
|
||||
}
|
||||
}
|
||||
|
||||
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']);
|
||||
@ -380,14 +385,16 @@ logger('4');
|
||||
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');
|
||||
@ -410,7 +417,7 @@ logger('4');
|
||||
|
||||
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
|
||||
|
||||
@ -426,7 +433,7 @@ logger('4');
|
||||
[
|
||||
'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']
|
||||
]
|
||||
);
|
||||
@ -777,7 +784,7 @@ logger('4');
|
||||
|
||||
// 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) {
|
||||
@ -1130,7 +1137,7 @@ logger('4');
|
||||
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) {
|
||||
@ -1304,12 +1311,12 @@ logger('4');
|
||||
|
||||
$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'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1317,7 +1324,7 @@ logger('4');
|
||||
if($include_sys) {
|
||||
$sys = get_sys_channel();
|
||||
if($sys)
|
||||
$r[] = $sys['channel_hash'];
|
||||
$r[] = $sys['channel_portable_id'];
|
||||
}
|
||||
|
||||
|
||||
@ -1333,7 +1340,7 @@ logger('4');
|
||||
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)
|
||||
);
|
||||
@ -1354,7 +1361,7 @@ logger('4');
|
||||
$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)
|
||||
);
|
||||
@ -1428,7 +1435,7 @@ logger('4');
|
||||
* 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;
|
||||
@ -1710,7 +1717,7 @@ logger('4');
|
||||
|
||||
$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']);
|
||||
}
|
||||
|
||||
@ -1810,9 +1817,9 @@ logger('4');
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@ -2048,7 +2055,7 @@ logger('4');
|
||||
|
||||
$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'])
|
||||
);
|
||||
|
||||
@ -2203,7 +2210,7 @@ logger('4');
|
||||
|
||||
$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)
|
||||
);
|
||||
|
||||
@ -2211,7 +2218,7 @@ logger('4');
|
||||
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)
|
||||
);
|
||||
@ -2247,7 +2254,7 @@ logger('4');
|
||||
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) {
|
||||
@ -2558,6 +2565,9 @@ logger('4');
|
||||
|
||||
static function zotinfo($arr) {
|
||||
|
||||
logger('arr: ' . print_r($arr,true));
|
||||
|
||||
|
||||
$ret = [];
|
||||
|
||||
$zhash = ((x($arr,'guid_hash')) ? $arr['guid_hash'] : '');
|
||||
@ -2594,13 +2604,13 @@ logger('4');
|
||||
$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)
|
||||
@ -2608,7 +2618,7 @@ logger('4');
|
||||
}
|
||||
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)
|
||||
@ -2628,10 +2638,10 @@ logger('4');
|
||||
*
|
||||
*/
|
||||
|
||||
$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");
|
||||
}
|
||||
}
|
||||
@ -2775,7 +2785,7 @@ logger('4');
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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');
|
||||
@ -43,6 +45,48 @@ class Channel extends Controller {
|
||||
$profile = 0;
|
||||
$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);
|
||||
|
@ -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'] = base64url_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);
|
||||
@ -215,50 +237,43 @@ class HTTPSig {
|
||||
*/
|
||||
|
||||
function get_activitystreams_key($id) {
|
||||
$x = q("select * from xchan left join hubloc on xchan_portable_id = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
|
||||
dbesc(str_replace('acct:','',$id)),
|
||||
dbesc($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:','',$url)),
|
||||
dbesc($url)
|
||||
);
|
||||
if(! $x) {
|
||||
$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)
|
||||
);
|
||||
}
|
||||
|
||||
if($x && $x[0]['xchan_pubkey']) {
|
||||
return [ 'portable_id' => $x[0]['hubloc_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
|
||||
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;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function get_webfinger_key($id) {
|
||||
|
||||
$x = q("select * from xchan left join hubloc on xchan_portable_id = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
|
||||
$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)
|
||||
);
|
||||
if(! $x) {
|
||||
$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)
|
||||
);
|
||||
}
|
||||
|
||||
if($x && $x[0]['xchan_pubkey']) {
|
||||
return [ 'portable_id' => $x[0]['hubloc_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
|
||||
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
|
||||
}
|
||||
|
||||
$wf = Webfinger::exec($id);
|
||||
@ -280,26 +295,18 @@ class HTTPSig {
|
||||
}
|
||||
}
|
||||
|
||||
return (($key['public_key']) ? $key : false);
|
||||
return (($key['public_key']) ? $key : false);
|
||||
}
|
||||
|
||||
|
||||
function get_zotfinger_key($id) {
|
||||
|
||||
$x = q("select * from xchan left join hubloc on xchan_portable_id = hubloc_hash where hubloc_addr = '%s' or hubloc_id_url = '%s' limit 1",
|
||||
$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)
|
||||
);
|
||||
if(! $x) {
|
||||
$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)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if($x && $x[0]['xchan_pubkey']) {
|
||||
return [ 'portable_id' => $x[0]['hubloc_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
|
||||
return [ 'portable_id' => $x[0]['xchan_hash'], 'public_key' => $x[0]['xchan_pubkey'] , 'hubloc' => $x[0] ];
|
||||
}
|
||||
|
||||
$wf = Webfinger::exec($id);
|
||||
@ -321,14 +328,9 @@ class HTTPSig {
|
||||
if($i['success']) {
|
||||
$key['portable_id'] = $i['hash'];
|
||||
|
||||
$x = q("select * from xchan left join hubloc on xchan_portable_id = hubloc_hash where hubloc_id_url = '%s' limit 1",
|
||||
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1",
|
||||
dbesc($l['href'])
|
||||
);
|
||||
if(! $x) {
|
||||
$x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1",
|
||||
dbesc($l['href'])
|
||||
);
|
||||
}
|
||||
if($x) {
|
||||
$key['hubloc'] = $x[0];
|
||||
}
|
||||
@ -433,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";
|
||||
|
@ -4,7 +4,7 @@ namespace Zotlabs\Zot6;
|
||||
|
||||
use Zotlabs\Lib\Config;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
use Zotlabs\Web\HTTPSig;
|
||||
|
||||
|
||||
class Receiver {
|
||||
|
||||
|
@ -72,8 +72,8 @@ class Zot6Handler implements IHandler {
|
||||
foreach ($recipients as $recip) {
|
||||
|
||||
$r = q("select channel.*,xchan.* from channel
|
||||
left join xchan on channel_portable_id = xchan_portable_id
|
||||
where xchan_portable_id ='%s' limit 1",
|
||||
left join xchan on channel_portable_id = xchan_hash
|
||||
where xchan_hash ='%s' limit 1",
|
||||
dbesc($recip)
|
||||
);
|
||||
|
||||
@ -141,7 +141,7 @@ class Zot6Handler implements IHandler {
|
||||
|
||||
$arr = $data['recipients'][0];
|
||||
|
||||
$c = q("select * from channel left join xchan on channel_portable_id = xchan_portable_id where channel_portable_id = '%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) {
|
||||
@ -197,7 +197,7 @@ class Zot6Handler implements IHandler {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$r = q("select * from xchan where xchan_hash = '%s' or xchan_portable_id = '%s' limit 1",
|
||||
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
|
||||
dbesc($sender)
|
||||
);
|
||||
|
||||
@ -231,15 +231,14 @@ class Zot6Handler implements IHandler {
|
||||
// basically this means "unfriend"
|
||||
foreach ($recipients as $recip) {
|
||||
$r = q("select channel.*,xchan.* from channel
|
||||
left join xchan on channel_portable_id = xchan_portable_id
|
||||
left join xchan on channel_portable_id = xchan_hash
|
||||
where channel_portable_id = '%s' limit 1",
|
||||
dbesc($recip)
|
||||
);
|
||||
if ($r) {
|
||||
$r = q("select abook_id from abook where uid = %d and (abook_xchan = '%s' or abook_xchan = '%s') limit 1",
|
||||
$r = q("select abook_id from abook where uid = %d and abook_xchan = '%s' limit 1",
|
||||
intval($r[0]['channel_id']),
|
||||
dbesc($sender),
|
||||
dbesc($r[0]['xchan_portable_id'])
|
||||
dbesc($sender)
|
||||
);
|
||||
if ($r) {
|
||||
contact_remove($r[0]['channel_id'],$r[0]['abook_id']);
|
||||
|
@ -10,7 +10,7 @@ use Zotlabs\Access\Permissions;
|
||||
use Zotlabs\Daemon\Master;
|
||||
use Zotlabs\Lib\System;
|
||||
use Zotlabs\Render\Comanche;
|
||||
use Zotlabs\Lib\Zotlib;
|
||||
use Zotlabs\Lib\Libzot;
|
||||
|
||||
require_once('include/zot.php');
|
||||
require_once('include/crypto.php');
|
||||
@ -233,7 +233,7 @@ function create_identity($arr) {
|
||||
|
||||
$sig = base64url_encode(rsa_sign($guid,$key['prvkey']));
|
||||
$hash = make_xchan_hash($guid,$sig);
|
||||
$zhash = Zotlib::make_xchan_hash($guid,$key['pubkey']);
|
||||
$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
|
||||
|
||||
@ -353,10 +353,12 @@ function create_identity($arr) {
|
||||
'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'),
|
||||
@ -373,7 +375,6 @@ function create_identity($arr) {
|
||||
$r = xchan_store_lowlevel(
|
||||
[
|
||||
'xchan_hash' => $hash,
|
||||
'xchan_portable_id' => $zhash,
|
||||
'xchan_guid' => $guid,
|
||||
'xchan_guid_sig' => $sig,
|
||||
'xchan_pubkey' => $key['pubkey'],
|
||||
@ -393,6 +394,30 @@ function create_identity($arr) {
|
||||
]
|
||||
);
|
||||
|
||||
$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
|
||||
|
||||
|
@ -12,7 +12,6 @@ function xchan_store_lowlevel($arr) {
|
||||
|
||||
$store = [
|
||||
'xchan_hash' => ((array_key_exists('xchan_hash',$arr)) ? $arr['xchan_hash'] : ''),
|
||||
'xchan_portable_id' => ((array_key_exists('xchan_portable_id',$arr)) ? $arr['xchan_portable_id'] : ''),
|
||||
'xchan_guid' => ((array_key_exists('xchan_guid',$arr)) ? $arr['xchan_guid'] : ''),
|
||||
'xchan_guid_sig' => ((array_key_exists('xchan_guid_sig',$arr)) ? $arr['xchan_guid_sig'] : ''),
|
||||
'xchan_pubkey' => ((array_key_exists('xchan_pubkey',$arr)) ? $arr['xchan_pubkey'] : ''),
|
||||
|
Reference in New Issue
Block a user