Merge pull request #9664 from annando/delete-contacts

Delete removed contacts
This commit is contained in:
Hypolite Petovan 2020-12-16 11:28:56 -05:00 committed by GitHub
commit 1414d43597
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 58 additions and 14 deletions

View file

@ -147,14 +147,25 @@ class APContact
$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;
}
@ -207,8 +218,11 @@ class APContact
}
// 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

View file

@ -724,7 +724,7 @@ class Contact
{
// 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;
}
@ -1762,6 +1762,17 @@ class Contact
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
*
@ -1914,6 +1925,15 @@ class 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']);

View file

@ -97,6 +97,7 @@ class User
const ACCOUNT_TYPE_NEWS = 2;
const ACCOUNT_TYPE_COMMUNITY = 3;
const ACCOUNT_TYPE_RELAY = 4;
const ACCOUNT_TYPE_DELETED = 127;
/**
* @}
*/

View file

@ -104,7 +104,7 @@ class Proxy extends BaseModule
// 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

View file

@ -68,7 +68,7 @@ class ActivityPub
'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
*
@ -113,6 +113,9 @@ class ActivityPub
case 'Application':
$accounttype = User::ACCOUNT_TYPE_RELAY;
break;
case 'Tombstone':
$accounttype = User::ACCOUNT_TYPE_DELETED;
break;
}
return $accounttype;

View file

@ -376,8 +376,7 @@ class HTTPSignature
*/
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;
@ -410,7 +409,7 @@ class HTTPSignature
* @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 = [];

View file

@ -31,15 +31,21 @@ use Friendica\Model\Photo;
*/
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)) {
@ -49,7 +55,8 @@ class RemoveContact {
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]);
}
}