Merge pull request #8678 from annando/gserver-detection-type

Improved server detection / gsid introduced
This commit is contained in:
Hypolite Petovan 2020-05-22 10:25:37 -04:00 committed by GitHub
commit 669124e72f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 492 additions and 115 deletions

View file

@ -1,9 +1,37 @@
-- ------------------------------------------ -- ------------------------------------------
-- Friendica 2020.06-dev (Red Hot Poker) -- Friendica 2020.06-dev (Red Hot Poker)
-- DB_UPDATE_VERSION 1348 -- DB_UPDATE_VERSION 1350
-- ------------------------------------------ -- ------------------------------------------
--
-- TABLE gserver
--
CREATE TABLE IF NOT EXISTS `gserver` (
`id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
`url` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`nurl` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`version` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`site_name` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`info` text COMMENT '',
`register_policy` tinyint NOT NULL DEFAULT 0 COMMENT '',
`registered-users` int unsigned NOT NULL DEFAULT 0 COMMENT 'Number of registered users',
`directory-type` tinyint DEFAULT 0 COMMENT 'Type of directory service (Poco, Mastodon)',
`poco` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`noscrape` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`network` char(4) NOT NULL DEFAULT '' COMMENT '',
`platform` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`relay-subscribe` boolean NOT NULL DEFAULT '0' COMMENT 'Has the server subscribed to the relay system',
`relay-scope` varchar(10) NOT NULL DEFAULT '' COMMENT 'The scope of messages that the server wants to get',
`detection-method` tinyint unsigned COMMENT 'Method that had been used to detect that server',
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
`last_poco_query` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
`last_contact` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
`last_failure` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
PRIMARY KEY(`id`),
UNIQUE INDEX `nurl` (`nurl`(190))
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Global servers';
-- --
-- TABLE clients -- TABLE clients
-- --
@ -87,6 +115,7 @@ CREATE TABLE IF NOT EXISTS `contact` (
`unsearchable` boolean NOT NULL DEFAULT '0' COMMENT 'Contact prefers to not be searchable', `unsearchable` boolean NOT NULL DEFAULT '0' COMMENT 'Contact prefers to not be searchable',
`sensitive` boolean NOT NULL DEFAULT '0' COMMENT 'Contact posts sensitive content', `sensitive` boolean NOT NULL DEFAULT '0' COMMENT 'Contact posts sensitive content',
`baseurl` varchar(255) DEFAULT '' COMMENT 'baseurl of the contact', `baseurl` varchar(255) DEFAULT '' COMMENT 'baseurl of the contact',
`gsid` int unsigned COMMENT 'Global Server ID',
`reason` text COMMENT '', `reason` text COMMENT '',
`closeness` tinyint unsigned NOT NULL DEFAULT 99 COMMENT '', `closeness` tinyint unsigned NOT NULL DEFAULT 99 COMMENT '',
`info` mediumtext COMMENT '', `info` mediumtext COMMENT '',
@ -108,7 +137,9 @@ CREATE TABLE IF NOT EXISTS `contact` (
INDEX `nurl_uid` (`nurl`(32),`uid`), INDEX `nurl_uid` (`nurl`(32),`uid`),
INDEX `nick_uid` (`nick`(32),`uid`), INDEX `nick_uid` (`nick`(32),`uid`),
INDEX `dfrn-id` (`dfrn-id`(64)), INDEX `dfrn-id` (`dfrn-id`(64)),
INDEX `issued-id` (`issued-id`(64)) INDEX `issued-id` (`issued-id`(64)),
INDEX `gsid` (`gsid`),
FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='contact table'; ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='contact table';
-- --
@ -210,6 +241,7 @@ CREATE TABLE IF NOT EXISTS `apcontact` (
`alias` varchar(255) COMMENT '', `alias` varchar(255) COMMENT '',
`pubkey` text COMMENT '', `pubkey` text COMMENT '',
`baseurl` varchar(255) COMMENT 'baseurl of the ap contact', `baseurl` varchar(255) COMMENT 'baseurl of the ap contact',
`gsid` int unsigned COMMENT 'Global Server ID',
`generator` varchar(255) COMMENT 'Name of the contact\'s system', `generator` varchar(255) COMMENT 'Name of the contact\'s system',
`following_count` int unsigned DEFAULT 0 COMMENT 'Number of following contacts', `following_count` int unsigned DEFAULT 0 COMMENT 'Number of following contacts',
`followers_count` int unsigned DEFAULT 0 COMMENT 'Number of followers', `followers_count` int unsigned DEFAULT 0 COMMENT 'Number of followers',
@ -218,7 +250,9 @@ CREATE TABLE IF NOT EXISTS `apcontact` (
PRIMARY KEY(`url`), PRIMARY KEY(`url`),
INDEX `addr` (`addr`(32)), INDEX `addr` (`addr`(32)),
INDEX `alias` (`alias`(190)), INDEX `alias` (`alias`(190)),
INDEX `url` (`followers`(190)) INDEX `followers` (`followers`(190)),
INDEX `gsid` (`gsid`),
FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='ActivityPub compatible contacts - used in the ActivityPub implementation'; ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='ActivityPub compatible contacts - used in the ActivityPub implementation';
-- --
@ -463,13 +497,16 @@ CREATE TABLE IF NOT EXISTS `gcontact` (
`alias` varchar(255) NOT NULL DEFAULT '' COMMENT '', `alias` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`generation` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', `generation` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '',
`server_url` varchar(255) NOT NULL DEFAULT '' COMMENT 'baseurl of the contacts server', `server_url` varchar(255) NOT NULL DEFAULT '' COMMENT 'baseurl of the contacts server',
`gsid` int unsigned COMMENT 'Global Server ID',
PRIMARY KEY(`id`), PRIMARY KEY(`id`),
UNIQUE INDEX `nurl` (`nurl`(190)), UNIQUE INDEX `nurl` (`nurl`(190)),
INDEX `name` (`name`(64)), INDEX `name` (`name`(64)),
INDEX `nick` (`nick`(32)), INDEX `nick` (`nick`(32)),
INDEX `addr` (`addr`(64)), INDEX `addr` (`addr`(64)),
INDEX `hide_network_updated` (`hide`,`network`,`updated`), INDEX `hide_network_updated` (`hide`,`network`,`updated`),
INDEX `updated` (`updated`) INDEX `updated` (`updated`),
INDEX `gsid` (`gsid`),
FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='global contacts'; ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='global contacts';
-- --
@ -523,33 +560,6 @@ CREATE TABLE IF NOT EXISTS `group_member` (
UNIQUE INDEX `gid_contactid` (`gid`,`contact-id`) UNIQUE INDEX `gid_contactid` (`gid`,`contact-id`)
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='privacy groups, member info'; ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='privacy groups, member info';
--
-- TABLE gserver
--
CREATE TABLE IF NOT EXISTS `gserver` (
`id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID',
`url` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`nurl` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`version` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`site_name` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`info` text COMMENT '',
`register_policy` tinyint NOT NULL DEFAULT 0 COMMENT '',
`registered-users` int unsigned NOT NULL DEFAULT 0 COMMENT 'Number of registered users',
`directory-type` tinyint DEFAULT 0 COMMENT 'Type of directory service (Poco, Mastodon)',
`poco` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`noscrape` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`network` char(4) NOT NULL DEFAULT '' COMMENT '',
`platform` varchar(255) NOT NULL DEFAULT '' COMMENT '',
`relay-subscribe` boolean NOT NULL DEFAULT '0' COMMENT 'Has the server subscribed to the relay system',
`relay-scope` varchar(10) NOT NULL DEFAULT '' COMMENT 'The scope of messages that the server wants to get',
`created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '',
`last_poco_query` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
`last_contact` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
`last_failure` datetime DEFAULT '0001-01-01 00:00:00' COMMENT '',
PRIMARY KEY(`id`),
UNIQUE INDEX `nurl` (`nurl`(190))
) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Global servers';
-- --
-- TABLE gserver-tag -- TABLE gserver-tag
-- --

View file

@ -25,6 +25,7 @@ use Friendica\Core\Logger;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\DI; use Friendica\DI;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\GServer;
use Friendica\Model\Item; use Friendica\Model\Item;
use Friendica\Model\ItemURI; use Friendica\Model\ItemURI;
use Friendica\Model\PermissionSet; use Friendica\Model\PermissionSet;
@ -86,6 +87,15 @@ class PostUpdate
if (!self::update1347()) { if (!self::update1347()) {
return false; return false;
} }
if (!self::update1348()) {
return false;
}
if (!self::update1349()) {
return false;
}
if (!self::update1350()) {
return false;
}
return true; return true;
} }
@ -870,4 +880,163 @@ class PostUpdate
return false; return false;
} }
/**
* update the "gsid" (global server id) field in the contact table
*
* @return bool "true" when the job is done
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
private static function update1348()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1348) {
return true;
}
$id = DI::config()->get("system", "post_update_version_1348_id", 0);
Logger::info('Start', ['contact' => $id]);
$start_id = $id;
$rows = 0;
$condition = ["`id` > ? AND `gsid` IS NULL AND `baseurl` != '' AND NOT `baseurl` IS NULL", $id];
$params = ['order' => ['id'], 'limit' => 10000];
$contacts = DBA::select('contact', ['id', 'baseurl'], $condition, $params);
if (DBA::errorNo() != 0) {
Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
return false;
}
while ($contact = DBA::fetch($contacts)) {
$id = $contact['id'];
DBA::update('contact',
['gsid' => GServer::getID($contact['baseurl']), 'baseurl' => GServer::cleanURL($contact['baseurl'])],
['id' => $contact['id']]);
++$rows;
}
DBA::close($contacts);
DI::config()->set("system", "post_update_version_1348_id", $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
if ($start_id == $id) {
DI::config()->set("system", "post_update_version", 1348);
Logger::info('Done');
return true;
}
return false;
}
/**
* update the "gsid" (global server id) field in the apcontact table
*
* @return bool "true" when the job is done
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
private static function update1349()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1349) {
return true;
}
$id = DI::config()->get("system", "post_update_version_1349_id", 0);
Logger::info('Start', ['apcontact' => $id]);
$start_id = $id;
$rows = 0;
$condition = ["`url` > ? AND `gsid` IS NULL AND `baseurl` != '' AND NOT `baseurl` IS NULL", $id];
$params = ['order' => ['url'], 'limit' => 10000];
$apcontacts = DBA::select('apcontact', ['url', 'baseurl'], $condition, $params);
if (DBA::errorNo() != 0) {
Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
return false;
}
while ($apcontact = DBA::fetch($apcontacts)) {
$id = $apcontact['url'];
DBA::update('apcontact',
['gsid' => GServer::getID($apcontact['baseurl']), 'baseurl' => GServer::cleanURL($apcontact['baseurl'])],
['url' => $apcontact['url']]);
++$rows;
}
DBA::close($apcontacts);
DI::config()->set("system", "post_update_version_1349_id", $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
if ($start_id == $id) {
DI::config()->set("system", "post_update_version", 1349);
Logger::info('Done');
return true;
}
return false;
}
/**
* update the "gsid" (global server id) field in the gcontact table
*
* @return bool "true" when the job is done
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
private static function update1350()
{
// Was the script completed?
if (DI::config()->get("system", "post_update_version") >= 1350) {
return true;
}
$id = DI::config()->get("system", "post_update_version_1350_id", 0);
Logger::info('Start', ['gcontact' => $id]);
$start_id = $id;
$rows = 0;
$condition = ["`id` > ? AND `gsid` IS NULL AND `server_url` != '' AND NOT `server_url` IS NULL", $id];
$params = ['order' => ['id'], 'limit' => 10000];
$gcontacts = DBA::select('gcontact', ['id', 'server_url'], $condition, $params);
if (DBA::errorNo() != 0) {
Logger::error('Database error', ['no' => DBA::errorNo(), 'message' => DBA::errorMessage()]);
return false;
}
while ($gcontact = DBA::fetch($gcontacts)) {
$id = $gcontact['id'];
DBA::update('gcontact',
['gsid' => GServer::getID($gcontact['server_url']), 'server_url' => GServer::cleanURL($gcontact['server_url'])],
['id' => $gcontact['id']]);
++$rows;
}
DBA::close($gcontacts);
DI::config()->set("system", "post_update_version_1350_id", $id);
Logger::info('Processed', ['rows' => $rows, 'last' => $id]);
if ($start_id == $id) {
DI::config()->set("system", "post_update_version", 1350);
Logger::info('Done');
return true;
}
return false;
}
} }

View file

@ -291,6 +291,12 @@ class APContact
$apcontact['baseurl'] = null; $apcontact['baseurl'] = null;
} }
if (!empty($apcontact['baseurl']) && empty($fetched_contact['gsid'])) {
$apcontact['gsid'] = GServer::getID($apcontact['baseurl']);
} elseif (!empty($fetched_contact['gsid'])) {
$apcontact['gsid'] = $fetched_contact['gsid'];
}
if ($apcontact['url'] == $apcontact['alias']) { if ($apcontact['url'] == $apcontact['alias']) {
$apcontact['alias'] = null; $apcontact['alias'] = null;
} }

View file

@ -1530,10 +1530,6 @@ class Contact
if (empty($data)) { if (empty($data)) {
$data = Probe::uri($url, "", $uid); $data = Probe::uri($url, "", $uid);
// Ensure that there is a gserver entry
if (!empty($data['baseurl']) && ($data['network'] != Protocol::PHANTOM)) {
GServer::check($data['baseurl']);
}
} }
// Take the default values when probing failed // Take the default values when probing failed
@ -1575,6 +1571,7 @@ class Contact
'confirm' => $data['confirm'] ?? '', 'confirm' => $data['confirm'] ?? '',
'poco' => $data['poco'] ?? '', 'poco' => $data['poco'] ?? '',
'baseurl' => $data['baseurl'] ?? '', 'baseurl' => $data['baseurl'] ?? '',
'gsid' => $data['gsid'] ?? null,
'name-date' => DateTimeFormat::utcNow(), 'name-date' => DateTimeFormat::utcNow(),
'uri-date' => DateTimeFormat::utcNow(), 'uri-date' => DateTimeFormat::utcNow(),
'avatar-date' => DateTimeFormat::utcNow(), 'avatar-date' => DateTimeFormat::utcNow(),
@ -2082,7 +2079,7 @@ class Contact
$fields = ['uid', 'avatar', 'name', 'nick', 'location', 'keywords', 'about', $fields = ['uid', 'avatar', 'name', 'nick', 'location', 'keywords', 'about',
'unsearchable', 'url', 'addr', 'batch', 'notify', 'poll', 'request', 'confirm', 'poco', 'unsearchable', 'url', 'addr', 'batch', 'notify', 'poll', 'request', 'confirm', 'poco',
'network', 'alias', 'baseurl', 'forum', 'prv', 'contact-type', 'pubkey']; 'network', 'alias', 'baseurl', 'gsid', 'forum', 'prv', 'contact-type', 'pubkey'];
$contact = DBA::selectFirst('contact', $fields, ['id' => $id]); $contact = DBA::selectFirst('contact', $fields, ['id' => $id]);
if (!DBA::isResult($contact)) { if (!DBA::isResult($contact)) {
return false; return false;
@ -2415,6 +2412,7 @@ class Contact
'nick' => $ret['nick'], 'nick' => $ret['nick'],
'network' => $ret['network'], 'network' => $ret['network'],
'baseurl' => $ret['baseurl'], 'baseurl' => $ret['baseurl'],
'gsid' => $ret['gsid'] ?? null,
'protocol' => $protocol, 'protocol' => $protocol,
'pubkey' => $ret['pubkey'], 'pubkey' => $ret['pubkey'],
'rel' => $new_relation, 'rel' => $new_relation,

View file

@ -690,7 +690,7 @@ class GContact
} }
$public_contact = DBA::selectFirst('gcontact', [ $public_contact = DBA::selectFirst('gcontact', [
'name', 'nick', 'photo', 'location', 'about', 'addr', 'generation', 'birthday', 'keywords', 'name', 'nick', 'photo', 'location', 'about', 'addr', 'generation', 'birthday', 'keywords', 'gsid',
'contact-type', 'hide', 'nsfw', 'network', 'alias', 'notify', 'server_url', 'connect', 'updated', 'url' 'contact-type', 'hide', 'nsfw', 'network', 'alias', 'notify', 'server_url', 'connect', 'updated', 'url'
], ['id' => $gcontact_id]); ], ['id' => $gcontact_id]);
@ -752,6 +752,10 @@ class GContact
$contact['server_url'] = Strings::normaliseLink($contact['server_url']); $contact['server_url'] = Strings::normaliseLink($contact['server_url']);
} }
if (!empty($contact['server_url']) && empty($contact['gsid'])) {
$contact['gsid'] = GServer::getID($contact['server_url']);
}
if (empty($contact['addr']) && !empty($contact['server_url']) && !empty($contact['nick'])) { if (empty($contact['addr']) && !empty($contact['server_url']) && !empty($contact['nick'])) {
$hostname = str_replace('http://', '', $contact['server_url']); $hostname = str_replace('http://', '', $contact['server_url']);
$contact['addr'] = $contact['nick'] . '@' . $hostname; $contact['addr'] = $contact['nick'] . '@' . $hostname;
@ -791,7 +795,8 @@ class GContact
'notify' => $contact['notify'], 'url' => $contact['url'], 'notify' => $contact['notify'], 'url' => $contact['url'],
'location' => $contact['location'], 'about' => $contact['about'], 'location' => $contact['location'], 'about' => $contact['about'],
'generation' => $contact['generation'], 'updated' => $contact['updated'], 'generation' => $contact['generation'], 'updated' => $contact['updated'],
'server_url' => $contact['server_url'], 'connect' => $contact['connect'] 'server_url' => $contact['server_url'], 'connect' => $contact['connect'],
'gsid' => $contact['gsid']
]; ];
DBA::update('gcontact', $updated, $condition, $fields); DBA::update('gcontact', $updated, $condition, $fields);
@ -1016,7 +1021,7 @@ class GContact
$fields = ['name', 'nick', 'url', 'nurl', 'location', 'about', 'keywords', $fields = ['name', 'nick', 'url', 'nurl', 'location', 'about', 'keywords',
'bd', 'contact-type', 'network', 'addr', 'notify', 'alias', 'archive', 'term-date', 'bd', 'contact-type', 'network', 'addr', 'notify', 'alias', 'archive', 'term-date',
'created', 'updated', 'avatar', 'success_update', 'failure_update', 'forum', 'prv', 'created', 'updated', 'avatar', 'success_update', 'failure_update', 'forum', 'prv',
'baseurl', 'sensitive', 'unsearchable']; 'baseurl', 'gsid', 'sensitive', 'unsearchable'];
$contact = DBA::selectFirst('contact', $fields, array_merge($condition, ['uid' => 0, 'network' => Protocol::FEDERATED])); $contact = DBA::selectFirst('contact', $fields, array_merge($condition, ['uid' => 0, 'network' => Protocol::FEDERATED]));
if (!DBA::isResult($contact)) { if (!DBA::isResult($contact)) {
@ -1026,7 +1031,7 @@ class GContact
$fields = ['name', 'nick', 'url', 'nurl', 'location', 'about', 'keywords', 'generation', $fields = ['name', 'nick', 'url', 'nurl', 'location', 'about', 'keywords', 'generation',
'birthday', 'contact-type', 'network', 'addr', 'notify', 'alias', 'archived', 'archive_date', 'birthday', 'contact-type', 'network', 'addr', 'notify', 'alias', 'archived', 'archive_date',
'created', 'updated', 'photo', 'last_contact', 'last_failure', 'community', 'connect', 'created', 'updated', 'photo', 'last_contact', 'last_failure', 'community', 'connect',
'server_url', 'nsfw', 'hide', 'id']; 'server_url', 'gsid', 'nsfw', 'hide', 'id'];
$old_gcontact = DBA::selectFirst('gcontact', $fields, ['nurl' => $contact['nurl']]); $old_gcontact = DBA::selectFirst('gcontact', $fields, ['nurl' => $contact['nurl']]);
$do_insert = !DBA::isResult($old_gcontact); $do_insert = !DBA::isResult($old_gcontact);
@ -1037,7 +1042,7 @@ class GContact
$gcontact = []; $gcontact = [];
// These fields are identical in both contact and gcontact // These fields are identical in both contact and gcontact
$fields = ['name', 'nick', 'url', 'nurl', 'location', 'about', 'keywords', $fields = ['name', 'nick', 'url', 'nurl', 'location', 'about', 'keywords', 'gsid',
'contact-type', 'network', 'addr', 'notify', 'alias', 'created', 'updated']; 'contact-type', 'network', 'addr', 'notify', 'alias', 'created', 'updated'];
foreach ($fields as $field) { foreach ($fields as $field) {

View file

@ -34,6 +34,7 @@ use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings; use Friendica\Util\Strings;
use Friendica\Util\XML; use Friendica\Util\XML;
use Friendica\Core\Logger; use Friendica\Core\Logger;
use Friendica\Core\System;
use Friendica\Protocol\PortableContact; use Friendica\Protocol\PortableContact;
use Friendica\Protocol\Diaspora; use Friendica\Protocol\Diaspora;
use Friendica\Network\Probe; use Friendica\Network\Probe;
@ -47,6 +48,57 @@ class GServer
const DT_NONE = 0; const DT_NONE = 0;
const DT_POCO = 1; const DT_POCO = 1;
const DT_MASTODON = 2; const DT_MASTODON = 2;
// Methods to detect server types
// Non endpoint specific methods
const DETECT_MANUAL = 0;
const DETECT_HEADER = 1;
const DETECT_BODY = 2;
// Implementation specific endpoints
const DETECT_FRIENDIKA = 10;
const DETECT_FRIENDICA = 11;
const DETECT_STATUSNET = 12;
const DETECT_GNUSOCIAL = 13;
const DETECT_CONFIG_JSON = 14; // Statusnet, GNU Social, Older Hubzilla/Redmatrix
const DETECT_SITEINFO_JSON = 15; // Newer Hubzilla
const DETECT_MASTODON_API = 16;
const DETECT_STATUS_PHP = 17; // Nextcloud
// Standardized endpoints
const DETECT_STATISTICS_JSON = 100;
const DETECT_NODEINFO_1 = 101;
const DETECT_NODEINFO_2 = 102;
/**
* Get the ID for the given server URL
*
* @param string $url
* @param boolean $no_check Don't check if the server hadn't been found
* @return int gserver id
*/
public static function getID(string $url, bool $no_check = false)
{
if (empty($url)) {
return null;
}
$url = self::cleanURL($url);
$gserver = DBA::selectFirst('gserver', ['id'], ['nurl' => Strings::normaliseLink($url)]);
if (DBA::isResult($gserver)) {
Logger::info('Got ID for URL', ['id' => $gserver['id'], 'url' => $url, 'callstack' => System::callstack(20)]);
return $gserver['id'];
}
if ($no_check || !self::check($url)) {
return null;
}
return self::getID($url, true);
}
/** /**
* Checks if the given server is reachable * Checks if the given server is reachable
* *
@ -137,9 +189,7 @@ class GServer
*/ */
public static function check(string $server_url, string $network = '', bool $force = false, bool $only_nodeinfo = false) public static function check(string $server_url, string $network = '', bool $force = false, bool $only_nodeinfo = false)
{ {
// Unify the server address $server_url = self::cleanURL($server_url);
$server_url = trim($server_url, '/');
$server_url = str_replace('/index.php', '', $server_url);
if ($server_url == '') { if ($server_url == '') {
return false; return false;
@ -186,7 +236,8 @@ class GServer
private static function setFailure(string $url) private static function setFailure(string $url)
{ {
if (DBA::exists('gserver', ['nurl' => Strings::normaliseLink($url)])) { if (DBA::exists('gserver', ['nurl' => Strings::normaliseLink($url)])) {
DBA::update('gserver', ['last_failure' => DateTimeFormat::utcNow()], ['nurl' => Strings::normaliseLink($url)]); DBA::update('gserver', ['last_failure' => DateTimeFormat::utcNow(), 'detection-method' => null],
['nurl' => Strings::normaliseLink($url)]);
Logger::info('Set failed status for existing server', ['url' => $url]); Logger::info('Set failed status for existing server', ['url' => $url]);
return; return;
} }
@ -196,6 +247,38 @@ class GServer
Logger::info('Set failed status for new server', ['url' => $url]); Logger::info('Set failed status for new server', ['url' => $url]);
} }
/**
* Remove unwanted content from the given URL
*
* @param string $url
* @return string cleaned URL
*/
public static function cleanURL(string $url)
{
$url = trim($url, '/');
$url = str_replace('/index.php', '', $url);
$urlparts = parse_url($url);
unset($urlparts['user']);
unset($urlparts['pass']);
unset($urlparts['query']);
unset($urlparts['fragment']);
return Network::unparseURL($urlparts);
}
/**
* Return the base URL
*
* @param string $url
* @return string base URL
*/
private static function getBaseURL(string $url)
{
$urlparts = parse_url(self::cleanURL($url));
unset($urlparts['path']);
return Network::unparseURL($urlparts);
}
/** /**
* Detect server data (type, protocol, version number, ...) * Detect server data (type, protocol, version number, ...)
* The detected data is then updated or inserted in the gserver table. * The detected data is then updated or inserted in the gserver table.
@ -209,17 +292,15 @@ class GServer
public static function detect(string $url, string $network = '', bool $only_nodeinfo = false) public static function detect(string $url, string $network = '', bool $only_nodeinfo = false)
{ {
Logger::info('Detect server type', ['server' => $url]); Logger::info('Detect server type', ['server' => $url]);
$serverdata = []; $serverdata = ['detection-method' => self::DETECT_MANUAL];
$original_url = $url; $original_url = $url;
// Remove URL content that is not supposed to exist for a server url // Remove URL content that is not supposed to exist for a server url
$urlparts = parse_url($url); $url = self::cleanURL($url);
unset($urlparts['user']);
unset($urlparts['pass']); // Get base URL
unset($urlparts['query']); $baseurl = self::getBaseURL($url);
unset($urlparts['fragment']);
$url = Network::unparseURL($urlparts);
// If the URL missmatches, then we mark the old entry as failure // If the URL missmatches, then we mark the old entry as failure
if ($url != $original_url) { if ($url != $original_url) {
@ -249,18 +330,53 @@ class GServer
// If that didn't work out well, we use some protocol specific endpoints // If that didn't work out well, we use some protocol specific endpoints
// For Friendica and Zot based networks we have to dive deeper to reveal more details // For Friendica and Zot based networks we have to dive deeper to reveal more details
if (empty($nodeinfo['network']) || in_array($nodeinfo['network'], [Protocol::DFRN, Protocol::ZOT])) { if (empty($nodeinfo['network']) || in_array($nodeinfo['network'], [Protocol::DFRN, Protocol::ZOT])) {
if (!empty($nodeinfo['detection-method'])) {
$serverdata['detection-method'] = $nodeinfo['detection-method'];
}
// Fetch the landing page, possibly it reveals some data // Fetch the landing page, possibly it reveals some data
if (empty($nodeinfo['network'])) { if (empty($nodeinfo['network'])) {
$curlResult = Network::curl($url, false, ['timeout' => $xrd_timeout]); if ($baseurl == $url) {
$basedata = $serverdata;
} else {
$basedata = ['detection-method' => self::DETECT_MANUAL];
}
$curlResult = Network::curl($baseurl, false, ['timeout' => $xrd_timeout]);
if ($curlResult->isSuccess()) { if ($curlResult->isSuccess()) {
$serverdata = self::analyseRootHeader($curlResult, $serverdata); $basedata = self::analyseRootHeader($curlResult, $basedata);
$serverdata = self::analyseRootBody($curlResult, $serverdata, $url); $basedata = self::analyseRootBody($curlResult, $basedata, $baseurl);
} }
if (!$curlResult->isSuccess() || empty($curlResult->getBody()) || self::invalidBody($curlResult->getBody())) { if (!$curlResult->isSuccess() || empty($curlResult->getBody()) || self::invalidBody($curlResult->getBody())) {
self::setFailure($url); self::setFailure($url);
return false; return false;
} }
if ($baseurl == $url) {
$serverdata = $basedata;
} else {
// When the base path doesn't seem to contain a social network we try the complete path.
// Most detectable system have to be installed in the root directory.
// We checked the base to avoid false positives.
$curlResult = Network::curl($url, false, ['timeout' => $xrd_timeout]);
if ($curlResult->isSuccess()) {
$urldata = self::analyseRootHeader($curlResult, $serverdata);
$urldata = self::analyseRootBody($curlResult, $urldata, $url);
$comparebase = $basedata;
unset($comparebase['info']);
unset($comparebase['site_name']);
$compareurl = $urldata;
unset($compareurl['info']);
unset($compareurl['site_name']);
// We assume that no one will install the identical system in the root and a subfolder
if (!empty(array_diff($comparebase, $compareurl))) {
$serverdata = $urldata;
}
}
}
} }
if (empty($serverdata['network']) || ($serverdata['network'] == Protocol::ACTIVITYPUB)) { if (empty($serverdata['network']) || ($serverdata['network'] == Protocol::ACTIVITYPUB)) {
@ -296,6 +412,8 @@ class GServer
if (empty($serverdata['network'])) { if (empty($serverdata['network'])) {
$serverdata = self::detectGNUSocial($url, $serverdata); $serverdata = self::detectGNUSocial($url, $serverdata);
} }
$serverdata = array_merge($nodeinfo, $serverdata);
} else { } else {
$serverdata = $nodeinfo; $serverdata = $nodeinfo;
} }
@ -326,12 +444,7 @@ class GServer
$registeredUsers = 1; $registeredUsers = 1;
} }
if ($serverdata['network'] != Protocol::PHANTOM) { if ($serverdata['network'] == Protocol::PHANTOM) {
$gcontacts = DBA::count('gcontact', ['server_url' => [$url, $serverdata['nurl']]]);
$apcontacts = DBA::count('apcontact', ['baseurl' => [$url, $serverdata['nurl']]]);
$contacts = DBA::count('contact', ['uid' => 0, 'baseurl' => [$url, $serverdata['nurl']]]);
$serverdata['registered-users'] = max($gcontacts, $apcontacts, $contacts, $registeredUsers);
} else {
$serverdata['registered-users'] = $registeredUsers; $serverdata['registered-users'] = $registeredUsers;
$serverdata = self::detectNetworkViaContacts($url, $serverdata); $serverdata = self::detectNetworkViaContacts($url, $serverdata);
} }
@ -342,6 +455,7 @@ class GServer
if (!DBA::isResult($gserver)) { if (!DBA::isResult($gserver)) {
$serverdata['created'] = DateTimeFormat::utcNow(); $serverdata['created'] = DateTimeFormat::utcNow();
$ret = DBA::insert('gserver', $serverdata); $ret = DBA::insert('gserver', $serverdata);
$id = DBA::lastInsertId();
} else { } else {
// Don't override the network with 'unknown' when there had been a valid entry before // Don't override the network with 'unknown' when there had been a valid entry before
if (($serverdata['network'] == Protocol::PHANTOM) && !empty($gserver['network'])) { if (($serverdata['network'] == Protocol::PHANTOM) && !empty($gserver['network'])) {
@ -349,11 +463,26 @@ class GServer
} }
$ret = DBA::update('gserver', $serverdata, ['nurl' => $serverdata['nurl']]); $ret = DBA::update('gserver', $serverdata, ['nurl' => $serverdata['nurl']]);
$gserver = DBA::selectFirst('gserver', ['id'], ['nurl' => $serverdata['nurl']]);
if (DBA::isResult($gserver)) {
$id = $gserver['id'];
}
}
if (!empty($id) && ($serverdata['network'] != Protocol::PHANTOM)) {
$gcontacts = DBA::count('gcontact', ['gsid' => $id]);
$apcontacts = DBA::count('apcontact', ['gsid' => $id]);
$contacts = DBA::count('contact', ['uid' => 0, 'gsid' => $id]);
$max_users = max($gcontacts, $apcontacts, $contacts, $registeredUsers);
if ($max_users > $registeredUsers) {
Logger::info('Update registered users', ['id' => $id, 'url' => $serverdata['nurl'], 'registered-users' => $max_users]);
DBA::update('gserver', ['registered-users' => $max_users], ['id' => $id]);
}
} }
if (!empty($serverdata['network']) && in_array($serverdata['network'], [Protocol::DFRN, Protocol::DIASPORA])) { if (!empty($serverdata['network']) && in_array($serverdata['network'], [Protocol::DFRN, Protocol::DIASPORA])) {
self::discoverRelay($url); self::discoverRelay($url);
} }
return $ret; return $ret;
} }
@ -459,7 +588,7 @@ class GServer
return []; return [];
} }
$serverdata = []; $serverdata = ['detection-method' => self::DETECT_STATISTICS_JSON];
if (!empty($data['version'])) { if (!empty($data['version'])) {
$serverdata['version'] = $data['version']; $serverdata['version'] = $data['version'];
@ -560,7 +689,6 @@ class GServer
private static function parseNodeinfo1(string $nodeinfo_url) private static function parseNodeinfo1(string $nodeinfo_url)
{ {
$curlResult = Network::curl($nodeinfo_url); $curlResult = Network::curl($nodeinfo_url);
if (!$curlResult->isSuccess()) { if (!$curlResult->isSuccess()) {
return []; return [];
} }
@ -571,9 +699,8 @@ class GServer
return []; return [];
} }
$server = []; $server = ['detection-method' => self::DETECT_NODEINFO_1,
'register_policy' => Register::CLOSED];
$server['register_policy'] = Register::CLOSED;
if (!empty($nodeinfo['openRegistrations'])) { if (!empty($nodeinfo['openRegistrations'])) {
$server['register_policy'] = Register::OPEN; $server['register_policy'] = Register::OPEN;
@ -648,9 +775,8 @@ class GServer
return []; return [];
} }
$server = []; $server = ['detection-method' => self::DETECT_NODEINFO_2,
'register_policy' => Register::CLOSED];
$server['register_policy'] = Register::CLOSED;
if (!empty($nodeinfo['openRegistrations'])) { if (!empty($nodeinfo['openRegistrations'])) {
$server['register_policy'] = Register::OPEN; $server['register_policy'] = Register::OPEN;
@ -725,6 +851,10 @@ class GServer
return $serverdata; return $serverdata;
} }
if (in_array($serverdata['detection-method'], [self::DETECT_HEADER, self::DETECT_BODY, self::DETECT_MANUAL])) {
$serverdata['detection-method'] = self::DETECT_SITEINFO_JSON;
}
if (!empty($data['url'])) { if (!empty($data['url'])) {
$serverdata['platform'] = strtolower($data['platform']); $serverdata['platform'] = strtolower($data['platform']);
$serverdata['version'] = $data['version']; $serverdata['version'] = $data['version'];
@ -934,7 +1064,6 @@ class GServer
private static function detectNextcloud(string $url, array $serverdata) private static function detectNextcloud(string $url, array $serverdata)
{ {
$curlResult = Network::curl($url . '/status.php'); $curlResult = Network::curl($url . '/status.php');
if (!$curlResult->isSuccess() || ($curlResult->getBody() == '')) { if (!$curlResult->isSuccess() || ($curlResult->getBody() == '')) {
return $serverdata; return $serverdata;
} }
@ -948,6 +1077,10 @@ class GServer
$serverdata['platform'] = 'nextcloud'; $serverdata['platform'] = 'nextcloud';
$serverdata['version'] = $data['version']; $serverdata['version'] = $data['version'];
$serverdata['network'] = Protocol::ACTIVITYPUB; $serverdata['network'] = Protocol::ACTIVITYPUB;
if (in_array($serverdata['detection-method'], [self::DETECT_HEADER, self::DETECT_BODY, self::DETECT_MANUAL])) {
$serverdata['detection-method'] = self::DETECT_STATUS_PHP;
}
} }
return $serverdata; return $serverdata;
@ -964,7 +1097,6 @@ class GServer
private static function detectMastodonAlikes(string $url, array $serverdata) private static function detectMastodonAlikes(string $url, array $serverdata)
{ {
$curlResult = Network::curl($url . '/api/v1/instance'); $curlResult = Network::curl($url . '/api/v1/instance');
if (!$curlResult->isSuccess() || ($curlResult->getBody() == '')) { if (!$curlResult->isSuccess() || ($curlResult->getBody() == '')) {
return $serverdata; return $serverdata;
} }
@ -974,6 +1106,10 @@ class GServer
return $serverdata; return $serverdata;
} }
if (in_array($serverdata['detection-method'], [self::DETECT_HEADER, self::DETECT_BODY, self::DETECT_MANUAL])) {
$serverdata['detection-method'] = self::DETECT_MASTODON_API;
}
if (!empty($data['version'])) { if (!empty($data['version'])) {
$serverdata['platform'] = 'mastodon'; $serverdata['platform'] = 'mastodon';
$serverdata['version'] = $data['version'] ?? ''; $serverdata['version'] = $data['version'] ?? '';
@ -1031,7 +1167,7 @@ class GServer
} }
$data = json_decode($curlResult->getBody(), true); $data = json_decode($curlResult->getBody(), true);
if (empty($data)) { if (empty($data) || empty($data['site'])) {
return $serverdata; return $serverdata;
} }
@ -1079,11 +1215,16 @@ class GServer
} }
if (!$closed && !$private and $inviteonly) { if (!$closed && !$private and $inviteonly) {
$register_policy = Register::APPROVE; $serverdata['register_policy'] = Register::APPROVE;
} elseif (!$closed && !$private) { } elseif (!$closed && !$private) {
$register_policy = Register::OPEN; $serverdata['register_policy'] = Register::OPEN;
} else { } else {
$register_policy = Register::CLOSED; $serverdata['register_policy'] = Register::CLOSED;
}
if (!empty($serverdata['network']) && in_array($serverdata['detection-method'],
[self::DETECT_HEADER, self::DETECT_BODY, self::DETECT_MANUAL])) {
$serverdata['detection-method'] = self::DETECT_CONFIG_JSON;
} }
return $serverdata; return $serverdata;
@ -1127,6 +1268,11 @@ class GServer
$serverdata['version'] = str_replace(["\r", "\n", "\t"], '', $serverdata['version']); $serverdata['version'] = str_replace(["\r", "\n", "\t"], '', $serverdata['version']);
$serverdata['version'] = trim($serverdata['version'], '"'); $serverdata['version'] = trim($serverdata['version'], '"');
$serverdata['network'] = Protocol::OSTATUS; $serverdata['network'] = Protocol::OSTATUS;
if (in_array($serverdata['detection-method'], [self::DETECT_HEADER, self::DETECT_BODY, self::DETECT_MANUAL])) {
$serverdata['detection-method'] = self::DETECT_GNUSOCIAL;
}
return $serverdata; return $serverdata;
} }
@ -1148,6 +1294,10 @@ class GServer
$serverdata['platform'] = 'statusnet'; $serverdata['platform'] = 'statusnet';
$serverdata['network'] = Protocol::OSTATUS; $serverdata['network'] = Protocol::OSTATUS;
} }
if (in_array($serverdata['detection-method'], [self::DETECT_HEADER, self::DETECT_BODY, self::DETECT_MANUAL])) {
$serverdata['detection-method'] = self::DETECT_STATUSNET;
}
} }
return $serverdata; return $serverdata;
@ -1166,6 +1316,11 @@ class GServer
$curlResult = Network::curl($url . '/friendica/json'); $curlResult = Network::curl($url . '/friendica/json');
if (!$curlResult->isSuccess()) { if (!$curlResult->isSuccess()) {
$curlResult = Network::curl($url . '/friendika/json'); $curlResult = Network::curl($url . '/friendika/json');
$friendika = true;
$platform = 'Friendika';
} else {
$friendika = false;
$platform = 'Friendica';
} }
if (!$curlResult->isSuccess()) { if (!$curlResult->isSuccess()) {
@ -1177,6 +1332,10 @@ class GServer
return $serverdata; return $serverdata;
} }
if (in_array($serverdata['detection-method'], [self::DETECT_HEADER, self::DETECT_BODY, self::DETECT_MANUAL])) {
$serverdata['detection-method'] = $friendika ? self::DETECT_FRIENDIKA : self::DETECT_FRIENDICA;
}
$serverdata['network'] = Protocol::DFRN; $serverdata['network'] = Protocol::DFRN;
$serverdata['version'] = $data['version']; $serverdata['version'] = $data['version'];
@ -1212,7 +1371,7 @@ class GServer
break; break;
} }
$serverdata['platform'] = strtolower($data['platform'] ?? ''); $serverdata['platform'] = strtolower($data['platform'] ?? $platform);
return $serverdata; return $serverdata;
} }
@ -1260,7 +1419,8 @@ class GServer
$serverdata['info'] = $attr['content']; $serverdata['info'] = $attr['content'];
} }
if ($attr['name'] == 'application-name') { if (in_array($attr['name'], ['application-name', 'al:android:app_name', 'al:ios:app_name',
'twitter:app:name:googleplay', 'twitter:app:name:iphone', 'twitter:app:name:ipad'])) {
$serverdata['platform'] = strtolower($attr['content']); $serverdata['platform'] = strtolower($attr['content']);
if (in_array($attr['content'], ['Misskey', 'Write.as'])) { if (in_array($attr['content'], ['Misskey', 'Write.as'])) {
$serverdata['network'] = Protocol::ACTIVITYPUB; $serverdata['network'] = Protocol::ACTIVITYPUB;
@ -1281,6 +1441,10 @@ class GServer
} else { } else {
$serverdata['network'] = Protocol::FEED; $serverdata['network'] = Protocol::FEED;
} }
if ($serverdata['detection-method'] == self::DETECT_MANUAL) {
$serverdata['detection-method'] = self::DETECT_BODY;
}
} }
if (in_array($version_part[0], ['Friendika', 'Friendica'])) { if (in_array($version_part[0], ['Friendika', 'Friendica'])) {
$serverdata['platform'] = strtolower($version_part[0]); $serverdata['platform'] = strtolower($version_part[0]);
@ -1336,6 +1500,10 @@ class GServer
} }
} }
if (!empty($serverdata['network']) && ($serverdata['detection-method'] == self::DETECT_MANUAL)) {
$serverdata['detection-method'] = self::DETECT_BODY;
}
return $serverdata; return $serverdata;
} }
@ -1351,16 +1519,23 @@ class GServer
{ {
if ($curlResult->getHeader('server') == 'Mastodon') { if ($curlResult->getHeader('server') == 'Mastodon') {
$serverdata['platform'] = 'mastodon'; $serverdata['platform'] = 'mastodon';
$serverdata['network'] = $network = Protocol::ACTIVITYPUB; $serverdata['network'] = Protocol::ACTIVITYPUB;
} elseif ($curlResult->inHeader('x-diaspora-version')) { } elseif ($curlResult->inHeader('x-diaspora-version')) {
$serverdata['platform'] = 'diaspora'; $serverdata['platform'] = 'diaspora';
$serverdata['network'] = $network = Protocol::DIASPORA; $serverdata['network'] = Protocol::DIASPORA;
$serverdata['version'] = $curlResult->getHeader('x-diaspora-version'); $serverdata['version'] = $curlResult->getHeader('x-diaspora-version');
} elseif ($curlResult->inHeader('x-friendica-version')) { } elseif ($curlResult->inHeader('x-friendica-version')) {
$serverdata['platform'] = 'friendica'; $serverdata['platform'] = 'friendica';
$serverdata['network'] = $network = Protocol::DFRN; $serverdata['network'] = Protocol::DFRN;
$serverdata['version'] = $curlResult->getHeader('x-friendica-version'); $serverdata['version'] = $curlResult->getHeader('x-friendica-version');
} else {
return $serverdata;
} }
if ($serverdata['detection-method'] == self::DETECT_MANUAL) {
$serverdata['detection-method'] = self::DETECT_HEADER;
}
return $serverdata; return $serverdata;
} }
@ -1472,7 +1647,6 @@ class GServer
$api = 'https://instances.social/api/1.0/instances/list?count=0'; $api = 'https://instances.social/api/1.0/instances/list?count=0';
$header = ['Authorization: Bearer '.$accesstoken]; $header = ['Authorization: Bearer '.$accesstoken];
$curlResult = Network::curl($api, false, ['headers' => $header]); $curlResult = Network::curl($api, false, ['headers' => $header]);
if ($curlResult->isSuccess()) { if ($curlResult->isSuccess()) {
$servers = json_decode($curlResult->getBody(), true); $servers = json_decode($curlResult->getBody(), true);

View file

@ -30,6 +30,7 @@ use Friendica\Core\System;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\DI; use Friendica\DI;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\GServer;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Protocol\ActivityNamespace; use Friendica\Protocol\ActivityNamespace;
use Friendica\Protocol\ActivityPub; use Friendica\Protocol\ActivityPub;
@ -86,14 +87,16 @@ class Probe
"community", "keywords", "location", "about", "hide", "community", "keywords", "location", "about", "hide",
"batch", "notify", "poll", "request", "confirm", "poco", "batch", "notify", "poll", "request", "confirm", "poco",
"following", "followers", "inbox", "outbox", "sharedinbox", "following", "followers", "inbox", "outbox", "sharedinbox",
"priority", "network", "pubkey", "baseurl"]; "priority", "network", "pubkey", "baseurl", "gsid"];
$newdata = []; $newdata = [];
foreach ($fields as $field) { foreach ($fields as $field) {
if (isset($data[$field])) { if (isset($data[$field])) {
$newdata[$field] = $data[$field]; $newdata[$field] = $data[$field];
} else { } elseif ($field != "gsid") {
$newdata[$field] = ""; $newdata[$field] = "";
} else {
$newdata[$field] = null;
} }
} }
@ -461,6 +464,10 @@ class Probe
$data['baseurl'] = self::$baseurl; $data['baseurl'] = self::$baseurl;
} }
if (!empty($data['baseurl']) && empty($data['gsid'])) {
$data['gsid'] = GServer::getID($data['baseurl']);
}
if (empty($data['network'])) { if (empty($data['network'])) {
$data['network'] = Protocol::PHANTOM; $data['network'] = Protocol::PHANTOM;
} }

View file

@ -171,6 +171,7 @@ class ActivityPub
$profile['poll'] = $apcontact['outbox']; $profile['poll'] = $apcontact['outbox'];
$profile['pubkey'] = $apcontact['pubkey']; $profile['pubkey'] = $apcontact['pubkey'];
$profile['baseurl'] = $apcontact['baseurl']; $profile['baseurl'] = $apcontact['baseurl'];
$profile['gsid'] = $apcontact['gsid'];
// Remove all "null" fields // Remove all "null" fields
foreach ($profile as $field => $content) { foreach ($profile as $field => $content) {

View file

@ -54,11 +54,40 @@
use Friendica\Database\DBA; use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) { if (!defined('DB_UPDATE_VERSION')) {
define('DB_UPDATE_VERSION', 1349); define('DB_UPDATE_VERSION', 1350);
} }
return [ return [
// Side tables // Side tables
"gserver" => [
"comment" => "Global servers",
"fields" => [
"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
"url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"nurl" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"version" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"site_name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"info" => ["type" => "text", "comment" => ""],
"register_policy" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => ""],
"registered-users" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => "Number of registered users"],
"directory-type" => ["type" => "tinyint", "default" => "0", "comment" => "Type of directory service (Poco, Mastodon)"],
"poco" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"noscrape" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => ""],
"platform" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"relay-subscribe" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Has the server subscribed to the relay system"],
"relay-scope" => ["type" => "varchar(10)", "not null" => "1", "default" => "", "comment" => "The scope of messages that the server wants to get"],
"detection-method" => ["type" => "tinyint unsigned", "comment" => "Method that had been used to detect that server"],
"created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""],
"last_poco_query" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""],
"last_contact" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""],
"last_failure" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""],
],
"indexes" => [
"PRIMARY" => ["id"],
"nurl" => ["UNIQUE", "nurl(190)"],
]
],
"clients" => [ "clients" => [
"comment" => "OAuth usage", "comment" => "OAuth usage",
"fields" => [ "fields" => [
@ -142,6 +171,7 @@ return [
"unsearchable" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact prefers to not be searchable"], "unsearchable" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact prefers to not be searchable"],
"sensitive" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact posts sensitive content"], "sensitive" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact posts sensitive content"],
"baseurl" => ["type" => "varchar(255)", "default" => "", "comment" => "baseurl of the contact"], "baseurl" => ["type" => "varchar(255)", "default" => "", "comment" => "baseurl of the contact"],
"gsid" => ["type" => "int unsigned", "foreign" => ["gserver" => "id", "on delete" => "restrict"], "comment" => "Global Server ID"],
"reason" => ["type" => "text", "comment" => ""], "reason" => ["type" => "text", "comment" => ""],
"closeness" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "99", "comment" => ""], "closeness" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "99", "comment" => ""],
"info" => ["type" => "mediumtext", "comment" => ""], "info" => ["type" => "mediumtext", "comment" => ""],
@ -166,6 +196,7 @@ return [
"nick_uid" => ["nick(32)", "uid"], "nick_uid" => ["nick(32)", "uid"],
"dfrn-id" => ["dfrn-id(64)"], "dfrn-id" => ["dfrn-id(64)"],
"issued-id" => ["issued-id(64)"], "issued-id" => ["issued-id(64)"],
"gsid" => ["gsid"]
] ]
], ],
"item-uri" => [ "item-uri" => [
@ -273,6 +304,7 @@ return [
"alias" => ["type" => "varchar(255)", "comment" => ""], "alias" => ["type" => "varchar(255)", "comment" => ""],
"pubkey" => ["type" => "text", "comment" => ""], "pubkey" => ["type" => "text", "comment" => ""],
"baseurl" => ["type" => "varchar(255)", "comment" => "baseurl of the ap contact"], "baseurl" => ["type" => "varchar(255)", "comment" => "baseurl of the ap contact"],
"gsid" => ["type" => "int unsigned", "foreign" => ["gserver" => "id", "on delete" => "restrict"], "comment" => "Global Server ID"],
"generator" => ["type" => "varchar(255)", "comment" => "Name of the contact's system"], "generator" => ["type" => "varchar(255)", "comment" => "Name of the contact's system"],
"following_count" => ["type" => "int unsigned", "default" => 0, "comment" => "Number of following contacts"], "following_count" => ["type" => "int unsigned", "default" => 0, "comment" => "Number of following contacts"],
"followers_count" => ["type" => "int unsigned", "default" => 0, "comment" => "Number of followers"], "followers_count" => ["type" => "int unsigned", "default" => 0, "comment" => "Number of followers"],
@ -283,7 +315,8 @@ return [
"PRIMARY" => ["url"], "PRIMARY" => ["url"],
"addr" => ["addr(32)"], "addr" => ["addr(32)"],
"alias" => ["alias(190)"], "alias" => ["alias(190)"],
"url" => ["followers(190)"] "followers" => ["followers(190)"],
"gsid" => ["gsid"]
] ]
], ],
"attach" => [ "attach" => [
@ -539,6 +572,7 @@ return [
"alias" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], "alias" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"generation" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], "generation" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
"server_url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "baseurl of the contacts server"], "server_url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "baseurl of the contacts server"],
"gsid" => ["type" => "int unsigned", "foreign" => ["gserver" => "id", "on delete" => "restrict"], "comment" => "Global Server ID"],
], ],
"indexes" => [ "indexes" => [
"PRIMARY" => ["id"], "PRIMARY" => ["id"],
@ -548,6 +582,7 @@ return [
"addr" => ["addr(64)"], "addr" => ["addr(64)"],
"hide_network_updated" => ["hide", "network", "updated"], "hide_network_updated" => ["hide", "network", "updated"],
"updated" => ["updated"], "updated" => ["updated"],
"gsid" => ["gsid"]
] ]
], ],
"gfollower" => [ "gfollower" => [
@ -605,34 +640,6 @@ return [
"gid_contactid" => ["UNIQUE", "gid", "contact-id"], "gid_contactid" => ["UNIQUE", "gid", "contact-id"],
] ]
], ],
"gserver" => [
"comment" => "Global servers",
"fields" => [
"id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"],
"url" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"nurl" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"version" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"site_name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"info" => ["type" => "text", "comment" => ""],
"register_policy" => ["type" => "tinyint", "not null" => "1", "default" => "0", "comment" => ""],
"registered-users" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "comment" => "Number of registered users"],
"directory-type" => ["type" => "tinyint", "default" => "0", "comment" => "Type of directory service (Poco, Mastodon)"],
"poco" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"noscrape" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"network" => ["type" => "char(4)", "not null" => "1", "default" => "", "comment" => ""],
"platform" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"relay-subscribe" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Has the server subscribed to the relay system"],
"relay-scope" => ["type" => "varchar(10)", "not null" => "1", "default" => "", "comment" => "The scope of messages that the server wants to get"],
"created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""],
"last_poco_query" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""],
"last_contact" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""],
"last_failure" => ["type" => "datetime", "default" => DBA::NULL_DATETIME, "comment" => ""],
],
"indexes" => [
"PRIMARY" => ["id"],
"nurl" => ["UNIQUE", "nurl(190)"],
]
],
"gserver-tag" => [ "gserver-tag" => [
"comment" => "Tags that the server has subscribed", "comment" => "Tags that the server has subscribed",
"fields" => [ "fields" => [