$url = $apcontact['url'];
}
- $data = ActivityPub::fetchContent($url);
- if (empty($data)) {
+ $curlResult = HTTPSignature::fetchRaw($url);
+ $failed = empty($curlResult) || empty($curlResult->getBody()) ||
+ (!$curlResult->isSuccess() && ($curlResult->getReturnCode() != 410));
+
+ if (!$failed) {
+ $data = json_decode($curlResult->getBody(), true);
+ $failed = empty($data) || !is_array($data);
+ }
+
+ if (!$failed && ($curlResult->getReturnCode() == 410)) {
+ $data = ['@context' => ActivityPub::CONTEXT, 'id' => $url, 'type' => 'Tombstone'];
+ }
+
+ if ($failed) {
self::markForArchival($fetched_contact ?: []);
return $fetched_contact;
}
$compacted = JsonLD::compact($data);
-
if (empty($compacted['@id'])) {
return $fetched_contact;
}
}
// Quit if none of the basic values are set
- if (empty($apcontact['url']) || empty($apcontact['inbox']) || empty($apcontact['type'])) {
+ if (empty($apcontact['url']) || empty($apcontact['type']) || (($apcontact['type'] != 'Tombstone') && empty($apcontact['inbox']))) {
return $fetched_contact;
+ } elseif ($apcontact['type'] == 'Tombstone') {
+ // The "inbox" field must have a content
+ $apcontact['inbox'] = '';
}
// Quit if this doesn't seem to be an account at all
{
// We want just to make sure that we don't delete our "self" contact
$contact = DBA::selectFirst('contact', ['uid'], ['id' => $id, 'self' => false]);
- if (!DBA::isResult($contact) || !intval($contact['uid'])) {
+ if (!DBA::isResult($contact)) {
return;
}
DBA::update('contact', $fields, ['id' => $cids]);
}
+ public static function deleteContactByUrl(string $url)
+ {
+ // Update contact data for all users
+ $condition = ['self' => false, 'nurl' => Strings::normaliseLink($url)];
+ $contacts = DBA::select('contact', ['id', 'uid'], $condition);
+ while ($contact = DBA::fetch($contacts)) {
+ Logger::info('Deleting contact', ['id' => $contact['id'], 'uid' => $contact['uid'], 'url' => $url]);
+ self::remove($contact['id']);
+ }
+ }
+
/**
* Helper function for "updateFromProbe". Updates personal and public contact
*
return false;
}
+ if (!empty($ret['account-type']) && $ret['account-type'] == User::ACCOUNT_TYPE_DELETED) {
+ Logger::info('Deleted account', ['id' => $id, 'url' => $ret['url'], 'ret' => $ret]);
+ self::remove($id);
+
+ // Delete all contacts with the same URL
+ self::deleteContactByUrl($ret['url']);
+ return true;
+ }
+
$uid = $contact['uid'];
unset($contact['uid']);
const ACCOUNT_TYPE_NEWS = 2;
const ACCOUNT_TYPE_COMMUNITY = 3;
const ACCOUNT_TYPE_RELAY = 4;
+ const ACCOUNT_TYPE_DELETED = 127;
/**
* @}
*/
// It shouldn't happen but it does - spaces in URL
$request['url'] = str_replace(' ', '+', $request['url']);
- $fetchResult = HTTPSignature::fetchRaw($request['url'], local_user(), true, ['timeout' => 10]);
+ $fetchResult = HTTPSignature::fetchRaw($request['url'], local_user(), ['timeout' => 10]);
$img_str = $fetchResult->getBody();
// If there is an error then return a blank image
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
'sensitive' => 'as:sensitive', 'Hashtag' => 'as:Hashtag',
'directMessage' => 'litepub:directMessage']];
- const ACCOUNT_TYPES = ['Person', 'Organization', 'Service', 'Group', 'Application'];
+ const ACCOUNT_TYPES = ['Person', 'Organization', 'Service', 'Group', 'Application', 'Tombstone'];
/**
* Checks if the web request is done for the AP protocol
*
case 'Application':
$accounttype = User::ACCOUNT_TYPE_RELAY;
break;
- }
+ case 'Tombstone':
+ $accounttype = User::ACCOUNT_TYPE_DELETED;
+ break;
+ }
return $accounttype;
}
*/
public static function fetch($request, $uid)
{
- $opts = ['accept_content' => 'application/activity+json, application/ld+json'];
- $curlResult = self::fetchRaw($request, $uid, false, $opts);
+ $curlResult = self::fetchRaw($request, $uid);
if (empty($curlResult)) {
return false;
* @return object CurlResult
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function fetchRaw($request, $uid = 0, $binary = false, $opts = [])
+ public static function fetchRaw($request, $uid = 0, $opts = ['accept_content' => 'application/activity+json, application/ld+json'])
{
$header = [];
*/
class RemoveContact {
public static function execute($id) {
-
// Only delete if the contact is to be deleted
$contact = DBA::selectFirst('contact', ['uid'], ['deleted' => true, 'id' => $id]);
if (!DBA::isResult($contact)) {
return;
}
+ Logger::info('Start deleting contact', ['id' => $id]);
// Now we delete the contact and all depending tables
- $condition = ['uid' => $contact['uid'], 'contact-id' => $id];
+ if ($contact['uid'] == 0) {
+ DBA::delete('post-tag', ['cid' => $id]);
+ $condition = ["`author-id` = ? OR `owner-id` = ? OR `causer-id` = ? OR `contact-id` = ?",
+ $id, $id, $id, $id];
+ } else {
+ $condition = ['uid' => $contact['uid'], 'contact-id' => $id];
+ }
do {
$items = Item::select(['id', 'guid'], $condition, ['limit' => 100]);
while ($item = Item::fetch($items)) {
DBA::close($items);
} while (Item::exists($condition));
- Photo::delete(['uid' => $contact['uid'], 'contact-id' => $id]);
- DBA::delete('contact', ['id' => $id]);
+ Photo::delete(['contact-id' => $id]);
+ $ret = DBA::delete('contact', ['id' => $id]);
+ Logger::info('Deleted contact', ['id' => $id, 'result' => $ret]);
}
}