aboutsummaryrefslogtreecommitdiffstats
path: root/include/zot.php
diff options
context:
space:
mode:
Diffstat (limited to 'include/zot.php')
-rw-r--r--include/zot.php224
1 files changed, 176 insertions, 48 deletions
diff --git a/include/zot.php b/include/zot.php
index 65f3b606f..9777f7ae4 100644
--- a/include/zot.php
+++ b/include/zot.php
@@ -4,9 +4,26 @@ require_once('include/crypto.php');
require_once('include/items.php');
/**
+ * Red implementation of zot protocol.
+ *
+ * https://github.com/friendica/red/wiki/zot
+ * https://github.com/friendica/red/wiki/Zot---A-High-Level-Overview
+ *
+ */
+
+
+/**
*
* @function zot_new_uid($channel_nick)
- * @channel_id = unique nickname of controlling entity
+ *
+ * Generates a unique string for use as a zot guid using our DNS-based url, the channel nickname and some entropy.
+ * The entropy ensures uniqueness against re-installs where the same URL and nickname are chosen.
+ * NOTE: zot doesn't require this to be unique. Internally we use a whirlpool hash of this guid and the signature
+ * of this guid signed with the channel private key. This can be verified and should make the probability of
+ * collision of the verified result negligible within the constraints of our immediate universe.
+ *
+ * @param string channel_nickname = unique nickname of controlling entity
+ *
* @returns string
*
*/
@@ -18,41 +35,58 @@ function zot_new_uid($channel_nick) {
/**
- *
- * Given an array of zot hashes, return all distinct hubs
- * If primary is true, return only primary hubs
- * Result is ordered by url to assist in batching.
- * Return only the first primary hub as there should only be one.
+ * @function zot_get_hublocs($hash)
+ * Given a zot hash, return all distinct hubs.
+ * This function is used in building the zot discovery packet
+ * and therefore should only be used by channels which are defined
+ * on this hub
+ * @param string $hash - xchan_hash
+ * @retuns array of hubloc (hub location structures)
+ * hubloc_id int
+ * hubloc_guid char(255)
+ * hubloc_guid_sig text
+ * hubloc_hash char(255)
+ * hubloc_addr char(255)
+ * hubloc_flags int
+ * hubloc_status int
+ * hubloc_url char(255)
+ * hubloc_url_sig text
+ * hubloc_host char(255)
+ * hubloc_callback char(255)
+ * hubloc_connect char(255)
+ * hubloc_sitekey text
+ * hubloc_updated datetime
+ * hubloc_connected datetime
*
*/
-function zot_get_hubloc($arr,$primary = false) {
+function zot_get_hublocs($hash) {
- $tmp = '';
-
- if(is_array($arr)) {
- foreach($arr as $e) {
- if(strlen($tmp))
- $tmp .= ',';
- $tmp .= "'" . dbesc($e) . "'" ;
- }
- }
-
- if(! strlen($tmp))
- return array();
-
- $sql_extra = (($primary) ? " and hubloc_flags & " . intval(HUBLOC_FLAGS_PRIMARY) : "" );
- $limit = (($primary) ? " limit 1 " : "");
- return q("select * from hubloc where hubloc_hash in ( $tmp ) $sql_extra order by hubloc_url $limit");
+ /** Only search for active hublocs - e.g. those that haven't been marked deleted */
+ $ret = q("select * from hubloc where hubloc_hash = '%s' and not ( hubloc_flags & %d ) group by hubloc_url ",
+ dbesc($hash),
+ intval(HUBLOC_FLAGS_DELETED)
+ );
+ return $ret;
}
-/*
+/**
+ *
+ * @function zot_build_packet($channel,$type = 'notify',$recipients = null, $remote_key = null, $secret = null)
+ * builds a zot notification packet that you can either
+ * store in the queue with a message array or call zot_zot to immediately
+ * zot it to the other side
*
- * zot_build_packet builds a notification packet that you can either
- * store in the queue with a message array or call zot_zot to immediately
- * zot it to the other side
+ * @param array $channel => sender channel structure
+ * @param string $type => packet type: one of 'ping', 'pickup', 'purge', 'refresh', 'notify', 'auth_check'
+ * @param array $recipients => envelope information, array ( 'guid' => string, 'guid_sig' => string ); empty for public posts
+ * @param string $remote_key => optional public site key of target hub used to encrypt entire packet
+ * NOTE: remote_key and encrypted packets are required for 'auth_check' packets, optional for all others
+ * @param string $secret => random string, required for packets which require verification/callback
+ * e.g. 'pickup', 'purge', 'notify', 'auth_check' --- 'ping' and 'refresh' do not require verification
*
+ * @returns string json encoded zot packet
*/
function zot_build_packet($channel,$type = 'notify',$recipients = null, $remote_key = null, $secret = null) {
@@ -194,12 +228,27 @@ function zot_finger($webbie,$channel,$autofallback = true) {
}
/**
- * @function: zot_refresh
+ * @function: zot_refresh($them, $channel = null)
*
- * zot_refresh is typically invoked when somebody has changed permissions of a channel and they are notified
- * to fetch new permissions via a finger operation. This may result in a new connection (abook entry) being added to a local channel
- * and it may result in auto-permissions being granted.
+ * zot_refresh is typically invoked when somebody has changed permissions of a channel and they are notified
+ * to fetch new permissions via a finger/discovery operation. This may result in a new connection
+ * (abook entry) being added to a local channel and it may result in auto-permissions being granted.
+ *
+ * Friending in zot is accomplished by sending a refresh packet to a specific channel which indicates a
+ * permission change has been made by the sender which affects the target channel. The hub controlling
+ * the target channel does targetted discovery (a zot-finger request requesting permissions for the local
+ * channel). These are decoded here, and if necessary and abook structure (addressbook) is created to store
+ * the permissions assigned to this channel.
+ *
+ * Initially these abook structures are created with a 'pending' flag, so that no reverse permissions are
+ * implied until this is approved by the owner channel. A channel can also auto-populate permissions in
+ * return and send back a refresh packet of its own. This is used by forum and group communication channels
+ * so that friending and membership in the channel's "club" is automatic.
+ *
+ * @param array $them => xchan structure of sender
+ * @param array $channel => local channel structure of target recipient, required for "friending" operations
*
+ * @returns boolean true if successful, else false
*/
function zot_refresh($them,$channel = null) {
@@ -366,7 +415,17 @@ function zot_refresh($them,$channel = null) {
* @function: zot_gethub
*
* A guid and a url, both signed by the sender, distinguish a known sender at a known location
- * This function looks these up to see if the channel is known. If not, we will need to verify it.
+ * This function looks these up to see if the channel is known and therefore previously verified.
+ * If not, we will need to verify it.
+ *
+ * @param array $arr
+ * $arr must contain:
+ * string $arr['guid'] => guid of conversant
+ * string $arr['guid_sig'] => guid signed with conversant's private key
+ * string $arr['url'] => URL of the origination hub of this communication
+ * string $arr['url_sig'] => URL signed with conversant's private key
+ *
+ *
* @returns: array => hubloc record
*/
@@ -393,6 +452,27 @@ function zot_gethub($arr) {
return null;
}
+/**
+ * @function zot_register_hub($arr)
+ *
+ * A communication has been received which has an unknown (to us) sender.
+ * Perform discovery based on our calculated hash of the sender at the origination address.
+ * This will fetch the discovery packet of the sender, which contains the public key we
+ * need to verify our guid and url signatures.
+ *
+ * @param array $arr
+ * $arr must contain:
+ * string $arr['guid'] => guid of conversant
+ * string $arr['guid_sig'] => guid signed with conversant's private key
+ * string $arr['url'] => URL of the origination hub of this communication
+ * string $arr['url_sig'] => URL signed with conversant's private key
+ *
+ *
+ * @returns array => 'success' (boolean true or false)
+ * 'message' (optional error string only if success is false)
+ */
+
+
function zot_register_hub($arr) {
$result = array('success' => false);
@@ -411,19 +491,43 @@ function zot_register_hub($arr) {
if($x['success']) {
$record = json_decode($x['body'],true);
- $c = import_xchan($record);
- if($c['success'])
- $result['success'] = true;
+
+ /*
+ * We now have a key - only continue registration if our signatures are valid
+ * AND the guid and guid sig in the returned packet match those provided in
+ * our current communication.
+ */
+
+ if((rsa_verify($arr['guid'],base64url_decode($arr['guid_sig']),$record['key']))
+ && (rsa_verify($arr['url'],base64url_decode($arr['url_sig']),$record['key']))
+ && ($arr['guid'] === $record['guid'])
+ && ($arr['guid_sig'] === $record['guid_sig'])) {
+
+ $c = import_xchan($record);
+ if($c['success'])
+ $result['success'] = true;
+ }
+ else {
+ logger('zot_register_hub: failure to verify returned packet.');
+ }
}
}
return $result;
}
-
-// Takes a json associative array from zot_finger and imports the xchan and hublocs
-// If the xchan already exists, update the name and photo if these have changed.
-//
+/**
+ * @function import_xchan($arr,$ud_flags = 1)
+ * Takes an associative array of a fecthed discovery packet and updates
+ * all internal data structures which need to be updated as a result.
+ *
+ * @param array $arr => json_decoded discovery packet
+ * @param int $ud_flags
+ * Determines whether to create a directory update record if any changes occur, default 1 or true
+ *
+ * @returns array => 'success' (boolean true or false)
+ * 'message' (optional error string only if success is false)
+ */
function import_xchan($arr,$ud_flags = 1) {
@@ -449,7 +553,6 @@ function import_xchan($arr,$ud_flags = 1) {
return $ret;
}
-
logger('import_xchan: ' . $xchan_hash, LOGGER_DEBUG);
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
@@ -766,6 +869,20 @@ function import_xchan($arr,$ud_flags = 1) {
return $ret;
}
+/**
+ * @function zot_process_response($hub,$arr,$outq) {
+ * Called immediately after sending a zot message which is using queue processing
+ * Updates the queue item according to the response result and logs any information
+ * returned to aid communications troubleshooting.
+ *
+ * @param string $hub - url of site we just contacted
+ * @param array $arr - output of z_post_url()
+ * @param array $outq - The queue structure attached to this request
+ *
+ * @returns nothing
+ */
+
+
function zot_process_response($hub,$arr,$outq) {
if(! $arr['success']) {
@@ -801,14 +918,16 @@ function zot_process_response($hub,$arr,$outq) {
}
/**
- * @function: zot_fetch
+ * @function zot_fetch($arr)
*
- * We received a notification packet (in mod/post.php) that a message is waiting for us, and we've verified the sender.
- * Now send back a pickup message, using our message tracking ID ($arr['secret']), which we will sign.
- * The entire pickup message is encrypted with the remote site's public key.
- * If everything checks out on the remote end, we will receive back a packet containing one or more messages,
- * which will be processed before returning.
- *
+ * We received a notification packet (in mod/post.php) that a message is waiting for us, and we've verified the sender.
+ * Now send back a pickup message, using our message tracking ID ($arr['secret']), which we will sign with our site private key.
+ * The entire pickup message is encrypted with the remote site's public key.
+ * If everything checks out on the remote end, we will receive back a packet containing one or more messages,
+ * which will be processed and delivered before this function ultimately returns.
+ *
+ * @param array $arr
+ * decrypted and json decoded notify packet from remote site
*/
@@ -846,7 +965,16 @@ function zot_fetch($arr) {
* Process an incoming array of messages which were obtained via pickup, and
* import, update, delete as directed.
*
- * The message types handled here are 'activity' (e.g. posts), 'mail' and 'profile'
+ * @param array $arr => 'pickup' structure returned from remote site
+ * @param string $sender_url => the url specified by the sender in the initial communication
+ * we will verify the sender and url in each returned message structure and also verify
+ * that all the messages returned match the site url that we are currently processing.
+ *
+ * The message types handled here are 'activity' (e.g. posts), 'mail' , 'profile', and 'channel_sync'
+ *
+ * @returns array => array ( [0] => string $channel_hash, [1] => string $delivery_status, [2] => string $address )
+ * suitable for logging remotely, enumerating the processing results of each message/recipient combination.
+ *
*/
function zot_import($arr, $sender_url) {