<?php namespace Zotlabs\Zot; class Receiver { protected $data; protected $encrypted; protected $error; protected $messagetype; protected $sender; protected $validated; protected $recipients; protected $response; protected $handler; function __construct($data,$prvkey,$handler) { $this->error = false; $this->validated = false; $this->messagetype = ''; $this->response = array('success' => false); $this->handler = $handler; if(! is_array($data)) $data = json_decode($data,true); if($data && is_array($data)) { $this->encrypted = ((array_key_exists('iv',$data)) ? true : false); if($this->encrypted) { $this->data = @json_decode(@crypto_unencapsulate($data,$prvkey),true); } if(! $this->data) $this->data = $data; if($this->data && is_array($this->data) && array_key_exists('type',$this->data)) $this->messagetype = $this->data['type']; } if(! $this->messagetype) $this->error = true; if($this->data) { $this->sender = ((array_key_exists('sender',$this->data)) ? $this->data['sender'] : null); $this->recipients = ((array_key_exists('recipients',$this->data)) ? $this->data['recipients'] : null); } if($this->sender) $this->ValidateSender(); $this->Dispatch(); } function ValidateSender() { $hubs = zot_gethub($this->sender,true); if (! $hubs) { /* Have never seen this guid or this guid coming from this location. Check it and register it. */ /* (!!) this will validate the sender. */ $result = zot_register_hub($this->sender); if ((! $result['success']) || (! ($hubs = zot_gethub($this->sender,true)))) { $this->response['message'] = 'Hub not available.'; json_return_and_die($this->response); } } foreach($hubs as $hub) { update_hub_connected($hub,((array_key_exists('sitekey',$this->sender)) ? $this->sender['sitekey'] : '')); } $this->validated = true; } function Dispatch() { /* Handle tasks which don't require sender validation */ switch($this->messagetype) { case 'ping': /* no validation needed */ $this->handler->Ping(); break; case 'pickup': /* perform site validation, as opposed to sender validation */ $this->handler->Pickup($this->data); break; default: if(! $this->validated) { $this->response['message'] = 'Sender not valid'; json_return_and_die($this->response); } break; } /* Now handle tasks which require sender validation */ switch($this->messagetype) { case 'auth_check': $this->handler->AuthCheck($this->data,$this->encrypted); break; case 'request': $this->handler->Request($this->data); break; case 'purge': $this->handler->Purge($this->sender,$this->recipients); break; case 'refresh': case 'force_refresh': $this->handler->Refresh($this->sender,$this->recipients); break; case 'notify': $this->handler->Notify($this->data); break; default: $this->response['message'] = 'Not implemented'; json_return_and_die($this->response); break; } } } /** * @brief zot communications and messaging. * * Sender HTTP posts to this endpoint ($site/post typically) with 'data' parameter set to json zot message packet. * This packet is optionally encrypted, which we will discover if the json has an 'iv' element. * $contents => array( 'alg' => 'aes256cbc', 'iv' => initialisation vector, 'key' => decryption key, 'data' => encrypted data); * $contents->iv and $contents->key are random strings encrypted with this site's RSA public key and then base64url encoded. * Currently only 'aes256cbc' is used, but this is extensible should that algorithm prove inadequate. * * Once decrypted, one will find the normal json_encoded zot message packet. * * Defined packet types are: notify, purge, refresh, force_refresh, auth_check, ping, and pickup * * Standard packet: (used by notify, purge, refresh, force_refresh, and auth_check) * \code{.json} * { * "type": "notify", * "sender":{ * "guid":"kgVFf_1...", * "guid_sig":"PT9-TApzp...", * "url":"http:\/\/podunk.edu", * "url_sig":"T8Bp7j5...", * }, * "recipients": { optional recipient array }, * "callback":"\/post", * "version":1, * "secret":"1eaa...", * "secret_sig": "df89025470fac8..." * } * \endcode * * Signature fields are all signed with the sender channel private key and base64url encoded. * Recipients are arrays of guid and guid_sig, which were previously signed with the recipients private * key and base64url encoded and later obtained via channel discovery. Absence of recipients indicates * a public message or visible to all potential listeners on this site. * * "pickup" packet: * The pickup packet is sent in response to a notify packet from another site * \code{.json} * { * "type":"pickup", * "url":"http:\/\/example.com", * "callback":"http:\/\/example.com\/post", * "callback_sig":"teE1_fLI...", * "secret":"1eaa...", * "secret_sig":"O7nB4_..." * } * \endcode * * In the pickup packet, the sig fields correspond to the respective data * element signed with this site's system private key and then base64url encoded. * The "secret" is the same as the original secret from the notify packet. * * If verification is successful, a json structure is returned containing a * success indicator and an array of type 'pickup'. * Each pickup element contains the original notify request and a message field * whose contents are dependent on the message type. * * This JSON array is AES encapsulated using the site public key of the site * that sent the initial zot pickup packet. * Using the above example, this would be example.com. * * \code{.json} * { * "success":1, * "pickup":{ * "notify":{ * "type":"notify", * "sender":{ * "guid":"kgVFf_...", * "guid_sig":"PT9-TApz...", * "url":"http:\/\/z.podunk.edu", * "url_sig":"T8Bp7j5D..." * }, * "callback":"\/post", * "version":1, * "secret":"1eaa661..." * }, * "message":{ * "type":"activity", * "message_id":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu", * "message_top":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu", * "message_parent":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu", * "created":"2012-11-20 04:04:16", * "edited":"2012-11-20 04:04:16", * "title":"", * "body":"Hi Nickordo", * "app":"", * "verb":"post", * "object_type":"", * "target_type":"", * "permalink":"", * "location":"", * "longlat":"", * "owner":{ * "name":"Indigo", * "address":"indigo@podunk.edu", * "url":"http:\/\/podunk.edu", * "photo":{ * "mimetype":"image\/jpeg", * "src":"http:\/\/podunk.edu\/photo\/profile\/m\/5" * }, * "guid":"kgVFf_...", * "guid_sig":"PT9-TAp...", * }, * "author":{ * "name":"Indigo", * "address":"indigo@podunk.edu", * "url":"http:\/\/podunk.edu", * "photo":{ * "mimetype":"image\/jpeg", * "src":"http:\/\/podunk.edu\/photo\/profile\/m\/5" * }, * "guid":"kgVFf_...", * "guid_sig":"PT9-TAp..." * } * } * } * } * \endcode * * Currently defined message types are 'activity', 'mail', 'profile', 'location' * and 'channel_sync', which each have different content schemas. * * Ping packet: * A ping packet does not require any parameters except the type. It may or may * not be encrypted. * * \code{.json} * { * "type": "ping" * } * \endcode * * On receipt of a ping packet a ping response will be returned: * * \code{.json} * { * "success" : 1, * "site" { * "url": "http:\/\/podunk.edu", * "url_sig": "T8Bp7j5...", * "sitekey": "-----BEGIN PUBLIC KEY----- * MIICIjANBgkqhkiG9w0BAQE..." * } * } * \endcode * * The ping packet can be used to verify that a site has not been re-installed, and to * initiate corrective action if it has. The url_sig is signed with the site private key * and base64url encoded - and this should verify with the enclosed sitekey. Failure to * verify indicates the site is corrupt or otherwise unable to communicate using zot. * This return packet is not otherwise verified, so should be compared with other * results obtained from this site which were verified prior to taking action. For instance * if you have one verified result with this signature and key, and other records for this * url which have different signatures and keys, it indicates that the site was re-installed * and corrective action may commence (remove or mark invalid any entries with different * signatures). * If you have no records which match this url_sig and key - no corrective action should * be taken as this packet may have been returned by an imposter. * * @param[in,out] App &$a */