function zot_reply_auth_check($data, $encrypted_packet) { $ret = array('success' => false); /* * Requestor visits /magic/?dest=somewhere on their own site with a browser * magic redirects them to $destsite/post [with auth args....] * $destsite sends an auth_check packet to originator site * The auth_check packet is handled here by the originator's site * - the browser session is still waiting * inside $destsite/post for everything to verify * If everything checks out we'll return a token to $destsite * and then $destsite will verify the token, authenticate the browser * session and then redirect to the original destination. * If authentication fails, the redirection to the original destination * will still take place but without authentication. */ logger('mod_zot: auth_check', LOGGER_DEBUG); if (!$encrypted_packet) { logger('mod_zot: auth_check packet was not encrypted.'); $ret['message'] .= 'no packet encryption' . EOL; json_return_and_die($ret); } $arr = $data['sender']; $sender_hash = make_xchan_hash($arr['guid'], $arr['guid_sig']); // garbage collect any old unused notifications // This was and should be 10 minutes but my hosting provider has time lag between the DB and // the web server. We should probably convert this to webserver time rather than DB time so // that the different clocks won't affect it and allow us to keep the time short. Zotlabs\Zot\Verify::purge('auth', '30 MINUTE'); $y = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1", dbesc($sender_hash)); // We created a unique hash in mod/magic.php when we invoked remote auth, and stored it in // the verify table. It is now coming back to us as 'secret' and is signed by a channel at the other end. // First verify their signature. We will have obtained a zot-info packet from them as part of the sender // verification. if (!$y || !rsa_verify($data['secret'], base64url_decode($data['secret_sig']), $y[0]['xchan_pubkey'])) { logger('mod_zot: auth_check: sender not found or secret_sig invalid.'); $ret['message'] .= 'sender not found or sig invalid ' . print_r($y, true) . EOL; json_return_and_die($ret); } // There should be exactly one recipient, the original auth requestor $ret['message'] .= 'recipients ' . print_r($recipients, true) . EOL; if ($data['recipients']) { $arr = $data['recipients'][0]; $recip_hash = make_xchan_hash($arr['guid'], $arr['guid_sig']); $c = q("select channel_id, channel_account_id, channel_prvkey from channel where channel_hash = '%s' limit 1", dbesc($recip_hash)); if (!$c) { logger('mod_zot: auth_check: recipient channel not found.'); $ret['message'] .= 'recipient not found.' . EOL; json_return_and_die($ret); } $confirm = base64url_encode(rsa_sign($data['secret'] . $recip_hash, $c[0]['channel_prvkey'])); // This additionally checks for forged sites since we already stored the expected result in meta // and we've already verified that this is them via zot_gethub() and that their key signed our token $z = Zotlabs\Zot\Verify::match('auth', $c[0]['channel_id'], $data['secret'], $data['sender']['url']); if (!$z) { logger('mod_zot: auth_check: verification key not found.'); $ret['message'] .= 'verification key not found' . EOL; json_return_and_die($ret); } $u = q("select account_service_class from account where account_id = %d limit 1", intval($c[0]['channel_account_id'])); logger('mod_zot: auth_check: success', LOGGER_DEBUG); $ret['success'] = true; $ret['confirm'] = $confirm; if ($u && $u[0]['account_service_class']) { $ret['service_class'] = $u[0]['account_service_class']; } // Set "do not track" flag if this site or this channel's profile is restricted // in some way if (intval(get_config('system', 'block_public'))) { $ret['DNT'] = true; } if (!perm_is_allowed($c[0]['channel_id'], '', 'view_profile')) { $ret['DNT'] = true; } if (get_pconfig($c[0]['channel_id'], 'system', 'do_not_track')) { $ret['DNT'] = true; } if (get_pconfig($c[0]['channel_id'], 'system', 'hide_online_status')) { $ret['DNT'] = true; } json_return_and_die($ret); } json_return_and_die($ret); }