diff options
-rw-r--r-- | Zotlabs/Daemon/Notifier.php | 25 | ||||
-rw-r--r-- | Zotlabs/Zot/IHandler.php | 2 | ||||
-rw-r--r-- | Zotlabs/Zot/Receiver.php | 4 | ||||
-rw-r--r-- | Zotlabs/Zot/ZotHandler.php | 4 | ||||
-rw-r--r-- | include/channel.php | 99 | ||||
-rw-r--r-- | include/xchan.php | 229 | ||||
-rw-r--r-- | include/zot.php | 44 |
7 files changed, 405 insertions, 2 deletions
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index 20dd96ddd..f64e6748c 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -67,6 +67,7 @@ require_once('include/bbcode.php'); * location channel_id * request channel_id xchan_hash message_id * rating xlink_id + * keychange channel_id * */ @@ -144,6 +145,20 @@ class Notifier { $packet_type = 'request'; $normal_mode = false; } + elseif($cmd === 'keychange') { + $channel = channelx_by_n($item_id); + $r = q("select abook_xchan from abook where abook_channel = %d", + intval($item_id) + ); + if($r) { + foreach($r as $rr) { + $recipients[] = $rr['abook_xchan']; + } + } + $private = false; + $packet_type = 'keychange'; + $normal_mode = false; + } elseif($cmd == 'permission_update' || $cmd == 'permission_create') { // Get the (single) recipient $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_self = 0", @@ -570,12 +585,17 @@ class Notifier { } - $hash = random_string(); + $hash = random_string(); $packet = null; + $pmsg = ''; if($packet_type === 'refresh' || $packet_type === 'purge') { $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null)); } + if($packet_type === 'keychange') { + $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null)); + $pmsg = get_pconfig($channel['channel_id'],'system','keychange'); + } elseif($packet_type === 'request') { $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'], @@ -589,7 +609,8 @@ class Notifier { 'account_id' => $channel['channel_account_id'], 'channel_id' => $channel['channel_id'], 'posturl' => $hub['hubloc_callback'], - 'notify' => $packet + 'notify' => $packet, + 'msg' => (($pmsg) ? json_encode($pmsg) : '') )); } else { diff --git a/Zotlabs/Zot/IHandler.php b/Zotlabs/Zot/IHandler.php index eeca1555c..dd82f5be6 100644 --- a/Zotlabs/Zot/IHandler.php +++ b/Zotlabs/Zot/IHandler.php @@ -12,6 +12,8 @@ interface IHandler { function Request($data); + function Rekey($sender,$data); + function AuthCheck($data,$encrypted); function Purge($sender,$recipients); diff --git a/Zotlabs/Zot/Receiver.php b/Zotlabs/Zot/Receiver.php index 0050a2559..c521c9d64 100644 --- a/Zotlabs/Zot/Receiver.php +++ b/Zotlabs/Zot/Receiver.php @@ -120,6 +120,10 @@ class Receiver { $this->handler->Notify($this->data); break; + case 'rekey': + $this->handler->Rekey($this->sender, $this->data); + break; + default: $this->response['message'] = 'Not implemented'; json_return_and_die($this->response); diff --git a/Zotlabs/Zot/ZotHandler.php b/Zotlabs/Zot/ZotHandler.php index aab336545..ab8815b3d 100644 --- a/Zotlabs/Zot/ZotHandler.php +++ b/Zotlabs/Zot/ZotHandler.php @@ -20,6 +20,10 @@ class ZotHandler implements IHandler { zot_reply_message_request($data); } + function Rekey($sender,$data) { + zot_rekey_request($sender,$data); + } + function AuthCheck($data,$encrypted) { zot_reply_auth_check($data,$encrypted); } diff --git a/include/channel.php b/include/channel.php index 49da57fd6..23ceb1414 100644 --- a/include/channel.php +++ b/include/channel.php @@ -454,6 +454,105 @@ function create_identity($arr) { return $ret; } + +function change_channel_keys($channel) { + + $ret = array('success' => false); + + $stored = []; + + $key = new_keypair(4096); + + $sig = base64url_encode(rsa_sign($channel['channel_guid'],$key['prvkey'])); + $hash = make_xchan_hash($channel['channel_guid'],$sig); + + $stored['old_guid'] = $channel['channel_guid']; + $stored['old_guid_sig'] = $channel['channel_guid_sig']; + $stored['old_key'] = $channel['channel_pubkey']; + $stored['old_hash'] = $channel['channel_hash']; + + $stored['new_key'] = $key['pubkey']; + $stored['new_sig'] = base64url_encode(rsa_sign($key['pubkey'],$channel['channel_prvkey'])); + + // Save this info for the notifier to collect + + set_pconfig($channel['channel_id'],'system','keychange',$stored); + + $r = q("update channel set channel_prvkey = '%s', channel_pubkey = '%s', channel_guid_sig = '%s', channel_hash = '%s' where channel_id = %d", + dbesc($key['prvkey']), + dbesc($key['pubkey']), + dbesc($sig), + dbesc($hash), + intval($channel['channel_id']) + ); + if(! $r) { + return $ret; + } + $r = q("select * from channel where channel_id = %d", + intval($channel['channel_id']) + ); + + if(! $r) { + $ret['message'] = t('Unable to retrieve modified identity'); + return $ret; + } + + $modified = $r[0]; + + $h = q("select * from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' ", + dbesc($stored['old_hash']), + dbesc(z_root()) + ); + + if($h) { + foreach($h as $hv) { + $hv['hubloc_guid_sig'] = $sig; + $hv['hubloc_hash'] = $hash; + $hv['hubloc_url_sig'] = base64url_encode(rsa_sign(z_root(),$modifed['channel_prvkey'])); + hubloc_store_lowlevel($hv); + } + } + + $x = q("select * from xchan where xchan_hash = '%s' ", + dbesc($stored['old_hash']) + ); + + $check = q("select * from xchan where xchan_hash = '%s'", + dbesc($hash) + ); + + if(($x) && (! $check)) { + $oldxchan = $x[0]; + foreach($x as $xv) { + $xv['xchan_guid_sig'] = $sig; + $xv['xchan_hash'] = $hash; + $xv['xchan_pubkey'] = $key['pubkey']; + xchan_store_lowlevel($xv); + $newxchan = $xv; + } + } + + $a = q("select * from abook where abook_xchan = '%s' and abook_self = 1", + dbesc($stored['old_hash']) + ); + + if($a) { + q("update abook set abook_xchan = '%s' where abook_id = %d", + dbesc($hash), + intval($a[0]['abook_id']) + ); + } + + xchan_change_key($oldxchan,$newxchan,$stored); + + Zotlabs\Daemon\Master::Summon(array('Notifier', 'keychange', $channel['channel_id'])); + + $ret['success'] = true; + return $ret; +} + + + /** * @brief Set default channel to be used on login. * diff --git a/include/xchan.php b/include/xchan.php index 12eb674fa..dba0b8b88 100644 --- a/include/xchan.php +++ b/include/xchan.php @@ -137,3 +137,232 @@ function xchan_fetch($arr) { } +function xchan_change_key($oldx,$newx,$data) { + + $r = q("update abook set abook_xchan = '%s' where abook_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update abconfig set xchan = '%s' where xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update group_member set xchan = '%s' where xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update chat set chat_xchan = '%s' where chat_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update chatpresence set cp_xchan = '%s' where cp_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update event set event_xchan = '%s' where event_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update item set owner_xchan = '%s' where owner_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update item set author_xchan = '%s' where author_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update item set source_xchan = '%s' where source_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update mail set from_xchan = '%s' where from_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update mail set to_xchan = '%s' where to_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update shares set share_xchan = '%s' where share_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update source set src_channel_xchan = '%s' where src_channel_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update source set src_xchan = '%s' where src_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update xchat set xchat_xchan = '%s' where xchat_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update xconfig set xchan = '%s' where xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update xign set xchan = '%s' where xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update xlink set xlink_xchan = '%s' where xlink_xchan = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update xprof set xprof_hash = '%s' where xprof_hash = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("update xtag set xtag_hash = '%s' where xtag_hash = '%s'", + dbsec($newx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + $r = q("select channel_id, channel_allow_cid, channel_deny_cid from channel where (channel_allow_cid like '%s' or channel_deny_cid like '%s') ", + dbesc($oldx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + if($r) { + foreach($r as $rv) { + $z = q("update channel set channel_allow_cid = '%s', channel_deny_cid = '%s' where channel_id = %d", + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['channel_allow_cid'])), + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['channel_deny_cid'])), + intval($rv['channel_id']) + ); + } + } + + $r = q("select id, allow_cid, deny_cid from attach where (allow_cid like '%s' or deny_cid like '%s') ", + dbesc($oldx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + if($r) { + foreach($r as $rv) { + $z = q("update attach set allow_cid = '%s', deny_cid = '%s' where id = %d", + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['allow_cid'])), + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['deny_cid'])), + intval($rv['id']) + ); + } + } + + $r = q("select cr_id, allow_cid, deny_cid from chatroom where (allow_cid like '%s' or deny_cid like '%s') ", + dbesc($oldx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + if($r) { + foreach($r as $rv) { + $z = q("update chatroom set allow_cid = '%s', deny_cid = '%s' where cr_id = %d", + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['allow_cid'])), + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['deny_cid'])), + intval($rv['cr_id']) + ); + } + } + + + $r = q("select id, allow_cid, deny_cid from event where (allow_cid like '%s' or deny_cid like '%s') ", + dbesc($oldx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + if($r) { + foreach($r as $rv) { + $z = q("update event set allow_cid = '%s', deny_cid = '%s' where id = %d", + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['allow_cid'])), + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['deny_cid'])), + intval($rv['id']) + ); + } + } + + + $r = q("select id, allow_cid, deny_cid from item where (allow_cid like '%s' or deny_cid like '%s') ", + dbesc($oldx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + if($r) { + foreach($r as $rv) { + $z = q("update item set allow_cid = '%s', deny_cid = '%s' where id = %d", + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['allow_cid'])), + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['deny_cid'])), + intval($rv['id']) + ); + } + } + + + $r = q("select mitem_id, allow_cid, deny_cid from menu_item where (allow_cid like '%s' or deny_cid like '%s') ", + dbesc($oldx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + if($r) { + foreach($r as $rv) { + $z = q("update menu_item set allow_cid = '%s', deny_cid = '%s' where mitem_id = %d", + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['allow_cid'])), + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['deny_cid'])), + intval($rv['mitem_id']) + ); + } + } + + + + $r = q("select obj_id, allow_cid, deny_cid from obj where (allow_cid like '%s' or deny_cid like '%s') ", + dbesc($oldx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + if($r) { + foreach($r as $rv) { + $z = q("update obj set allow_cid = '%s', deny_cid = '%s' where obj_id = %d", + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['allow_cid'])), + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['deny_cid'])), + intval($rv['obj_id']) + ); + } + } + + $r = q("select id, allow_cid, deny_cid from photo where (allow_cid like '%s' or deny_cid like '%s') ", + dbesc($oldx['xchan_hash']), + dbesc($oldx['xchan_hash']) + ); + + if($r) { + foreach($r as $rv) { + $z = q("update photo set allow_cid = '%s', deny_cid = '%s' where id = %d", + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['allow_cid'])), + dbesc(str_replace('<' . $oldx['xchan_hash'] . '>', '<' . $newx['xchan_hash'] . '>', $rv['deny_cid'])), + intval($rv['id']) + ); + } + } + + +}
\ No newline at end of file diff --git a/include/zot.php b/include/zot.php index 8bbc4a969..220292994 100644 --- a/include/zot.php +++ b/include/zot.php @@ -3757,6 +3757,50 @@ function zot_reply_message_request($data) { json_return_and_die($ret); } +function zot_rekey_request($sender,$data) { + + $ret = array('success' => false); + + // newsig is newkey signed with oldkey + + // The original xchan will remain. In Zot/Receiver we will have imported the new xchan and hubloc to verify + // the packet authenticity. What we will do now is verify that the keychange operation was signed by the + // oldkey, and if so change all the abook, abconfig, group, and permission elements which reference the + // old xchan_hash. + + if((! $data['oldkey']) && (! $data['oldsig']) && (! $data['newkey']) && (! $data['newsig'])) + json_return_and_die($ret); + + $oldhash = make_xchan_hash($data['old_guid'],$data['old_guid_sig']); + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($oldhash) + ); + + if(! $r) { + json_return_and_die($ret); + } + + $xchan = $r[0]; + + if(! rsa_verify($data['newkey'],base64url_decode($data['newsig']),$xchan['xchan_pubkey'])) { + json_return_and_die($ret); + } + + $newhash = make_xchan_hash($sender['guid'],$sender['guid_sig']); + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($newhash) + ); + + $newxchan = $r[0]; + + xchan_change_key($xchan,$newxchan,$data); + + $ret['success'] = true; + json_return_and_die($ret); +} + function zotinfo($arr) { |