1
0
Fork 0

Merge pull request #4725 from annando/dfrn-2

DFRN payload can now be transported via the Diaspora transport layer
This commit is contained in:
Hypolite Petovan 2018-04-02 09:47:31 -04:00 committed by GitHub
commit 4972b82807
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 117 additions and 31 deletions

View file

@ -12,15 +12,58 @@ use Friendica\Core\System;
use Friendica\Database\DBM; use Friendica\Database\DBM;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Protocol\DFRN; use Friendica\Protocol\DFRN;
use Friendica\Protocol\Diaspora;
require_once 'include/items.php'; require_once 'include/items.php';
function dfrn_notify_post(App $a) { function dfrn_notify_post(App $a) {
logger(__function__, LOGGER_TRACE); logger(__function__, LOGGER_TRACE);
if (empty($_POST)) { $postdata = file_get_contents('php://input');
require_once 'mod/salmon.php';
salmon_post($a); if (empty($_POST) || !empty($postdata)) {
$data = json_decode($postdata);
if (is_object($data)) {
$nick = defaults($a->argv, 1, '');
$user = dba::selectFirst('user', [], ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false]);
if (!DBM::is_result($user)) {
System::httpExit(500);
}
$msg = Diaspora::decodeRaw($user, $postdata);
// Check if the user has got this contact
$cid = Contact::getIdForURL($msg['author'], $user['uid']);
if (!$cid) {
// Otherwise there should be a public contact
$cid = Contact::getIdForURL($msg['author']);
if (!$cid) {
logger('Contact not found for address ' . $msg['author']);
System::xmlExit(3, 'Contact not found');
}
}
// We now have some contact, so we fetch it
$importer = dba::fetch_first("SELECT *, `name` as `senderName`
FROM `contact`
WHERE NOT `blocked` AND `id` = ? LIMIT 1",
$cid);
// This should never fail
if (!DBM::is_result($importer)) {
logger('Contact not found for address ' . $msg['author']);
System::xmlExit(3, 'Contact not found');
}
// Set the user id. This is important if this is a public contact
$importer['importer_uid'] = $user['uid'];
// Now we should be able to import it
$ret = DFRN::import($msg['message'], $importer);
System::xmlExit($ret, 'Done');
} else {
require_once 'mod/salmon.php';
salmon_post($a, $postdata);
}
} }
$dfrn_id = ((x($_POST,'dfrn_id')) ? notags(trim($_POST['dfrn_id'])) : ''); $dfrn_id = ((x($_POST,'dfrn_id')) ? notags(trim($_POST['dfrn_id'])) : '');

View file

@ -13,9 +13,11 @@ use Friendica\Util\Crypto;
require_once 'include/items.php'; require_once 'include/items.php';
function salmon_post(App $a) { function salmon_post(App $a, $xml = '') {
$xml = file_get_contents('php://input'); if (empty($xml)) {
$xml = file_get_contents('php://input');
}
logger('new salmon ' . $xml, LOGGER_DATA); logger('new salmon ' . $xml, LOGGER_DATA);

View file

@ -31,6 +31,7 @@ use Friendica\Util\Crypto;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Network; use Friendica\Util\Network;
use Friendica\Util\XML; use Friendica\Util\XML;
use Friendica\Protocol\Diaspora;
use dba; use dba;
use DOMDocument; use DOMDocument;
use DOMXPath; use DOMXPath;
@ -1368,6 +1369,43 @@ class DFRN
return intval($res->status); return intval($res->status);
} }
/**
* @brief Delivers items to the contacts via the Diaspora transport layer
*
* @param array $owner Owner record
* @param array $contact Contact record of the receiver
* @param array $items Items that will be transmitted
*
* @return int HTTP Deliver status
*/
public static function buildAndTransmit($owner, $contact, $items)
{
$a = get_app();
// Currently disabled, at first we will not use the batch delivery
// $public_batch = !$items[0]['private'];
$public_batch = false;
$msg = DFRN::entries($items, $owner);
$fcontact = Diaspora::personByHandle($contact['addr']);
if (empty($fcontact)) {
logger("unable to find contact details");
return;
}
$envelope = Diaspora::buildMessage($msg, $owner, $contact, $owner['uprvkey'], $fcontact['pubkey'], $public_batch);
$dest_url = ($public_batch ? $fcontact["batch"] : $contact["notify"]);
$content_type = ($public_batch ? "application/magic-envelope+xml" : "application/json");
$ret = Network::post($dest_url, $envelope, ["Content-Type: ".$content_type]);
/// @ToDo: Add better treatment of return codes
return $a->get_curl_code();
}
/** /**
* @brief Add new birthday event for this person * @brief Add new birthday event for this person
* *
@ -1433,7 +1471,7 @@ class DFRN
$contact_old = dba::fetch_first("SELECT `id`, `uid`, `url`, `network`, `avatar-date`, `avatar`, `name-date`, `uri-date`, `addr`, $contact_old = dba::fetch_first("SELECT `id`, `uid`, `url`, `network`, `avatar-date`, `avatar`, `name-date`, `uri-date`, `addr`,
`name`, `nick`, `about`, `location`, `keywords`, `xmpp`, `bdyear`, `bd`, `hidden`, `contact-type` `name`, `nick`, `about`, `location`, `keywords`, `xmpp`, `bdyear`, `bd`, `hidden`, `contact-type`
FROM `contact` WHERE `uid` = ? AND `nurl` = ? AND `network` != ?", FROM `contact` WHERE `uid` = ? AND `nurl` = ? AND `network` != ?",
$importer["uid"], $importer["importer_uid"],
normalise_link($author["link"]), normalise_link($author["link"]),
NETWORK_STATUSNET NETWORK_STATUSNET
); );
@ -1443,7 +1481,7 @@ class DFRN
$author["network"] = $contact_old["network"]; $author["network"] = $contact_old["network"];
} else { } else {
if (!$onlyfetch) { if (!$onlyfetch) {
logger("Contact ".$author["link"]." wasn't found for user ".$importer["uid"]." XML: ".$xml, LOGGER_DEBUG); logger("Contact ".$author["link"]." wasn't found for user ".$importer["importer_uid"]." XML: ".$xml, LOGGER_DEBUG);
} }
$author["contact-id"] = $importer["id"]; $author["contact-id"] = $importer["id"];
@ -1639,7 +1677,7 @@ class DFRN
Contact::updateAvatar( Contact::updateAvatar(
$author['avatar'], $author['avatar'],
$importer['uid'], $importer['importer_uid'],
$contact['id'], $contact['id'],
(strtotime($contact['avatar-date']) > strtotime($contact_old['avatar-date']) || ($author['avatar'] != $contact_old['avatar'])) (strtotime($contact['avatar-date']) > strtotime($contact_old['avatar-date']) || ($author['avatar'] != $contact_old['avatar']))
); );
@ -1657,7 +1695,7 @@ class DFRN
$poco["contact-type"] = $contact["contact-type"]; $poco["contact-type"] = $contact["contact-type"];
$gcid = GContact::update($poco); $gcid = GContact::update($poco);
GContact::link($gcid, $importer["uid"], $contact["id"]); GContact::link($gcid, $importer["importer_uid"], $contact["id"]);
} }
return $author; return $author;
@ -2617,7 +2655,7 @@ class DFRN
if ((x($ev, "desc") || x($ev, "summary")) && x($ev, "start")) { if ((x($ev, "desc") || x($ev, "summary")) && x($ev, "start")) {
logger("Event in item ".$item["uri"]." was found.", LOGGER_DEBUG); logger("Event in item ".$item["uri"]." was found.", LOGGER_DEBUG);
$ev["cid"] = $importer["id"]; $ev["cid"] = $importer["id"];
$ev["uid"] = $importer["uid"]; $ev["uid"] = $importer["importer_uid"];
$ev["uri"] = $item["uri"]; $ev["uri"] = $item["uri"];
$ev["edited"] = $item["edited"]; $ev["edited"] = $item["edited"];
$ev["private"] = $item["private"]; $ev["private"] = $item["private"];
@ -2626,7 +2664,7 @@ class DFRN
$r = q( $r = q(
"SELECT `id` FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", "SELECT `id` FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($item["uri"]), dbesc($item["uri"]),
intval($importer["uid"]) intval($importer["importer_uid"])
); );
if (DBM::is_result($r)) { if (DBM::is_result($r)) {
$ev["id"] = $r[0]["id"]; $ev["id"] = $r[0]["id"];
@ -2681,6 +2719,14 @@ class DFRN
return true; return true;
} }
} else { // $entrytype == DFRN_TOP_LEVEL } else { // $entrytype == DFRN_TOP_LEVEL
if ($importer["readonly"]) {
logger('ignoring read-only contact '.$importer["id"]);
return;
}
if ($importer["uid"] == 0) {
logger("Contact ".$importer["id"]." isn't known to user ".$importer["importer_uid"].". The post will be ignored.", LOGGER_DEBUG);
return;
}
if (!link_compare($item["owner-link"], $importer["url"])) { if (!link_compare($item["owner-link"], $importer["url"])) {
/* /*
* The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, * The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery,
@ -2736,10 +2782,10 @@ class DFRN
return false; return false;
} }
$condition = ["`uri` = ? AND `uid` = ? AND NOT `file` LIKE '%[%'", $uri, $importer["uid"]]; $condition = ["`uri` = ? AND `uid` = ? AND NOT `file` LIKE '%[%'", $uri, $importer["importer_uid"]];
$item = dba::selectFirst('item', ['id', 'parent', 'contact-id'], $condition); $item = dba::selectFirst('item', ['id', 'parent', 'contact-id'], $condition);
if (!DBM::is_result($item)) { if (!DBM::is_result($item)) {
logger("Item with uri " . $uri . " for user " . $importer["uid"] . " wasn't found.", LOGGER_DEBUG); logger("Item with uri " . $uri . " for user " . $importer["importer_uid"] . " wasn't found.", LOGGER_DEBUG);
return; return;
} }
@ -2808,7 +2854,7 @@ class DFRN
$xpath->registerNamespace("statusnet", NAMESPACE_STATUSNET); $xpath->registerNamespace("statusnet", NAMESPACE_STATUSNET);
$header = []; $header = [];
$header["uid"] = $importer["uid"]; $header["uid"] = $importer["importer_uid"];
$header["network"] = NETWORK_DFRN; $header["network"] = NETWORK_DFRN;
$header["type"] = "remote"; $header["type"] = "remote";
$header["wall"] = 0; $header["wall"] = 0;
@ -2827,7 +2873,7 @@ class DFRN
self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", false, $xml); self::fetchauthor($xpath, $doc->firstChild, $importer, "dfrn:owner", false, $xml);
} }
logger("Import DFRN message for user " . $importer["uid"] . " from contact " . $importer["id"], LOGGER_DEBUG); logger("Import DFRN message for user " . $importer["importer_uid"] . " from contact " . $importer["id"], LOGGER_DEBUG);
// The account type is new since 3.5.1 // The account type is new since 3.5.1
if ($xpath->query("/atom:feed/dfrn:account_type")->length > 0) { if ($xpath->query("/atom:feed/dfrn:account_type")->length > 0) {
@ -2853,21 +2899,16 @@ class DFRN
self::processRelocation($xpath, $relocation, $importer); self::processRelocation($xpath, $relocation, $importer);
} }
if ($importer["readonly"]) { if (($importer["uid"] != 0) && !$importer["readonly"]) {
// We aren't receiving stuff from this person. But we will quietly ignore them $mails = $xpath->query("/atom:feed/dfrn:mail");
// rather than a blatant "go away" message. foreach ($mails as $mail) {
logger('ignoring contact '.$importer["id"]); self::processMail($xpath, $mail, $importer);
return 403; }
}
$mails = $xpath->query("/atom:feed/dfrn:mail"); $suggestions = $xpath->query("/atom:feed/dfrn:suggest");
foreach ($mails as $mail) { foreach ($suggestions as $suggestion) {
self::processMail($xpath, $mail, $importer); self::processSuggestion($xpath, $suggestion, $importer);
} }
$suggestions = $xpath->query("/atom:feed/dfrn:suggest");
foreach ($suggestions as $suggestion) {
self::processSuggestion($xpath, $suggestion, $importer);
} }
$deletions = $xpath->query("/atom:feed/at:deleted-entry"); $deletions = $xpath->query("/atom:feed/at:deleted-entry");
@ -2895,7 +2936,7 @@ class DFRN
self::processEntry($header, $xpath, $entry, $importer, $xml); self::processEntry($header, $xpath, $entry, $importer, $xml);
} }
} }
logger("Import done for user " . $importer["uid"] . " from contact " . $importer["id"], LOGGER_DEBUG); logger("Import done for user " . $importer["importer_uid"] . " from contact " . $importer["id"], LOGGER_DEBUG);
return 200; return 200;
} }

View file

@ -3205,7 +3205,7 @@ class Diaspora
* *
* @return string The message that will be transmitted to other servers * @return string The message that will be transmitted to other servers
*/ */
private static function buildMessage($msg, $user, $contact, $prvkey, $pubkey, $public = false) public static function buildMessage($msg, $user, $contact, $prvkey, $pubkey, $public = false)
{ {
// The message is put into an envelope with the sender's signature // The message is put into an envelope with the sender's signature
$envelope = self::buildMagicEnvelope($msg, $user); $envelope = self::buildMagicEnvelope($msg, $user);