diff options
Diffstat (limited to 'Zotlabs/Lib')
-rw-r--r-- | Zotlabs/Lib/ActivityStreams.php | 43 | ||||
-rw-r--r-- | Zotlabs/Lib/LDSignatures.php | 117 | ||||
-rw-r--r-- | Zotlabs/Lib/ThreadItem.php | 6 |
3 files changed, 162 insertions, 4 deletions
diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index 3bbe3b190..686f4a140 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -14,6 +14,8 @@ class ActivityStreams { public $origin = null; public $owner = null; + public $recips = null; + function __construct($string) { $this->data = json_decode($string,true); @@ -28,7 +30,7 @@ class ActivityStreams { $this->obj = $this->get_compound_property('object'); $this->tgt = $this->get_compound_property('target'); $this->origin = $this->get_compound_property('origin'); - $this->owner = $this->get_compound_property('owner','','http://purl.org/zot/protocol'); + $this->recips = $this->collect_recips(); if(($this->type === 'Note') && (! $this->obj)) { $this->obj = $this->data; @@ -41,6 +43,45 @@ class ActivityStreams { return $this->valid; } + function collect_recips($base = '',$namespace = 'https://www.w3.org/ns/activitystreams') { + $x = []; + $fields = [ 'to','cc','bto','bcc','audience']; + foreach($fields as $f) { + $y = $this->get_compound_property($f,$base,$namespace); + if($y) + $x = array_merge($x,$y); + } +// not yet ready for prime time +// $x = $this->expand($x,$base,$namespace); + return $x; + } + + function expand($arr,$base = '',$namespace = 'https://www.w3.org/ns/activitystreams') { + $ret = []; + + // right now use a hardwired recursion depth of 5 + + for($z = 0; $z < 5; $z ++) { + if(is_array($arr) && $arr) { + foreach($arr as $a) { + if(is_array($a)) { + $ret[] = $a; + } + else { + $x = $this->get_compound_property($a,$base,$namespace); + if($x) { + $ret = array_merge($ret,$x); + } + } + } + } + } + + // @fixme de-duplicate + + return $ret; + } + function get_namespace($base,$namespace) { $key = null; diff --git a/Zotlabs/Lib/LDSignatures.php b/Zotlabs/Lib/LDSignatures.php new file mode 100644 index 000000000..88dfe80c0 --- /dev/null +++ b/Zotlabs/Lib/LDSignatures.php @@ -0,0 +1,117 @@ +<?php + +namespace Zotlabs\Lib; + +require_once('library/jsonld/jsonld.php'); + +class LDSignatures { + + + static function verify($data,$pubkey) { + + $ohash = self::hash(self::signable_options($data['signature'])); + $dhash = self::hash(self::signable_data($data)); + + return rsa_verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey); + } + + static function dopplesign(&$data,$channel) { + $data['magicEnv'] = self::salmon_sign($data,$channel); + return self::sign($data,$channel); + } + + static function sign($data,$channel) { + $options = [ + 'type' => 'RsaSignature2017', + 'nonce' => random_string(64), + 'creator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem', + 'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z') + ]; + + $ohash = self::hash(self::signable_options($options)); + $dhash = self::hash(self::signable_data($data)); + $options['signatureValue'] = base64_encode(rsa_sign($ohash . $dhash,$channel['channel_prvkey'])); + + $signed = array_merge([ + '@context' => [ 'https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1' ], + ],$options); + + return $signed; + } + + + static function signable_data($data) { + + $newdata = []; + if($data) { + foreach($data as $k => $v) { + if(! in_array($k,[ 'signature' ])) { + $newopts[$k] = $v; + } + } + } + return json_encode($newdata,JSON_UNESCAPED_SLASHES); + } + + + static function signable_options($options) { + + $newopts = [ '@context' => 'https://w3id.org/identity/v1' ]; + if($options) { + foreach($options as $k => $v) { + if(! in_array($k,[ 'type','id','signatureValue' ])) { + $newopts[$k] = $v; + } + } + } + return json_encode($newopts,JSON_UNESCAPED_SLASHES); + } + + static function hash($obj) { + return hash('sha256',self::normalise($obj)); + } + + static function normalise($data) { + if(is_string($data)) { + $data = json_decode($data); + } + + if(! is_object($data)) + return ''; + + return jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]); + } + + static function salmon_sign($data,$channel) { + + $arr = $data; + $data = json_encode($data,JSON_UNESCAPED_SLASHES); + $data = base64url_encode($data, false); // do not strip padding + $data_type = 'application/activity+json'; + $encoding = 'base64url'; + $algorithm = 'RSA-SHA256'; + $keyhash = base64url_encode(z_root() . '/channel/' . $channel['channel_address']); + + $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$data); + + // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods + + $precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng=='; + + $signature = base64url_encode(rsa_sign($data . $precomputed,$channel['channel_prvkey'])); + + return ([ + 'id' => $arr['id'], + 'meData' => $data, + 'meDataType' => $data_type, + 'meEncoding' => $encoding, + 'meAlgorithm' => $algorithm, + 'meCreator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem', + 'meSignatureValue' => $signature + ]); + + } + + + +}
\ No newline at end of file diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php index 313001cc7..f9565d339 100644 --- a/Zotlabs/Lib/ThreadItem.php +++ b/Zotlabs/Lib/ThreadItem.php @@ -758,9 +758,9 @@ class ThreadItem { '$sourceapp' => \App::$sourcename, '$observer' => get_observer_hash(), '$anoncomments' => (($conv->get_mode() === 'channel' && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false), - '$anonname' => [ 'anonname', t('Your full name (required)'),'','','','onBlur="commentCloseUI(this,\'' . $this->get_id() . '\')"' ], - '$anonmail' => [ 'anonmail', t('Your email address (required)'),'','','','onBlur="commentCloseUI(this,\'' . $this->get_id() . '\')"' ], - '$anonurl' => [ 'anonurl', t('Your website URL (optional)'),'','','','onBlur="commentCloseUI(this,\'' . $this->get_id() . '\')"' ] + '$anonname' => [ 'anonname', t('Your full name (required)') ], + '$anonmail' => [ 'anonmail', t('Your email address (required)') ], + '$anonurl' => [ 'anonurl', t('Your website URL (optional)') ] )); return $comment_box; |