Use "author_handle" for the author handle extracted from Diaspora XML messages
- We have structured data under the variable name "author" - Remove unused $uid parameter from Diaspora::storeByGuid - Convert $person parameter to just its URL in Diaspora::authorContactByUrl - Flip parameters in getUriFromGuid to get rid of $onlyfound
This commit is contained in:
parent
d5e005f90d
commit
ace80ca1b4
3 changed files with 416 additions and 154 deletions
|
@ -42,6 +42,7 @@ use Friendica\Model\Post;
|
|||
use Friendica\Model\Tag;
|
||||
use Friendica\Model\User;
|
||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||
use Friendica\Network\HTTPException\InternalServerErrorException;
|
||||
use Friendica\Network\Probe;
|
||||
use Friendica\Util\Crypto;
|
||||
use Friendica\Util\DateTimeFormat;
|
||||
|
@ -161,8 +162,12 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
$key = self::key($handle);
|
||||
try {
|
||||
$key = self::key(WebFingerUri::fromString($handle));
|
||||
if ($key == '') {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
Logger::notice("Couldn't get a key for handle " . $handle . ". Discarding.");
|
||||
return false;
|
||||
}
|
||||
|
@ -300,8 +305,13 @@ class Diaspora
|
|||
}
|
||||
}
|
||||
|
||||
$key = self::key($author_addr);
|
||||
try {
|
||||
$author = WebFingerUri::fromString($author_addr);
|
||||
$key = self::key($author);
|
||||
if ($key == '') {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
Logger::notice("Couldn't get a key for handle " . $author_addr . ". Discarding.");
|
||||
if ($no_exit) {
|
||||
return false;
|
||||
|
@ -322,7 +332,7 @@ class Diaspora
|
|||
|
||||
return [
|
||||
'message' => (string)Strings::base64UrlDecode($base->data),
|
||||
'author' => XML::unescape($author_addr),
|
||||
'author' => $author->getAddr(),
|
||||
'key' => (string)$key
|
||||
];
|
||||
}
|
||||
|
@ -356,7 +366,7 @@ class Diaspora
|
|||
|
||||
if ($children->header) {
|
||||
$public = true;
|
||||
$author_link = str_replace('acct:', '', $children->header->author_id);
|
||||
$idom = $children->header;
|
||||
} else {
|
||||
// This happens with posts from a relais
|
||||
if (empty($privKey)) {
|
||||
|
@ -384,8 +394,13 @@ class Diaspora
|
|||
|
||||
$inner_iv = base64_decode($idom->iv);
|
||||
$inner_aes_key = base64_decode($idom->aes_key);
|
||||
}
|
||||
|
||||
$author_link = str_replace('acct:', '', $idom->author_id);
|
||||
try {
|
||||
$author = WebFingerUri::fromString($idom->author_id);
|
||||
} catch (\Throwable $e) {
|
||||
Logger::notice('Could not retrieve author URI.', ['idom' => $idom]);
|
||||
throw new \Friendica\Network\HTTPException\BadRequestException();
|
||||
}
|
||||
|
||||
$dom = $basedom->children(ActivityNamespace::SALMON_ME);
|
||||
|
@ -439,17 +454,12 @@ class Diaspora
|
|||
$inner_decrypted = self::aesDecrypt($inner_aes_key, $inner_iv, $inner_encrypted);
|
||||
}
|
||||
|
||||
if (!$author_link) {
|
||||
Logger::notice('Could not retrieve author URI.');
|
||||
throw new \Friendica\Network\HTTPException\BadRequestException();
|
||||
}
|
||||
// Once we have the author URI, go to the web and try to find their public key
|
||||
// (first this will look it up locally if it is in the fcontact cache)
|
||||
// This will also convert diaspora public key from pkcs#1 to pkcs#8
|
||||
|
||||
Logger::notice('Fetching key for '.$author_link);
|
||||
$key = self::key($author_link);
|
||||
|
||||
Logger::notice('Fetching key for ' . $author);
|
||||
$key = self::key($author);
|
||||
if (!$key) {
|
||||
Logger::notice('Could not retrieve author key.');
|
||||
throw new \Friendica\Network\HTTPException\BadRequestException();
|
||||
|
@ -465,9 +475,9 @@ class Diaspora
|
|||
Logger::notice('Message verified.');
|
||||
|
||||
return [
|
||||
'message' => (string)$inner_decrypted,
|
||||
'author' => XML::unescape($author_link),
|
||||
'key' => (string)$key
|
||||
'message' => $inner_decrypted,
|
||||
'author' => $author->getAddr(),
|
||||
'key' => $key
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -520,7 +530,7 @@ class Diaspora
|
|||
{
|
||||
// The sender is the handle of the contact that sent the message.
|
||||
// This will often be different with relayed messages (for example "like" and "comment")
|
||||
$sender = $msg['author'];
|
||||
$sender = WebFingerUri::fromString($msg['author']);
|
||||
|
||||
// This is only needed for private postings since this is already done for public ones before
|
||||
if (is_null($fields)) {
|
||||
|
@ -535,7 +545,7 @@ class Diaspora
|
|||
|
||||
$type = $fields->getName();
|
||||
|
||||
Logger::info('Received message', ['type' => $type, 'sender' => $sender, 'user' => $importer['uid']]);
|
||||
Logger::info('Received message', ['type' => $type, 'sender' => $sender->getAddr(), 'user' => $importer['uid']]);
|
||||
|
||||
switch ($type) {
|
||||
case 'account_migration':
|
||||
|
@ -743,7 +753,7 @@ class Diaspora
|
|||
}
|
||||
|
||||
if (isset($parent_author_signature)) {
|
||||
$key = self::key($msg['author']);
|
||||
$key = self::key(WebFingerUri::fromString($msg['author']));
|
||||
if (empty($key)) {
|
||||
Logger::info('No key found for parent', ['author' => $msg['author']]);
|
||||
return false;
|
||||
|
@ -755,8 +765,12 @@ class Diaspora
|
|||
}
|
||||
}
|
||||
|
||||
$key = self::key($fields->author);
|
||||
try {
|
||||
$key = self::key(WebFingerUri::fromString($fields->author));
|
||||
if (empty($key)) {
|
||||
throw new \InvalidArgumentException();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Logger::info('No key found', ['author' => $fields->author]);
|
||||
return false;
|
||||
}
|
||||
|
@ -772,19 +786,17 @@ class Diaspora
|
|||
/**
|
||||
* Fetches the public key for a given handle
|
||||
*
|
||||
* @param string $handle The handle
|
||||
* @param WebFingerUri $uri The handle
|
||||
*
|
||||
* @return string The public key
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function key(string $handle = null): string
|
||||
private static function key(WebFingerUri $uri): string
|
||||
{
|
||||
$handle = strval($handle);
|
||||
Logger::notice('Fetching diaspora key', ['handle' => $uri->getAddr(), 'callstack' => System::callstack(20)]);
|
||||
|
||||
Logger::notice('Fetching diaspora key', ['handle' => $handle, 'callstack' => System::callstack(20)]);
|
||||
|
||||
$fcontact = FContact::getByURL($handle);
|
||||
$fcontact = FContact::getByURL($uri);
|
||||
if (!empty($fcontact['pubkey'])) {
|
||||
return $fcontact['pubkey'];
|
||||
}
|
||||
|
@ -795,18 +807,16 @@ class Diaspora
|
|||
/**
|
||||
* Get a contact id for a given handle
|
||||
*
|
||||
* @todo Move to Friendica\Model\Contact
|
||||
*
|
||||
* @param int $uid The user id
|
||||
* @param string $handle The handle in the format user@domain.tld
|
||||
* @param WebFingerUri $uri
|
||||
*
|
||||
* @return array Contact data
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function contactByHandle(int $uid, string $handle): array
|
||||
private static function contactByHandle(int $uid, WebFingerUri $uri): array
|
||||
{
|
||||
return Contact::getByURL($handle, null, [], $uid);
|
||||
return Contact::getByURL($uri->getAddr(), null, [], $uid);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -875,20 +885,21 @@ class Diaspora
|
|||
* Fetches the contact id for a handle and checks if posting is allowed
|
||||
*
|
||||
* @param array $importer Array of the importer user
|
||||
* @param string $handle The checked handle in the format user@domain.tld
|
||||
* @param WebFingerUri $contact_uri The checked contact
|
||||
* @param bool $is_comment Is the check for a comment?
|
||||
*
|
||||
* @return array|bool The contact data or false on error
|
||||
* @throws \Exception
|
||||
* @throws InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function allowedContactByHandle(array $importer, string $handle, bool $is_comment = false)
|
||||
private static function allowedContactByHandle(array $importer, WebFingerUri $contact_uri, bool $is_comment = false)
|
||||
{
|
||||
$contact = self::contactByHandle($importer['uid'], $handle);
|
||||
$contact = self::contactByHandle($importer['uid'], $contact_uri);
|
||||
if (!$contact) {
|
||||
Logger::notice('A Contact for handle ' . $handle . ' and user ' . $importer['uid'] . ' was not found');
|
||||
Logger::notice('A Contact for handle ' . $contact_uri . ' and user ' . $importer['uid'] . ' was not found');
|
||||
// If a contact isn't found, we accept it anyway if it is a comment
|
||||
if ($is_comment && ($importer['uid'] != 0)) {
|
||||
return self::contactByHandle(0, $handle);
|
||||
return self::contactByHandle(0, $contact_uri);
|
||||
} elseif ($is_comment) {
|
||||
return $importer;
|
||||
} else {
|
||||
|
@ -897,7 +908,7 @@ class Diaspora
|
|||
}
|
||||
|
||||
if (!self::postAllow($importer, $contact, $is_comment)) {
|
||||
Logger::notice('The handle: ' . $handle . ' is not allowed to post to user ' . $importer['uid']);
|
||||
Logger::notice('The handle: ' . $contact_uri . ' is not allowed to post to user ' . $importer['uid']);
|
||||
return false;
|
||||
}
|
||||
return $contact;
|
||||
|
@ -1011,7 +1022,7 @@ class Diaspora
|
|||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
public static function storeByGuid(string $guid, string $server, bool $force)
|
||||
private static function storeByGuid(string $guid, string $server, bool $force)
|
||||
{
|
||||
$serverparts = parse_url($server);
|
||||
|
||||
|
@ -1092,24 +1103,26 @@ class Diaspora
|
|||
return self::message($source_xml->root_guid, $server, ++$level);
|
||||
}
|
||||
|
||||
$author = '';
|
||||
$author_handle = '';
|
||||
|
||||
// Fetch the author - for the old and the new Diaspora version
|
||||
if ($source_xml->post->status_message && $source_xml->post->status_message->diaspora_handle) {
|
||||
$author = (string)$source_xml->post->status_message->diaspora_handle;
|
||||
$author_handle = (string)$source_xml->post->status_message->diaspora_handle;
|
||||
} elseif ($source_xml->author && ($source_xml->getName() == 'status_message')) {
|
||||
$author = (string)$source_xml->author;
|
||||
$author_handle = (string)$source_xml->author;
|
||||
}
|
||||
|
||||
try {
|
||||
$author = WebFingerUri::fromString($author_handle);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
// If this isn't a "status_message" then quit
|
||||
if (!$author) {
|
||||
Logger::info("Message doesn't seem to be a status message");
|
||||
return false;
|
||||
}
|
||||
|
||||
return [
|
||||
'message' => $x,
|
||||
'author' => $author,
|
||||
'author' => $author->getAddr(),
|
||||
'key' => self::key($author)
|
||||
];
|
||||
}
|
||||
|
@ -1159,13 +1172,13 @@ class Diaspora
|
|||
*
|
||||
* @param int $uid The user id
|
||||
* @param string $guid message guid
|
||||
* @param string $author The handle of the item
|
||||
* @param WebFingerUri $author
|
||||
* @param array $contact The contact of the item owner
|
||||
*
|
||||
* @return array|bool the item record or false on failure
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function parentItem(int $uid, string $guid, string $author, array $contact)
|
||||
private static function parentItem(int $uid, string $guid, WebFingerUri $author, array $contact)
|
||||
{
|
||||
$fields = ['id', 'parent', 'body', 'wall', 'uri', 'guid', 'private', 'origin',
|
||||
'author-name', 'author-link', 'author-avatar', 'gravity',
|
||||
|
@ -1200,10 +1213,10 @@ class Diaspora
|
|||
}
|
||||
|
||||
/**
|
||||
* returns contact details
|
||||
* returns contact details for the given user
|
||||
*
|
||||
* @param array $def_contact The default contact if the person isn't found
|
||||
* @param array $person The record of the person
|
||||
* @param array $def_contact The default details if the contact isn't found
|
||||
* @param string $contact_url The url of the contact
|
||||
* @param int $uid The user id
|
||||
*
|
||||
* @return array
|
||||
|
@ -1211,9 +1224,9 @@ class Diaspora
|
|||
* 'network' => network type
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function authorContactByUrl(array $def_contact, array $person, int $uid): array
|
||||
private static function authorContactByUrl(array $def_contact, string $contact_url, int $uid): array
|
||||
{
|
||||
$condition = ['nurl' => Strings::normaliseLink($person['url']), 'uid' => $uid];
|
||||
$condition = ['nurl' => Strings::normaliseLink($contact_url), 'uid' => $uid];
|
||||
$contact = DBA::selectFirst('contact', ['id', 'network'], $condition);
|
||||
if (DBA::isResult($contact)) {
|
||||
$cid = $contact['id'];
|
||||
|
@ -1318,21 +1331,27 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveAccountMigration(array $importer, SimpleXMLElement $data): bool
|
||||
{
|
||||
$old_handle = XML::unescape($data->author);
|
||||
$new_handle = XML::unescape($data->profile->author);
|
||||
$signature = XML::unescape($data->signature);
|
||||
|
||||
$contact = self::contactByHandle($importer['uid'], $old_handle);
|
||||
if (!$contact) {
|
||||
Logger::notice('Cannot find contact for sender: ' . $old_handle . ' and user ' . $importer['uid']);
|
||||
try {
|
||||
$old_author = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$new_author = WebFingerUri::fromString(XML::unescape($data->profile->author));
|
||||
} catch (\Throwable $e) {
|
||||
Logger::notice('Cannot find handles for sender and user', ['data' => $data]);
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger::notice('Got migration for ' . $old_handle . ', to ' . $new_handle . ' with user ' . $importer['uid']);
|
||||
$signature = XML::unescape($data->signature);
|
||||
|
||||
$contact = self::contactByHandle($importer['uid'], $old_author);
|
||||
if (!$contact) {
|
||||
Logger::notice('Cannot find contact for sender: ' . $old_author . ' and user ' . $importer['uid']);
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger::notice('Got migration for ' . $old_author . ', to ' . $new_author . ' with user ' . $importer['uid']);
|
||||
|
||||
// Check signature
|
||||
$signed_text = 'AccountMigration:' . $old_handle . ':' . $new_handle;
|
||||
$key = self::key($old_handle);
|
||||
$signed_text = 'AccountMigration:' . $old_author . ':' . $new_author;
|
||||
$key = self::key($old_author);
|
||||
if (!Crypto::rsaVerify($signed_text, $signature, $key, 'sha256')) {
|
||||
Logger::notice('No valid signature for migration.');
|
||||
return false;
|
||||
|
@ -1342,9 +1361,9 @@ class Diaspora
|
|||
self::receiveProfile($importer, $data->profile);
|
||||
|
||||
// change the technical stuff in contact
|
||||
$data = Probe::uri($new_handle);
|
||||
$data = Probe::uri($new_author);
|
||||
if ($data['network'] == Protocol::PHANTOM) {
|
||||
Logger::notice("Account for " . $new_handle . " couldn't be probed.");
|
||||
Logger::notice("Account for " . $new_author . " couldn't be probed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1360,7 +1379,7 @@ class Diaspora
|
|||
'network' => $data['network'],
|
||||
];
|
||||
|
||||
Contact::update($fields, ['addr' => $old_handle]);
|
||||
Contact::update($fields, ['addr' => $old_author->getAddr()]);
|
||||
|
||||
Logger::notice('Contacts are updated.');
|
||||
|
||||
|
@ -1377,15 +1396,15 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveAccountDeletion(SimpleXMLElement $data): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author_handle = XML::unescape($data->author);
|
||||
|
||||
$contacts = DBA::select('contact', ['id'], ['addr' => $author]);
|
||||
$contacts = DBA::select('contact', ['id'], ['addr' => $author_handle]);
|
||||
while ($contact = DBA::fetch($contacts)) {
|
||||
Contact::remove($contact['id']);
|
||||
}
|
||||
DBA::close($contacts);
|
||||
|
||||
Logger::notice('Removed contacts for ' . $author);
|
||||
Logger::notice('Removed contacts for ' . $author_handle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1393,21 +1412,20 @@ class Diaspora
|
|||
/**
|
||||
* Fetch the uri from our database if we already have this item (maybe from ourselves)
|
||||
*
|
||||
* @param string $author Author handle
|
||||
* @param string $guid Message guid
|
||||
* @param boolean $onlyfound Only return uri when found in the database
|
||||
* @param WebFingerUri|null $person_uri Optional person to derive the base URL from
|
||||
*
|
||||
* @return string The constructed uri or the one from our database or empty string on if $onlyfound is true
|
||||
* @return string The constructed uri or the one from our database or empty string
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function getUriFromGuid(string $author, string $guid, bool $onlyfound = false): string
|
||||
private static function getUriFromGuid(string $guid, WebFingerUri $person_uri = null): string
|
||||
{
|
||||
$item = Post::selectFirst(['uri'], ['guid' => $guid]);
|
||||
if (DBA::isResult($item)) {
|
||||
return $item['uri'];
|
||||
} elseif (!$onlyfound) {
|
||||
$person = FContact::getByURL($author);
|
||||
} elseif ($person_uri) {
|
||||
$person = FContact::getByURL($person_uri);
|
||||
|
||||
$parts = parse_url($person['url']);
|
||||
unset($parts['path']);
|
||||
|
@ -1457,18 +1475,18 @@ class Diaspora
|
|||
* Processes an incoming comment
|
||||
*
|
||||
* @param array $importer Array of the importer user
|
||||
* @param string $sender The sender of the message
|
||||
* @param WebFingerUri $sender The sender of the message
|
||||
* @param SimpleXMLElement $data The message object
|
||||
* @param string $xml The original XML of the message
|
||||
* @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH)
|
||||
*
|
||||
* @return int The message id of the generated comment or "false" if there was an error
|
||||
* @return bool The message id of the generated comment or "false" if there was an error
|
||||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function receiveComment(array $importer, string $sender, SimpleXMLElement $data, string $xml, int $direction): bool
|
||||
private static function receiveComment(array $importer, WebFingerUri $sender, SimpleXMLElement $data, string $xml, int $direction): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$guid = XML::unescape($data->guid);
|
||||
$parent_guid = XML::unescape($data->parent_guid);
|
||||
$text = XML::unescape($data->text);
|
||||
|
@ -1481,7 +1499,7 @@ class Diaspora
|
|||
|
||||
if (isset($data->thread_parent_guid)) {
|
||||
$thread_parent_guid = XML::unescape($data->thread_parent_guid);
|
||||
$thr_parent = self::getUriFromGuid('', $thread_parent_guid, true);
|
||||
$thr_parent = self::getUriFromGuid($thread_parent_guid);
|
||||
} else {
|
||||
$thr_parent = '';
|
||||
}
|
||||
|
@ -1512,7 +1530,7 @@ class Diaspora
|
|||
}
|
||||
|
||||
// Fetch the contact id - if we know this contact
|
||||
$author_contact = self::authorContactByUrl($contact, $person, $importer['uid']);
|
||||
$author_contact = self::authorContactByUrl($contact, $person['url'], $importer['uid']);
|
||||
|
||||
$datarray = [];
|
||||
|
||||
|
@ -1530,7 +1548,7 @@ class Diaspora
|
|||
$datarray = self::setDirection($datarray, $direction);
|
||||
|
||||
$datarray['guid'] = $guid;
|
||||
$datarray['uri'] = self::getUriFromGuid($author, $guid);
|
||||
$datarray['uri'] = self::getUriFromGuid($guid, $author);
|
||||
$datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]);
|
||||
|
||||
$datarray['verb'] = Activity::POST;
|
||||
|
@ -1601,16 +1619,16 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveConversationMessage(array $importer, array $contact, SimpleXMLElement $data, array $msg, $mesg, array $conversation): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author_handle = XML::unescape($data->author);
|
||||
$guid = XML::unescape($data->guid);
|
||||
$subject = XML::unescape($data->subject);
|
||||
|
||||
// "diaspora_handle" is the element name from the old version
|
||||
// "author" is the element name from the new version
|
||||
if ($mesg->author) {
|
||||
$msg_author = XML::unescape($mesg->author);
|
||||
$msg_author_handle = XML::unescape($mesg->author);
|
||||
} elseif ($mesg->diaspora_handle) {
|
||||
$msg_author = XML::unescape($mesg->diaspora_handle);
|
||||
$msg_author_handle = XML::unescape($mesg->diaspora_handle);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -1626,9 +1644,8 @@ class Diaspora
|
|||
}
|
||||
|
||||
$body = Markdown::toBBCode($msg_text);
|
||||
$message_uri = $msg_author . ':' . $msg_guid;
|
||||
|
||||
$person = FContact::getByURL($msg_author);
|
||||
$person = FContact::getByURL($msg_author_handle);
|
||||
|
||||
return Mail::insert([
|
||||
'uid' => $importer['uid'],
|
||||
|
@ -1640,8 +1657,8 @@ class Diaspora
|
|||
'contact-id' => $contact['id'],
|
||||
'title' => $subject,
|
||||
'body' => $body,
|
||||
'uri' => $message_uri,
|
||||
'parent-uri' => $author . ':' . $guid,
|
||||
'uri' => $msg_author_handle . ':' . $msg_guid,
|
||||
'parent-uri' => $author_handle . ':' . $guid,
|
||||
'created' => $msg_created_at
|
||||
]);
|
||||
}
|
||||
|
@ -1658,7 +1675,7 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveConversation(array $importer, array $msg, SimpleXMLElement $data)
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author_handle = XML::unescape($data->author);
|
||||
$guid = XML::unescape($data->guid);
|
||||
$subject = XML::unescape($data->subject);
|
||||
$created_at = DateTimeFormat::utc(XML::unescape($data->created_at));
|
||||
|
@ -1671,7 +1688,7 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
$contact = self::allowedContactByHandle($importer, $msg['author'], true);
|
||||
$contact = self::allowedContactByHandle($importer, WebFingerUri::fromString($msg['author']), true);
|
||||
if (!$contact) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1685,7 +1702,7 @@ class Diaspora
|
|||
$r = DBA::insert('conv', [
|
||||
'uid' => $importer['uid'],
|
||||
'guid' => $guid,
|
||||
'creator' => $author,
|
||||
'creator' => $author_handle,
|
||||
'created' => $created_at,
|
||||
'updated' => DateTimeFormat::utcNow(),
|
||||
'subject' => $subject,
|
||||
|
@ -1712,7 +1729,7 @@ class Diaspora
|
|||
* Processes "like" messages
|
||||
*
|
||||
* @param array $importer Array of the importer user
|
||||
* @param string $sender The sender of the message
|
||||
* @param WebFingerUri $sender The sender of the message
|
||||
* @param SimpleXMLElement $data The message object
|
||||
* @param int $direction Indicates if the message had been fetched or pushed (self::PUSHED, self::FETCHED, self::FORCED_FETCH)
|
||||
*
|
||||
|
@ -1720,9 +1737,9 @@ class Diaspora
|
|||
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function receiveLike(array $importer, string $sender, SimpleXMLElement $data, int $direction): bool
|
||||
private static function receiveLike(array $importer, WebFingerUri $sender, SimpleXMLElement $data, int $direction): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$guid = XML::unescape($data->guid);
|
||||
$parent_guid = XML::unescape($data->parent_guid);
|
||||
$parent_type = XML::unescape($data->parent_type);
|
||||
|
@ -1760,7 +1777,7 @@ class Diaspora
|
|||
}
|
||||
|
||||
// Fetch the contact id - if we know this contact
|
||||
$author_contact = self::authorContactByUrl($contact, $person, $importer['uid']);
|
||||
$author_contact = self::authorContactByUrl($contact, $person['url'], $importer['uid']);
|
||||
|
||||
// "positive" = "false" would be a Dislike - wich isn't currently supported by Diaspora
|
||||
// We would accept this anyhow.
|
||||
|
@ -1784,7 +1801,7 @@ class Diaspora
|
|||
$datarray['owner-id'] = $datarray['author-id'] = Contact::getIdForURL($person['url'], 0);
|
||||
|
||||
$datarray['guid'] = $guid;
|
||||
$datarray['uri'] = self::getUriFromGuid($author, $guid);
|
||||
$datarray['uri'] = self::getUriFromGuid($guid, $author);
|
||||
|
||||
$datarray['verb'] = $verb;
|
||||
$datarray['gravity'] = Item::GRAVITY_ACTIVITY;
|
||||
|
@ -1843,7 +1860,7 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveMessage(array $importer, SimpleXMLElement $data): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$guid = XML::unescape($data->guid);
|
||||
$conversation_guid = XML::unescape($data->conversation_guid);
|
||||
$text = XML::unescape($data->text);
|
||||
|
@ -1858,18 +1875,13 @@ class Diaspora
|
|||
GServer::setProtocol($contact['gsid'], Post\DeliveryData::DIASPORA);
|
||||
}
|
||||
|
||||
$conversation = null;
|
||||
|
||||
$condition = ['uid' => $importer['uid'], 'guid' => $conversation_guid];
|
||||
$conversation = DBA::selectFirst('conv', [], $condition);
|
||||
|
||||
if (!DBA::isResult($conversation)) {
|
||||
Logger::notice('Conversation not available.');
|
||||
return false;
|
||||
}
|
||||
|
||||
$message_uri = $author . ':' . $guid;
|
||||
|
||||
$person = FContact::getByURL($author);
|
||||
if (!$person) {
|
||||
Logger::notice('Unable to find author details');
|
||||
|
@ -1891,7 +1903,7 @@ class Diaspora
|
|||
'title' => $conversation['subject'],
|
||||
'body' => $body,
|
||||
'reply' => 1,
|
||||
'uri' => $message_uri,
|
||||
'uri' => $author . ':' . $guid,
|
||||
'parent-uri' => $author . ':' . $conversation['guid'],
|
||||
'created' => $created_at
|
||||
]);
|
||||
|
@ -1910,7 +1922,7 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveParticipation(array $importer, SimpleXMLElement $data, int $direction): bool
|
||||
{
|
||||
$author = strtolower(XML::unescape($data->author));
|
||||
$author = WebFingerUri::fromString(strtolower(XML::unescape($data->author)));
|
||||
$guid = XML::unescape($data->guid);
|
||||
$parent_guid = XML::unescape($data->parent_guid);
|
||||
|
||||
|
@ -1947,7 +1959,7 @@ class Diaspora
|
|||
return false;
|
||||
}
|
||||
|
||||
$author_contact = self::authorContactByUrl($contact, $person, $importer['uid']);
|
||||
$author_contact = self::authorContactByUrl($contact, $person['url'], $importer['uid']);
|
||||
|
||||
// Store participation
|
||||
$datarray = [];
|
||||
|
@ -1964,7 +1976,7 @@ class Diaspora
|
|||
$datarray['owner-id'] = $datarray['author-id'] = Contact::getIdForURL($person['url'], 0);
|
||||
|
||||
$datarray['guid'] = $guid;
|
||||
$datarray['uri'] = self::getUriFromGuid($author, $guid);
|
||||
$datarray['uri'] = self::getUriFromGuid($guid, $author);
|
||||
|
||||
$datarray['verb'] = Activity::FOLLOW;
|
||||
$datarray['gravity'] = Item::GRAVITY_ACTIVITY;
|
||||
|
@ -2056,7 +2068,7 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveProfile(array $importer, SimpleXMLElement $data): bool
|
||||
{
|
||||
$author = strtolower(XML::unescape($data->author));
|
||||
$author = WebFingerUri::fromString(strtolower(XML::unescape($data->author)));
|
||||
|
||||
$contact = self::contactByHandle($importer['uid'], $author);
|
||||
if (!$contact) {
|
||||
|
@ -2084,16 +2096,13 @@ class Diaspora
|
|||
|
||||
$keywords = implode(', ', $keywords);
|
||||
|
||||
$handle_parts = explode('@', $author);
|
||||
$nick = $handle_parts[0];
|
||||
|
||||
if ($name === '') {
|
||||
$name = $handle_parts[0];
|
||||
$name = $author->getUser();
|
||||
}
|
||||
|
||||
if (preg_match('|^https?://|', $image_url) === 0) {
|
||||
// @TODO No HTTPS here?
|
||||
$image_url = 'http://' . $handle_parts[1] . $image_url;
|
||||
$image_url = 'http://' . $author->getFullHost() . $image_url;
|
||||
}
|
||||
|
||||
Contact::updateAvatar($contact['id'], $image_url);
|
||||
|
@ -2115,7 +2124,7 @@ class Diaspora
|
|||
|
||||
$fields = ['name' => $name, 'location' => $location,
|
||||
'name-date' => DateTimeFormat::utcNow(), 'about' => $about,
|
||||
'addr' => $author, 'nick' => $nick, 'keywords' => $keywords,
|
||||
'addr' => $author->getAddr(), 'nick' => $author->getUser(), 'keywords' => $keywords,
|
||||
'unsearchable' => !$searchable, 'sensitive' => $nsfw];
|
||||
|
||||
if (!empty($birthday)) {
|
||||
|
@ -2158,13 +2167,15 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveContactRequest(array $importer, SimpleXMLElement $data): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author_handle = XML::unescape($data->author);
|
||||
$recipient = XML::unescape($data->recipient);
|
||||
|
||||
if (!$author || !$recipient) {
|
||||
if (!$author_handle || !$recipient) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$author = WebFingerUri::fromString($author_handle);
|
||||
|
||||
// the current protocol version doesn't know these fields
|
||||
// That means that we will assume their existance
|
||||
if (isset($data->following)) {
|
||||
|
@ -2265,9 +2276,12 @@ class Diaspora
|
|||
* @param array $item Array of reshare post
|
||||
* @param integer $parent_message_id Id of the parent post
|
||||
* @param string $guid GUID string of reshare action
|
||||
* @param string $author Author handle
|
||||
* @param WebFingerUri $author Author handle
|
||||
* @return false|void
|
||||
* @throws InternalServerErrorException
|
||||
* @throws \ImagickException
|
||||
*/
|
||||
private static function addReshareActivity(array $item, int $parent_message_id, string $guid, string $author)
|
||||
private static function addReshareActivity(array $item, int $parent_message_id, string $guid, WebFingerUri $author)
|
||||
{
|
||||
$parent = Post::selectFirst(['uri', 'guid'], ['id' => $parent_message_id]);
|
||||
|
||||
|
@ -2284,7 +2298,7 @@ class Diaspora
|
|||
$datarray['owner-id'] = $datarray['author-id'];
|
||||
|
||||
$datarray['guid'] = $parent['guid'] . '-' . $guid;
|
||||
$datarray['uri'] = self::getUriFromGuid($author, $datarray['guid']);
|
||||
$datarray['uri'] = self::getUriFromGuid($datarray['guid'], $author);
|
||||
$datarray['thr-parent'] = $parent['uri'];
|
||||
|
||||
$datarray['verb'] = $datarray['body'] = Activity::ANNOUNCE;
|
||||
|
@ -2329,7 +2343,7 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveReshare(array $importer, SimpleXMLElement $data, string $xml, int $direction): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$guid = XML::unescape($data->guid);
|
||||
$created_at = DateTimeFormat::utc(XML::unescape($data->created_at));
|
||||
$root_author = XML::unescape($data->root_author);
|
||||
|
@ -2337,7 +2351,7 @@ class Diaspora
|
|||
/// @todo handle unprocessed property "provider_display_name"
|
||||
$public = XML::unescape($data->public);
|
||||
|
||||
$contact = self::allowedContactByHandle($importer, $author, false);
|
||||
$contact = self::allowedContactByHandle($importer, $author);
|
||||
if (!$contact) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2369,7 +2383,7 @@ class Diaspora
|
|||
$datarray['owner-id'] = $datarray['author-id'];
|
||||
|
||||
$datarray['guid'] = $guid;
|
||||
$datarray['uri'] = $datarray['thr-parent'] = self::getUriFromGuid($author, $guid);
|
||||
$datarray['uri'] = $datarray['thr-parent'] = self::getUriFromGuid($guid, $author);
|
||||
$datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]);
|
||||
|
||||
$datarray['verb'] = Activity::POST;
|
||||
|
@ -2448,13 +2462,13 @@ class Diaspora
|
|||
*/
|
||||
private static function itemRetraction(array $importer, array $contact, SimpleXMLElement $data): bool
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author_handle = XML::unescape($data->author);
|
||||
$target_guid = XML::unescape($data->target_guid);
|
||||
$target_type = XML::unescape($data->target_type);
|
||||
|
||||
$person = FContact::getByURL($author);
|
||||
$person = FContact::getByURL($author_handle);
|
||||
if (!is_array($person)) {
|
||||
Logger::notice('Unable to find author detail for ' . $author);
|
||||
Logger::notice('Unable to find author detail for ' . $author_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2506,13 +2520,13 @@ class Diaspora
|
|||
* Receives retraction messages
|
||||
*
|
||||
* @param array $importer Array of the importer user
|
||||
* @param string $sender The sender of the message
|
||||
* @param WebFingerUri $sender The sender of the message
|
||||
* @param SimpleXMLElement $data The message object
|
||||
*
|
||||
* @return bool Success
|
||||
* @throws \Exception
|
||||
*/
|
||||
private static function receiveRetraction(array $importer, string $sender, SimpleXMLElement $data)
|
||||
private static function receiveRetraction(array $importer, WebFingerUri $sender, SimpleXMLElement $data)
|
||||
{
|
||||
$target_type = XML::unescape($data->target_type);
|
||||
|
||||
|
@ -2639,14 +2653,14 @@ class Diaspora
|
|||
*/
|
||||
private static function receiveStatusMessage(array $importer, SimpleXMLElement $data, string $xml, int $direction)
|
||||
{
|
||||
$author = XML::unescape($data->author);
|
||||
$author = WebFingerUri::fromString(XML::unescape($data->author));
|
||||
$guid = XML::unescape($data->guid);
|
||||
$created_at = DateTimeFormat::utc(XML::unescape($data->created_at));
|
||||
$public = XML::unescape($data->public);
|
||||
$text = XML::unescape($data->text);
|
||||
$provider_display_name = XML::unescape($data->provider_display_name);
|
||||
|
||||
$contact = self::allowedContactByHandle($importer, $author, false);
|
||||
$contact = self::allowedContactByHandle($importer, $author);
|
||||
if (!$contact) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2672,7 +2686,7 @@ class Diaspora
|
|||
$datarray = [];
|
||||
|
||||
$datarray['guid'] = $guid;
|
||||
$datarray['uri'] = $datarray['thr-parent'] = self::getUriFromGuid($author, $guid);
|
||||
$datarray['uri'] = $datarray['thr-parent'] = self::getUriFromGuid($guid, $author);
|
||||
$datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]);
|
||||
|
||||
// Attach embedded pictures to the body
|
||||
|
@ -3089,16 +3103,16 @@ class Diaspora
|
|||
$owner = User::getOwnerDataById($item['uid']);
|
||||
}
|
||||
|
||||
$author = self::myHandle($owner);
|
||||
$author_handle = self::myHandle($owner);
|
||||
|
||||
$message = [
|
||||
'author' => $author,
|
||||
'author' => $author_handle,
|
||||
'guid' => System::createUUID(),
|
||||
'parent_type' => 'Post',
|
||||
'parent_guid' => $item['guid']
|
||||
];
|
||||
|
||||
Logger::info('Send participation for ' . $item['guid'] . ' by ' . $author);
|
||||
Logger::info('Send participation for ' . $item['guid'] . ' by ' . $author_handle);
|
||||
|
||||
// It doesn't matter what we store, we only want to avoid sending repeated notifications for the same item
|
||||
DI::cache()->set($cachekey, $item['guid'], Duration::QUARTER_HOUR);
|
||||
|
|
113
src/Protocol/WebFingerUri.php
Normal file
113
src/Protocol/WebFingerUri.php
Normal file
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Protocol;
|
||||
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
|
||||
class WebFingerUri
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $user;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $host;
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $port;
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $path;
|
||||
|
||||
private function __construct(string $user, string $host, int $port = null, string $path = null)
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->host = $host;
|
||||
$this->port = $port;
|
||||
$this->path = $path;
|
||||
|
||||
$this->validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $addr
|
||||
* @return WebFingerUri
|
||||
*/
|
||||
public static function fromString(string $addr): WebFingerUri
|
||||
{
|
||||
$uri = new Uri('acct://' . preg_replace('/^acct:/', '', $addr));
|
||||
|
||||
return new self($uri->getUserInfo(), $uri->getHost(), $uri->getPort(), $uri->getPath());
|
||||
}
|
||||
|
||||
private function validate()
|
||||
{
|
||||
if (!$this->user) {
|
||||
throw new \InvalidArgumentException('WebFinger URI User part is required');
|
||||
}
|
||||
|
||||
if (!$this->host) {
|
||||
throw new \InvalidArgumentException('WebFinger URI Host part is required');
|
||||
}
|
||||
}
|
||||
|
||||
public function getUser(): string
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function getHost(): string
|
||||
{
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
public function getFullHost(): string
|
||||
{
|
||||
return $this->host
|
||||
. ($this->port ? ':' . $this->port : '') .
|
||||
($this->path ?: '');
|
||||
}
|
||||
|
||||
public function getLongForm(): string
|
||||
{
|
||||
return 'acct:' . $this->getShortForm();
|
||||
}
|
||||
|
||||
public function getShortForm(): string
|
||||
{
|
||||
return $this->user . '@' . $this->getFullHost();
|
||||
}
|
||||
|
||||
public function getAddr(): string
|
||||
{
|
||||
return $this->getShortForm();
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->getShortForm();
|
||||
}
|
||||
}
|
135
tests/src/Protocol/WebFingerUriTest.php
Normal file
135
tests/src/Protocol/WebFingerUriTest.php
Normal file
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2022, the Friendica project
|
||||
*
|
||||
* @license GNU AGPL version 3 or any later version
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Main database structure configuration file.
|
||||
*
|
||||
* Here are described all the tables, fields and indexes Friendica needs to work.
|
||||
* The entry order is mostly alphabetic - with the exception of tables that are used in foreign keys.
|
||||
*
|
||||
* Syntax (braces indicate optionale values):
|
||||
* "<table name>" => [
|
||||
* "comment" => "Description of the table",
|
||||
* "fields" => [
|
||||
* "<field name>" => [
|
||||
* "type" => "<field type>{(<field size>)} <unsigned>",
|
||||
* "not null" => 0|1,
|
||||
* {"extra" => "auto_increment",}
|
||||
* {"default" => "<default value>",}
|
||||
* {"default" => NULL_DATE,} (for datetime fields)
|
||||
* {"primary" => "1",}
|
||||
* {"foreign|relation" => ["<foreign key table name>" => "<foreign key field name>"],}
|
||||
* "comment" => "Description of the fields"
|
||||
* ],
|
||||
* ...
|
||||
* ],
|
||||
* "indexes" => [
|
||||
* "PRIMARY" => ["<primary key field name>", ...],
|
||||
* "<index name>" => [{"UNIQUE",} "<field name>{(<key size>)}", ...]
|
||||
* ...
|
||||
* ],
|
||||
* ],
|
||||
*
|
||||
* Whenever possible prefer "foreign" before "relation" with the foreign keys.
|
||||
* "foreign" adds true foreign keys on the database level, while "relation" is just an indicator of a table relation without any consequences
|
||||
*
|
||||
* If you need to make any change, make sure to increment the DB_UPDATE_VERSION constant value below.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Friendica\Test\src\Protocol;
|
||||
|
||||
use Friendica\Protocol\WebFingerUri;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class WebFingerUriTest extends TestCase
|
||||
{
|
||||
public function dataFromString(): array
|
||||
{
|
||||
return [
|
||||
'long' => [
|
||||
'expectedLong' => 'acct:selma@www.example.com:8080/friend',
|
||||
'expectedShort' => 'selma@www.example.com:8080/friend',
|
||||
'input' => 'acct:selma@www.example.com:8080/friend',
|
||||
],
|
||||
'short' => [
|
||||
'expectedLong' => 'acct:selma@www.example.com:8080/friend',
|
||||
'expectedShort' => 'selma@www.example.com:8080/friend',
|
||||
'input' => 'selma@www.example.com:8080/friend',
|
||||
],
|
||||
'minimal' => [
|
||||
'expectedLong' => 'acct:bob@example.com',
|
||||
'expectedShort' => 'bob@example.com',
|
||||
'input' => 'bob@example.com',
|
||||
],
|
||||
'acct:' => [
|
||||
'expectedLong' => 'acct:alice@example.acct:90',
|
||||
'expectedShort' => 'alice@example.acct:90',
|
||||
'input' => 'alice@example.acct:90',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataFromString
|
||||
* @param string $expectedLong
|
||||
* @param string $expectedShort
|
||||
* @param string $input
|
||||
* @return void
|
||||
*/
|
||||
public function testFromString(string $expectedLong, string $expectedShort, string $input)
|
||||
{
|
||||
$uri = WebFingerUri::fromString($input);
|
||||
|
||||
$this->assertEquals($expectedLong, $uri->getLongForm());
|
||||
$this->assertEquals($expectedShort, $uri->getShortForm());
|
||||
}
|
||||
|
||||
public function dataFromStringFailure()
|
||||
{
|
||||
return [
|
||||
'missing user' => [
|
||||
'input' => 'example.com',
|
||||
],
|
||||
'missing user @' => [
|
||||
'input' => '@example.com',
|
||||
],
|
||||
'missing host' => [
|
||||
'input' => 'alice',
|
||||
],
|
||||
'missing host @' => [
|
||||
'input' => 'alice@',
|
||||
],
|
||||
'missing everything' => [
|
||||
'input' => '',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataFromStringFailure
|
||||
* @param string $input
|
||||
* @return void
|
||||
*/
|
||||
public function testFromStringFailure(string $input)
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
|
||||
WebFingerUri::fromString($input);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue