From 5de4afecf138726dc483ebf90e4fe354002389bc Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 18 Sep 2018 22:09:27 +0000 Subject: [PATCH] Table for AP contacts, JSON-LD parser included --- composer.json | 3 +- composer.lock | 58 ++++++++++++++++++++++++--- config/dbstructure.json | 28 +++++++++++++ src/Protocol/ActivityPub.php | 78 +++++++++++++++++++++++------------- 4 files changed, 133 insertions(+), 34 deletions(-) diff --git a/composer.json b/composer.json index 04e4b655da..329c22664f 100644 --- a/composer.json +++ b/composer.json @@ -38,7 +38,8 @@ "npm-asset/jgrowl": "^1.4", "npm-asset/fullcalendar": "^3.0.1", "npm-asset/cropperjs": "1.2.2", - "npm-asset/imagesloaded": "4.1.4" + "npm-asset/imagesloaded": "4.1.4", + "digitalbazaar/json-ld": "^0.4.7" }, "repositories": [ { diff --git a/composer.lock b/composer.lock index 76c20a1b93..a564990347 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "d62c3e3d6971ee63a862a22ff3cd3768", + "content-hash": "7bfbddde186f6599a2f2012bb13cbbd8", "packages": [ { "name": "asika/simple-console", @@ -149,6 +149,52 @@ }, "type": "bower-asset-library" }, + { + "name": "digitalbazaar/json-ld", + "version": "0.4.7", + "source": { + "type": "git", + "url": "https://github.com/digitalbazaar/php-json-ld.git", + "reference": "dc1bd23f0ee2efd27ccf636d32d2738dabcee182" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/digitalbazaar/php-json-ld/zipball/dc1bd23f0ee2efd27ccf636d32d2738dabcee182", + "reference": "dc1bd23f0ee2efd27ccf636d32d2738dabcee182", + "shasum": "" + }, + "require": { + "ext-json": "*", + "php": ">=5.3.0" + }, + "type": "library", + "autoload": { + "files": [ + "jsonld.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Digital Bazaar, Inc.", + "email": "support@digitalbazaar.com" + } + ], + "description": "A JSON-LD Processor and API implementation in PHP.", + "homepage": "https://github.com/digitalbazaar/php-json-ld", + "keywords": [ + "JSON-LD", + "Linked Data", + "RDF", + "Semantic Web", + "json", + "jsonld" + ], + "time": "2016-04-25T04:17:52+00:00" + }, { "name": "divineomega/password_exposed", "version": "v2.5.1", @@ -3145,7 +3191,7 @@ } ], "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", + "homepage": "http://www.github.com/sebastianbergmann/comparator", "keywords": [ "comparator", "compare", @@ -3247,7 +3293,7 @@ } ], "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "https://github.com/sebastianbergmann/environment", + "homepage": "http://www.github.com/sebastianbergmann/environment", "keywords": [ "Xdebug", "environment", @@ -3315,7 +3361,7 @@ } ], "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "https://github.com/sebastianbergmann/exporter", + "homepage": "http://www.github.com/sebastianbergmann/exporter", "keywords": [ "export", "exporter" @@ -3367,7 +3413,7 @@ } ], "description": "Snapshotting of global state", - "homepage": "https://github.com/sebastianbergmann/global-state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", "keywords": [ "global state" ], @@ -3469,7 +3515,7 @@ } ], "description": "Provides functionality to recursively process PHP variables", - "homepage": "https://github.com/sebastianbergmann/recursion-context", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", "time": "2016-11-19T07:33:16+00:00" }, { diff --git a/config/dbstructure.json b/config/dbstructure.json index 8767c0db16..8f67686156 100644 --- a/config/dbstructure.json +++ b/config/dbstructure.json @@ -15,6 +15,34 @@ "name": ["UNIQUE", "name"] } }, + "apcontact": { + "comment": "ActivityPub compatible contacts - used in the ActivityPub implementation", + "fields": { + "url": {"type": "varbinary(255)", "not null": "1", "primary": "1", "comment": "URL of the contact"}, + "uuid": {"type": "varchar(255)", "comment": ""}, + "type": {"type": "varchar(20)", "not null": "1", "comment": ""}, + "following": {"type": "varchar(255)", "comment": ""}, + "followers": {"type": "varchar(255)", "comment": ""}, + "inbox": {"type": "varchar(255)", "not null": "1", "comment": ""}, + "outbox": {"type": "varchar(255)", "comment": ""}, + "sharedinbox": {"type": "varchar(255)", "comment": ""}, + "nick": {"type": "varchar(255)", "not null": "1", "default": "", "comment": ""}, + "name": {"type": "varchar(255)", "comment": ""}, + "about": {"type": "text", "comment": ""}, + "photo": {"type": "varchar(255)", "comment": ""}, + "addr": {"type": "varchar(255)", "comment": ""}, + "alias": {"type": "varchar(255)", "comment": ""}, + "pubkey": {"type": "text", "comment": ""}, + "baseurl": {"type": "varchar(255)", "comment": "baseurl of the ap contact"}, + "updated": {"type": "datetime", "not null": "1", "default": "0001-01-01 00:00:00", "comment": ""} + + }, + "indexes": { + "PRIMARY": ["url"], + "addr": ["addr(32)"], + "url": ["followers(190)"] + } + }, "attach": { "comment": "file attachments", "fields": { diff --git a/src/Protocol/ActivityPub.php b/src/Protocol/ActivityPub.php index 47f81f8bf4..ffde0eff00 100644 --- a/src/Protocol/ActivityPub.php +++ b/src/Protocol/ActivityPub.php @@ -684,39 +684,63 @@ class ActivityPub return false; } - $profile = ['network' => Protocol::ACTIVITYPUB]; - $profile['nick'] = $data['preferredUsername']; - $profile['name'] = defaults($data, 'name', $profile['nick']); - $profile['guid'] = defaults($data, 'uuid', null); - $profile['url'] = $data['id']; + $apcontact = []; + $apcontact['url'] = $data['id']; + $apcontact['uuid'] = defaults($data, 'uuid', null); + $apcontact['type'] = defaults($data, 'type', null); + $apcontact['following'] = defaults($data, 'following', null); + $apcontact['followers'] = defaults($data, 'followers', null); + $apcontact['inbox'] = defaults($data, 'inbox', null); + $apcontact['outbox'] = defaults($data, 'outbox', null); + $apcontact['sharedinbox'] = self::processElement($data, 'endpoints', 'sharedInbox'); + $apcontact['nick'] = defaults($data, 'preferredUsername', null); + $apcontact['name'] = defaults($data, 'name', $apcontact['nick']); + $apcontact['about'] = defaults($data, 'summary', ''); + $apcontact['photo'] = self::processElement($data, 'icon', 'url'); + $apcontact['alias'] = self::processElement($data, 'url', 'href'); - $parts = parse_url($profile['url']); + $parts = parse_url($apcontact['url']); unset($parts['scheme']); unset($parts['path']); - $profile['addr'] = $profile['nick'] . '@' . str_replace('//', '', Network::unparseURL($parts)); - $profile['alias'] = self::processElement($data, 'url', 'href'); - $profile['photo'] = self::processElement($data, 'icon', 'url'); + $apcontact['addr'] = $apcontact['nick'] . '@' . str_replace('//', '', Network::unparseURL($parts)); + + $apcontact['pubkey'] = self::processElement($data, 'publicKey', 'publicKeyPem'); + + // Check if the address is resolvable + if (self::addrToUrl($apcontact['addr']) == $apcontact['url']) { + $parts = parse_url($apcontact['url']); + unset($parts['path']); + $apcontact['baseurl'] = Network::unparseURL($parts); + } else { + $apcontact['addr'] = null; + } + + if ($apcontact['url'] == $apcontact['alias']) { + $apcontact['alias'] = null; + } + + $apcontact['updated'] = DateTimeFormat::utcNow(); + + DBA::update('apcontact', $apcontact, ['url' => $url], true); + + // Array that is compatible to Probe::uri + $profile = ['network' => Protocol::ACTIVITYPUB]; + $profile['nick'] = $apcontact['nick']; + $profile['name'] = $apcontact['name']; + $profile['guid'] = $apcontact['uuid']; + $profile['url'] = $apcontact['url']; + $profile['addr'] = $apcontact['addr']; + $profile['alias'] = $apcontact['alias']; + $profile['photo'] = $apcontact['photo']; // $profile['community'] // $profile['keywords'] // $profile['location'] - $profile['about'] = defaults($data, 'summary', ''); - $profile['batch'] = self::processElement($data, 'endpoints', 'sharedInbox'); - $profile['notify'] = $data['inbox']; - $profile['poll'] = $data['outbox']; - $profile['pubkey'] = self::processElement($data, 'publicKey', 'publicKeyPem'); - - // Check if the address is resolvable - if (self::addrToUrl($profile['addr']) == $profile['url']) { - $parts = parse_url($profile['url']); - unset($parts['path']); - $profile['baseurl'] = Network::unparseURL($parts); - } else { - unset($profile['addr']); - } - - if ($profile['url'] == $profile['alias']) { - unset($profile['alias']); - } + $profile['about'] = $apcontact['about']; + $profile['batch'] = $apcontact['sharedinbox']; + $profile['notify'] = $apcontact['inbox']; + $profile['poll'] = $apcontact['outbox']; + $profile['pubkey'] = $apcontact['pubkey']; + $profile['baseurl'] = $apcontact['baseurl']; // Remove all "null" fields foreach ($profile as $field => $content) {