diff --git a/composer.lock b/composer.lock index 5eb94336d5..679e94a37e 100644 --- a/composer.lock +++ b/composer.lock @@ -741,36 +741,38 @@ }, { "name": "doctrine/dbal", - "version": "3.1.4", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "821b4f01a36ce63ed36c090ea74767b72db367e9" + "reference": "5d54f63541d7bed1156cb5c9b79274ced61890e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/821b4f01a36ce63ed36c090ea74767b72db367e9", - "reference": "821b4f01a36ce63ed36c090ea74767b72db367e9", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/5d54f63541d7bed1156cb5c9b79274ced61890e4", + "reference": "5d54f63541d7bed1156cb5c9b79274ced61890e4", "shasum": "" }, "require": { "composer/package-versions-deprecated": "^1.11.99", - "doctrine/cache": "^1.0|^2.0", + "doctrine/cache": "^1.11|^2.0", "doctrine/deprecations": "^0.5.3", "doctrine/event-manager": "^1.0", - "php": "^7.3 || ^8.0" + "php": "^7.3 || ^8.0", + "psr/cache": "^1|^2|^3", + "psr/log": "^1|^2|^3" }, "require-dev": { "doctrine/coding-standard": "9.0.0", "jetbrains/phpstorm-stubs": "2021.1", - "phpstan/phpstan": "1.1.1", - "phpstan/phpstan-strict-rules": "^1", + "phpstan/phpstan": "1.2.0", + "phpstan/phpstan-strict-rules": "^1.1", "phpunit/phpunit": "9.5.10", "psalm/plugin-phpunit": "0.16.1", "squizlabs/php_codesniffer": "3.6.1", "symfony/cache": "^5.2|^6.0", "symfony/console": "^2.0.5|^3.0|^4.0|^5.0|^6.0", - "vimeo/psalm": "4.12.0" + "vimeo/psalm": "4.13.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -830,7 +832,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.1.4" + "source": "https://github.com/doctrine/dbal/tree/3.2.0" }, "funding": [ { @@ -846,7 +848,7 @@ "type": "tidelift" } ], - "time": "2021-11-15T16:44:33+00:00" + "time": "2021-11-26T21:00:12+00:00" }, { "name": "doctrine/deprecations", @@ -893,16 +895,16 @@ }, { "name": "doctrine/doctrine-bundle", - "version": "2.5.0", + "version": "2.5.2", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "4a75cead0bb01cadc57c81cfa7c905e3151ed119" + "reference": "5b77477ba2981a00b423d1bb17084b87eb57a4a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/4a75cead0bb01cadc57c81cfa7c905e3151ed119", - "reference": "4a75cead0bb01cadc57c81cfa7c905e3151ed119", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/5b77477ba2981a00b423d1bb17084b87eb57a4a5", + "reference": "5b77477ba2981a00b423d1bb17084b87eb57a4a5", "shasum": "" }, "require": { @@ -916,10 +918,10 @@ "symfony/config": "^4.4.3|^5.0|^6.0", "symfony/console": "^3.4.30|^4.3.3|^5.0|^6.0", "symfony/dependency-injection": "^4.3.3|^5.0|^6.0", - "symfony/deprecation-contracts": "^2.1", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/doctrine-bridge": "^4.4.22|^5.2.7|^6.0", "symfony/framework-bundle": "^3.4.30|^4.3.3|^5.0|^6.0", - "symfony/service-contracts": "^1.1.1|^2.0" + "symfony/service-contracts": "^1.1.1|^2.0|^3" }, "conflict": { "doctrine/orm": "<2.9", @@ -986,7 +988,7 @@ ], "support": { "issues": "https://github.com/doctrine/DoctrineBundle/issues", - "source": "https://github.com/doctrine/DoctrineBundle/tree/2.5.0" + "source": "https://github.com/doctrine/DoctrineBundle/tree/2.5.2" }, "funding": [ { @@ -1002,7 +1004,7 @@ "type": "tidelift" } ], - "time": "2021-11-20T08:43:19+00:00" + "time": "2021-12-01T10:13:31+00:00" }, { "name": "doctrine/doctrine-migrations-bundle", @@ -2091,16 +2093,16 @@ }, { "name": "giggsey/libphonenumber-for-php", - "version": "8.12.37", + "version": "8.12.38", "source": { "type": "git", "url": "https://github.com/giggsey/libphonenumber-for-php.git", - "reference": "4113157949337384c41b77bc1d5c0d46c1c3201b" + "reference": "0a6293c57de9256f4bd0d673280fbfbfd1e47533" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/giggsey/libphonenumber-for-php/zipball/4113157949337384c41b77bc1d5c0d46c1c3201b", - "reference": "4113157949337384c41b77bc1d5c0d46c1c3201b", + "url": "https://api.github.com/repos/giggsey/libphonenumber-for-php/zipball/0a6293c57de9256f4bd0d673280fbfbfd1e47533", + "reference": "0a6293c57de9256f4bd0d673280fbfbfd1e47533", "shasum": "" }, "require": { @@ -2160,7 +2162,7 @@ "issues": "https://github.com/giggsey/libphonenumber-for-php/issues", "source": "https://github.com/giggsey/libphonenumber-for-php" }, - "time": "2021-11-11T16:06:11+00:00" + "time": "2021-11-26T08:32:55+00:00" }, { "name": "giggsey/locale", @@ -2216,6 +2218,329 @@ }, "time": "2021-11-04T19:12:22+00:00" }, + { + "name": "guzzlehttp/guzzle", + "version": "7.4.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/868b3571a039f0ebc11ac8f344f4080babe2cb94", + "reference": "868b3571a039f0ebc11ac8f344f4080babe2cb94", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5", + "guzzlehttp/psr7": "^1.8.3 || ^2.1", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "ext-curl": "*", + "php-http/client-integration-tests": "^3.0", + "phpunit/phpunit": "^8.5.5 || ^9.3.5", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.4.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2021-10-18T09:52:00+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2021-10-22T20:56:57+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/089edd38f5b8abba6cb01567c2a8aaa47cec4c72", + "reference": "089edd38f5b8abba6cb01567c2a8aaa47cec4c72", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.8 || ^9.3.10" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.1.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2021-10-06T17:43:30+00:00" + }, { "name": "jcupitt/vips", "version": "v1.0.8", @@ -2344,6 +2669,55 @@ ], "time": "2021-09-21T13:40:23+00:00" }, + { + "name": "landrok/activitypub", + "version": "0.5.6", + "source": { + "type": "git", + "url": "https://github.com/landrok/activitypub.git", + "reference": "509dd3d759e550f6b34016ddec1f3a3b9f8fe47f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/landrok/activitypub/zipball/509dd3d759e550f6b34016ddec1f3a3b9f8fe47f", + "reference": "509dd3d759e550f6b34016ddec1f3a3b9f8fe47f", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": ">=6.3", + "monolog/monolog": "^1.12|^2.0", + "php": "^7.2|^8.0", + "phpseclib/phpseclib": "^3.0.7", + "psr/cache": "^1.0", + "symfony/cache": ">=4.0", + "symfony/http-foundation": ">=3.4" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "ActivityPhp\\": "src/ActivityPhp/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP implementation of ActivityPub protocol based upon the ActivityStreams 2.0 data format.", + "homepage": "https://github.com/landrok/activitypub", + "keywords": [ + "Federation", + "activitypub", + "activitystreams" + ], + "support": { + "issues": "https://github.com/landrok/activitypub/issues", + "source": "https://github.com/landrok/activitypub/tree/0.5.6" + }, + "time": "2021-04-11T16:10:46+00:00" + }, { "name": "league/uri-parser", "version": "1.4.1", @@ -3201,6 +3575,73 @@ }, "time": "2020-11-19T17:43:46+00:00" }, + { + "name": "paragonie/constant_time_encoding", + "version": "v2.4.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "reference": "f34c2b11eb9d2c9318e13540a1dbc2a3afbd939c", + "shasum": "" + }, + "require": { + "php": "^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2020-12-06T15:14:20+00:00" + }, { "name": "pear/xml_xrd", "version": "v0.3.1", @@ -3603,21 +4044,132 @@ "time": "2021-10-02T14:08:47+00:00" }, { - "name": "psr/cache", - "version": "2.0.0", + "name": "phpseclib/phpseclib", + "version": "3.0.12", "source": { "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b" + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "89bfb45bd8b1abc3b37e910d57f5dbd3174f40fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", - "reference": "213f9dbc5b9bfbc4f8db86d2838dc968752ce13b", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/89bfb45bd8b1abc3b37e910d57f5dbd3174f40fb", + "reference": "89bfb45bd8b1abc3b37e910d57f5dbd3174f40fb", "shasum": "" }, "require": { - "php": ">=8.0.0" + "paragonie/constant_time_encoding": "^1|^2", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" + }, + "require-dev": { + "phing/phing": "~2.7", + "phpunit/phpunit": "^5.7|^6.0|^9.4", + "squizlabs/php_codesniffer": "~2.0" + }, + "suggest": { + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib3\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.12" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2021-11-28T23:46:03+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" }, "type": "library", "extra": { @@ -3637,7 +4189,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" + "homepage": "http://www.php-fig.org/" } ], "description": "Common interface for caching libraries", @@ -3647,9 +4199,9 @@ "psr-6" ], "support": { - "source": "https://github.com/php-fig/cache/tree/2.0.0" + "source": "https://github.com/php-fig/cache/tree/master" }, - "time": "2021-02-03T23:23:37+00:00" + "time": "2016-08-06T20:24:11+00:00" }, { "name": "psr/container", @@ -4012,6 +4564,50 @@ }, "time": "2021-05-03T11:20:27+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, { "name": "sensio/framework-extra-bundle", "version": "v5.6.1", @@ -5581,16 +6177,16 @@ }, { "name": "symfony/flex", - "version": "v1.17.5", + "version": "v1.17.6", "source": { "type": "git", "url": "https://github.com/symfony/flex.git", - "reference": "3f0dc66dcddff035a2ab98ed7e666dfd478b2712" + "reference": "7a79135e1dc66b30042b4d968ecba0908f9374bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/flex/zipball/3f0dc66dcddff035a2ab98ed7e666dfd478b2712", - "reference": "3f0dc66dcddff035a2ab98ed7e666dfd478b2712", + "url": "https://api.github.com/repos/symfony/flex/zipball/7a79135e1dc66b30042b4d968ecba0908f9374bc", + "reference": "7a79135e1dc66b30042b4d968ecba0908f9374bc", "shasum": "" }, "require": { @@ -5626,7 +6222,7 @@ "description": "Composer plugin for Symfony", "support": { "issues": "https://github.com/symfony/flex/issues", - "source": "https://github.com/symfony/flex/tree/v1.17.5" + "source": "https://github.com/symfony/flex/tree/v1.17.6" }, "funding": [ { @@ -5642,7 +6238,7 @@ "type": "tidelift" } ], - "time": "2021-11-23T11:08:47+00:00" + "time": "2021-11-29T15:39:37+00:00" }, { "name": "symfony/form", @@ -9668,23 +10264,23 @@ }, { "name": "symfonycasts/reset-password-bundle", - "version": "v1.10.0", + "version": "v1.11.0", "source": { "type": "git", "url": "https://github.com/SymfonyCasts/reset-password-bundle.git", - "reference": "cfebb54e1090900dc5666be5ee1877cd50ae3241" + "reference": "09fcd0d893bbd58d4477787c6cb5a4ffc4fc9455" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SymfonyCasts/reset-password-bundle/zipball/cfebb54e1090900dc5666be5ee1877cd50ae3241", - "reference": "cfebb54e1090900dc5666be5ee1877cd50ae3241", + "url": "https://api.github.com/repos/SymfonyCasts/reset-password-bundle/zipball/09fcd0d893bbd58d4477787c6cb5a4ffc4fc9455", + "reference": "09fcd0d893bbd58d4477787c6cb5a4ffc4fc9455", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/config": "^4.4 | ^5.0 | ^6.0", "symfony/dependency-injection": "^4.4 | ^5.0 | ^6.0", - "symfony/deprecation-contracts": "^2.2", + "symfony/deprecation-contracts": "^2.2 | ^3.0", "symfony/http-kernel": "^4.4 | ^5.0 | ^6.0" }, "conflict": { @@ -9712,29 +10308,29 @@ "description": "Symfony bundle that adds password reset functionality.", "support": { "issues": "https://github.com/SymfonyCasts/reset-password-bundle/issues", - "source": "https://github.com/SymfonyCasts/reset-password-bundle/tree/v1.10.0" + "source": "https://github.com/SymfonyCasts/reset-password-bundle/tree/v1.11.0" }, - "time": "2021-11-19T00:31:19+00:00" + "time": "2021-11-30T17:32:21+00:00" }, { "name": "symfonycasts/verify-email-bundle", - "version": "v1.6.0", + "version": "v1.7.0", "source": { "type": "git", "url": "https://github.com/SymfonyCasts/verify-email-bundle.git", - "reference": "55487a5e55ab67ad77a84eefd1c92b0fab47e6ce" + "reference": "7b17b150c39d115141cb462862baac9c281a3de9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SymfonyCasts/verify-email-bundle/zipball/55487a5e55ab67ad77a84eefd1c92b0fab47e6ce", - "reference": "55487a5e55ab67ad77a84eefd1c92b0fab47e6ce", + "url": "https://api.github.com/repos/SymfonyCasts/verify-email-bundle/zipball/7b17b150c39d115141cb462862baac9c281a3de9", + "reference": "7b17b150c39d115141cb462862baac9c281a3de9", "shasum": "" }, "require": { "php": ">=7.2.5", "symfony/config": "^4.4 | ^5.0 | ^6.0", "symfony/dependency-injection": "^4.4 | ^5.0 | ^6.0", - "symfony/deprecation-contracts": "^2.2", + "symfony/deprecation-contracts": "^2.2 | ^3.0", "symfony/http-kernel": "^4.4 | ^5.0 | ^6.0", "symfony/routing": "^4.4 | ^5.0 | ^6.0" }, @@ -9761,9 +10357,9 @@ "description": "Simple, stylish Email Verification for Symfony", "support": { "issues": "https://github.com/SymfonyCasts/verify-email-bundle/issues", - "source": "https://github.com/SymfonyCasts/verify-email-bundle/tree/v1.6.0" + "source": "https://github.com/SymfonyCasts/verify-email-bundle/tree/v1.7.0" }, - "time": "2021-11-19T00:41:41+00:00" + "time": "2021-11-30T17:26:37+00:00" }, { "name": "tgalopin/html-sanitizer", @@ -9815,28 +10411,28 @@ }, { "name": "tgalopin/html-sanitizer-bundle", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/tgalopin/html-sanitizer-bundle.git", - "reference": "87e07cee80136d845a21faa3116982990884a89a" + "reference": "d5a59d214c6e8eeebd67c103288e3659027144a7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tgalopin/html-sanitizer-bundle/zipball/87e07cee80136d845a21faa3116982990884a89a", - "reference": "87e07cee80136d845a21faa3116982990884a89a", + "url": "https://api.github.com/repos/tgalopin/html-sanitizer-bundle/zipball/d5a59d214c6e8eeebd67c103288e3659027144a7", + "reference": "d5a59d214c6e8eeebd67c103288e3659027144a7", "shasum": "" }, "require": { "php": ">=7.1", - "symfony/framework-bundle": "^3.4|^4.0|^5.0", + "symfony/framework-bundle": "^3.4|^4.0|^5.0|^6.0", "tgalopin/html-sanitizer": "^1.1" }, "require-dev": { "phpunit/phpunit": "^7.4", - "symfony/form": "^4.1|^5.0", - "symfony/twig-bundle": "^4.1|^5.0", - "symfony/var-dumper": "^4.1|^5.0" + "symfony/form": "^4.1|^5.0|^6.0", + "symfony/twig-bundle": "^4.1|^5.0|^6.0", + "symfony/var-dumper": "^4.1|^5.0|^6.0" }, "type": "symfony-bundle", "autoload": { @@ -9857,9 +10453,9 @@ "description": "Symfony Bundle for https://github.com/tgalopin/html-sanitizer", "support": { "issues": "https://github.com/tgalopin/html-sanitizer-bundle/issues", - "source": "https://github.com/tgalopin/html-sanitizer-bundle/tree/1.3.0" + "source": "https://github.com/tgalopin/html-sanitizer-bundle/tree/1.4.0" }, - "time": "2021-01-27T08:34:58+00:00" + "time": "2021-11-25T21:37:14+00:00" }, { "name": "twig/extra-bundle", @@ -10974,16 +11570,16 @@ }, { "name": "nikic/php-parser", - "version": "v4.13.1", + "version": "v4.13.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd" + "reference": "210577fe3cf7badcc5814d99455df46564f3c077" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/63a79e8daa781cac14e5195e63ed8ae231dd10fd", - "reference": "63a79e8daa781cac14e5195e63ed8ae231dd10fd", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", + "reference": "210577fe3cf7badcc5814d99455df46564f3c077", "shasum": "" }, "require": { @@ -11024,9 +11620,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" }, - "time": "2021-11-03T20:52:16+00:00" + "time": "2021-11-30T19:35:32+00:00" }, { "name": "phar-io/manifest", @@ -11401,16 +11997,16 @@ }, { "name": "phpunit/php-file-iterator", - "version": "3.0.5", + "version": "3.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", "shasum": "" }, "require": { @@ -11449,7 +12045,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.5" + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" }, "funding": [ { @@ -11457,7 +12053,7 @@ "type": "github" } ], - "time": "2020-09-28T05:57:25+00:00" + "time": "2021-12-02T12:48:52+00:00" }, { "name": "phpunit/php-invoker", @@ -11745,16 +12341,16 @@ }, { "name": "psy/psysh", - "version": "v0.10.11", + "version": "v0.10.12", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "38017532bba35d15d28dcc001b4274df0251c4a1" + "reference": "a0d9981aa07ecfcbea28e4bfa868031cca121e7d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/38017532bba35d15d28dcc001b4274df0251c4a1", - "reference": "38017532bba35d15d28dcc001b4274df0251c4a1", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/a0d9981aa07ecfcbea28e4bfa868031cca121e7d", + "reference": "a0d9981aa07ecfcbea28e4bfa868031cca121e7d", "shasum": "" }, "require": { @@ -11814,9 +12410,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.10.11" + "source": "https://github.com/bobthecow/psysh/tree/v0.10.12" }, - "time": "2021-11-23T15:02:17+00:00" + "time": "2021-11-30T14:05:36+00:00" }, { "name": "sebastian/cli-parser", @@ -13001,16 +13597,16 @@ }, { "name": "symfony/maker-bundle", - "version": "v1.36.3", + "version": "v1.36.4", "source": { "type": "git", "url": "https://github.com/symfony/maker-bundle.git", - "reference": "0f40c826c0725208c254ddcd3481690e6c7e5047" + "reference": "716eee9c8b10b33e682df1b7d80b9061887e9691" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/0f40c826c0725208c254ddcd3481690e6c7e5047", - "reference": "0f40c826c0725208c254ddcd3481690e6c7e5047", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/716eee9c8b10b33e682df1b7d80b9061887e9691", + "reference": "716eee9c8b10b33e682df1b7d80b9061887e9691", "shasum": "" }, "require": { @@ -13020,7 +13616,7 @@ "symfony/config": "^4.4|^5.0|^6.0", "symfony/console": "^4.4|^5.0|^6.0", "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/deprecation-contracts": "^2.2", + "symfony/deprecation-contracts": "^2.2|^3", "symfony/filesystem": "^4.4|^5.0|^6.0", "symfony/finder": "^4.4|^5.0|^6.0", "symfony/framework-bundle": "^4.4|^5.0|^6.0", @@ -13069,7 +13665,7 @@ ], "support": { "issues": "https://github.com/symfony/maker-bundle/issues", - "source": "https://github.com/symfony/maker-bundle/tree/v1.36.3" + "source": "https://github.com/symfony/maker-bundle/tree/v1.36.4" }, "funding": [ { @@ -13085,31 +13681,31 @@ "type": "tidelift" } ], - "time": "2021-11-22T18:44:03+00:00" + "time": "2021-12-01T00:27:38+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v5.3.11", + "version": "v5.4.0", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "7b3637f0ce55c510a0fbe6e4d49b223103b7bf7b" + "reference": "59bbd98ee7aa15b9f75c0fc088c7a5cbf7aa9b5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/7b3637f0ce55c510a0fbe6e4d49b223103b7bf7b", - "reference": "7b3637f0ce55c510a0fbe6e4d49b223103b7bf7b", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/59bbd98ee7aa15b9f75c0fc088c7a5cbf7aa9b5c", + "reference": "59bbd98ee7aa15b9f75c0fc088c7a5cbf7aa9b5c", "shasum": "" }, "require": { "php": ">=7.1.3", - "symfony/deprecation-contracts": "^2.1" + "symfony/deprecation-contracts": "^2.1|^3" }, "conflict": { "phpunit/phpunit": "<7.5|9.1.2" }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0" + "symfony/error-handler": "^4.4|^5.0|^6.0" }, "suggest": { "symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" @@ -13152,7 +13748,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v5.3.11" + "source": "https://github.com/symfony/phpunit-bridge/tree/v5.4.0" }, "funding": [ { @@ -13168,7 +13764,7 @@ "type": "tidelift" } ], - "time": "2021-11-12T11:38:27+00:00" + "time": "2021-11-29T15:30:56+00:00" }, { "name": "symfony/web-profiler-bundle", diff --git a/plugins/ActivityPub/ActivityPub.php b/plugins/ActivityPub/ActivityPub.php index 5a67b41732..72f8ef3386 100644 --- a/plugins/ActivityPub/ActivityPub.php +++ b/plugins/ActivityPub/ActivityPub.php @@ -2,6 +2,33 @@ declare(strict_types=1); +// {{{ License +// This file is part of GNU social - https://www.gnu.org/software/social +// +// GNU social 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. +// +// GNU social 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 GNU social. If not, see . +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + namespace Plugin\ActivityPub; use App\Core\Event; @@ -22,18 +49,30 @@ use Exception; use Plugin\ActivityPub\Controller\Inbox; use Plugin\ActivityPub\Entity\ActivitypubActor; use Plugin\ActivityPub\Util\HTTPSignature; -use Plugin\ActivityPub\Util\Model\EntityToType\EntityToType; +use Plugin\ActivityPub\Util\Model; use Plugin\ActivityPub\Util\Response\ActorResponse; use Plugin\ActivityPub\Util\Response\NoteResponse; -use Plugin\ActivityPub\Util\Response\TypeResponse; -use Plugin\ActivityPub\Util\Type; +use Plugin\ActivityPub\Util\TypeResponse; +use Plugin\ActivityPub\Util\Validator\contentLangModelValidator; +use Plugin\ActivityPub\Util\Validator\manuallyApprovesFollowersModelValidator; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\ResponseInterface; use XML_XRD; use XML_XRD_Element_Link; use function count; -use function Psy\debug; +use function is_null; +use const PHP_URL_HOST; use const PREG_SET_ORDER; +/** + * Adds ActivityPub support to GNU social when enabled + * + * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ class ActivityPub extends Plugin { // ActivityStreams 2.0 Accept Headers @@ -89,6 +128,14 @@ class ActivityPub extends Plugin return Event::next; } + /** + * Fill Actor->getUrl() calls with correct URL coming from ActivityPub + * + * @param Actor $actor + * @param int $type + * @param string|null $url + * @return bool + */ public function onStartGetActorUrl(Actor $actor, int $type, ?string &$url): bool { if ( @@ -106,12 +153,80 @@ class ActivityPub extends Plugin return Event::next; } + /** + * Overload core endpoints to make resources available in ActivityStreams 2.0 + * + * @throws Exception + */ + public function onControllerResponseInFormat(string $route, array $accept_header, array $vars, ?TypeResponse &$response = null): bool + { + if (count(array_intersect(self::$accept_headers, $accept_header)) === 0) { + return Event::next; + } + switch ($route) { + case 'actor_view_id': + case 'actor_view_nickname': + $response = ActorResponse::handle($vars['actor']); + return Event::stop; + case 'note_view': + $response = NoteResponse::handle($vars['note']); + return Event::stop; + default: + if (Event::handle('ActivityPubActivityStreamsTwoResponse', [$route, $vars, &$response]) === Event::stop) { + return Event::stop; + } + return Event::next; + } + } + + /** + * Add ActivityStreams 2 Extensions + * + * @param string $type_name + * @param array $validators + * @return bool + */ + public function onActivityPubValidateActivityStreamsTwoData(string $type_name, array &$validators): bool + { + switch ($type_name) { + case 'Person': + $validators['manuallyApprovesFollowers'] = manuallyApprovesFollowersModelValidator::class; + break; + case 'Note': + $validators['contentLang'] = contentLangModelValidator::class; + break; + } + return Event::next; + } + + // FreeNetworkComponent Events + + /** + * Let FreeNetwork Component know we exist and which class to use to call the freeNetworkDistribute method + * + * @param array $protocols + * @return bool + */ public function onAddFreeNetworkProtocol(array &$protocols): bool { $protocols[] = '\Plugin\ActivityPub\ActivityPub'; return Event::next; } + /** + * The FreeNetwork component will call this function to distribute this instance's activities + * + * @param Actor $sender + * @param Activity $activity + * @param array $targets + * @param string|null $reason + * @param array $delivered + * @return bool + * @throws ClientExceptionInterface + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface + */ public static function freeNetworkDistribute(Actor $sender, Activity $activity, array $targets, ?string $reason = null, array &$delivered = []): bool { $to_addr = []; @@ -130,14 +245,13 @@ class ActivityPub extends Plugin //$to_failed = []; foreach ($to_addr as $inbox => $dummy) { try { - $res = self::postman($sender, EntityToType::translate($activity), $inbox); + $res = self::postman($sender, Model::toJson($activity), $inbox); // accumulate errors for later use, if needed $status_code = $res->getStatusCode(); if (!($status_code === 200 || $status_code === 202 || $status_code === 409)) { $res_body = json_decode($res->getContent(), true); - $errors[] = isset($res_body['error']) ? - $res_body['error'] : "An unknown error occurred."; + $errors[] = $res_body['error'] ?? 'An unknown error occurred.'; //$to_failed[$inbox] = $activity; } else { array_push($delivered, ...$dummy); @@ -145,7 +259,7 @@ class ActivityPub extends Plugin FreeNetworkActorProtocol::protocolSucceeded( 'activitypub', $actor, - Discovery::normalize($actor->getNickname() . '@' . parse_url($inbox, PHP_URL_HOST)) + Discovery::normalize($actor->getNickname() . '@' . parse_url($inbox, PHP_URL_HOST)), ); } } @@ -153,7 +267,6 @@ class ActivityPub extends Plugin Log::error('ActivityPub @ freeNetworkDistribute: ' . $e->getMessage()); //$to_failed[$inbox] = $activity; } - } if (!empty($errors)) { @@ -165,27 +278,117 @@ class ActivityPub extends Plugin } /** + * Internal tool to sign and send activities out + * * @param Actor $sender - * @param Type $activity + * @param string $json_activity * @param string $inbox * @param string $method * @return ResponseInterface + * @throws Exception */ - public static function postman(Actor $sender, mixed $activity, string $inbox, string $method = 'post'): ResponseInterface + private static function postman(Actor $sender, string $json_activity, string $inbox, string $method = 'post'): ResponseInterface { - $data = $activity->toJson(); - Log::debug('ActivityPub Postman: Delivering ' . $data . ' to ' . $inbox); + Log::debug('ActivityPub Postman: Delivering ' . $json_activity . ' to ' . $inbox); - $headers = HTTPSignature::sign($sender, $inbox, $data); + $headers = HTTPSignature::sign($sender, $inbox, $json_activity); Log::debug('ActivityPub Postman: Delivery headers were: ' . print_r($headers, true)); - $response = HTTPClient::$method($inbox, ['headers' => $headers, 'body' => $data]); + $response = HTTPClient::$method($inbox, ['headers' => $headers, 'body' => $json_activity]); Log::debug('ActivityPub Postman: Delivery result with status code ' . $response->getStatusCode() . ': ' . $response->getContent()); return $response; } + // WebFinger Events - public static function getActorByUri(string $resource, ?bool $attempt_fetch = true): Actor + /** + * Add activity+json mimetype to WebFinger + * + * @param XML_XRD $xrd + * @param Actor $object + * @return bool + */ + public function onEndWebFingerProfileLinks(XML_XRD $xrd, Actor $object): bool + { + if ($object->isPerson()) { + $link = new XML_XRD_Element_Link( + rel: 'self', + href: $object->getUri(Router::ABSOLUTE_URL),//Router::url('actor_view_id', ['id' => $object->getId()], Router::ABSOLUTE_URL), + type: 'application/activity+json', + ); + $xrd->links[] = clone $link; + } + return Event::next; + } + + /** + * When FreeNetwork component asks us to help with identifying Actors from XRDs + * + * @param XML_XRD $xrd + * @param Actor|null $actor + * @return bool + */ + public function onFreeNetworkFoundXrd(XML_XRD $xrd, ?Actor &$actor = null): bool + { + $addr = null; + foreach ($xrd->aliases as $alias) { + if (Discovery::isAcct($alias)) { + $addr = Discovery::normalize($alias); + } + } + if (is_null($addr)) { + return Event::next; + } else { + if (!FreeNetworkActorProtocol::canIAddr('activitypub', $addr)) { + return Event::next; + } + } + try { + $ap_actor = ActivitypubActor::fromXrd($addr, $xrd); + $actor = Actor::getById($ap_actor->getActorId()); + FreeNetworkActorProtocol::protocolSucceeded('activitypub', $actor, $addr); + return Event::stop; + } catch (Exception $e) { + Log::error('ActivityPub Actor from URL Mention check failed: ' . $e->getMessage()); + return Event::next; + } + } + + // Discovery Events + + /** + * When FreeNetwork component asks us to help with identifying Actors from URIs + * + * @param string $target + * @param Actor|null $actor + * @return bool + */ + public function onFreeNetworkFindMentions(string $target, ?Actor &$actor = null): bool + { + try { + if (FreeNetworkActorProtocol::canIAddr('activitypub', $addr = Discovery::normalize($target))) { + $ap_actor = ActivitypubActor::getByAddr($addr); + $actor = Actor::getById($ap_actor->getActorId()); + FreeNetworkActorProtocol::protocolSucceeded('activitypub', $actor->getId(), $addr); + return Event::stop; + } else { + return Event::next; + } + } catch (Exception $e) { + Log::error('ActivityPub Webfinger Mention check failed: ' . $e->getMessage()); + return Event::next; + } + } + + /** + * Get an Actor from ActivityPub URI, if it doesn't exist, attempt to fetch it + * This should only be necessary internally. + * + * @param string $resource + * @return Actor got from URI + * @throws NoSuchActorException + */ + public static function getActorByUri(string $resource): Actor { // Try local if (Common::isValidHttpUrl($resource)) { @@ -213,168 +416,4 @@ class ActivityPub extends Plugin throw new NoSuchActorException("From URI: {$resource}"); } } - - /** - * @throws Exception - */ - public function onControllerResponseInFormat(string $route, array $accept_header, array $vars, ?TypeResponse &$response = null): bool - { - if (count(array_intersect(self::$accept_headers, $accept_header)) === 0) { - return Event::next; - } - switch ($route) { - case 'actor_view_id': - case 'actor_view_nickname': - $response = ActorResponse::handle($vars['actor']); - return Event::stop; - case 'note_view': - $response = NoteResponse::handle($vars['note']); - return Event::stop; - /*case 'actor_favourites_id': - case 'actor_favourites_nickname': - $response = LikeResponse::handle($vars['actor']); - return Event::stop; - case 'actor_subscriptions_id': - case 'actor_subscriptions_nickname': - $response = FollowingResponse::handle($vars['actor']); - return Event::stop; - case 'actor_subscribers_id': - case 'actor_subscribers_nickname': - $response = FollowersResponse::handle($vars['actor']); - return Event::stop;*/ - default: - if (Event::handle('ActivityStreamsTwoResponse', [$route, &$response]) == Event::stop) { - return Event::stop; - } - return Event::next; - } - } - - /******************************************************** - * WebFinger Events * - ********************************************************/ - - /** - * Add activity+json mimetype on WebFinger - * - * @throws Exception - */ - public function onEndWebFingerProfileLinks(XML_XRD $xrd, Actor $object): bool - { - if ($object->isPerson()) { - $link = new XML_XRD_Element_Link( - rel: 'self', - href: $object->getUri(Router::ABSOLUTE_URL),//Router::url('actor_view_id', ['id' => $object->getId()], Router::ABSOLUTE_URL), - type: 'application/activity+json', - ); - $xrd->links[] = clone $link; - } - return Event::next; - } - - public function onFreeNetworkFindMentions(string $target, ?Actor &$actor = null): bool - { - try { - if (FreeNetworkActorProtocol::canIAddr('activitypub', $addr = Discovery::normalize($target))) { - $ap_actor = ActivitypubActor::getByAddr($addr); - $actor = Actor::getById($ap_actor->getActorId()); - FreeNetworkActorProtocol::protocolSucceeded('activitypub', $actor->getId(), $addr); - return Event::stop; - } else { - return Event::next; - } - } catch (Exception $e) { - Log::error("ActivityPub Webfinger Mention check failed: " . $e->getMessage()); - return Event::next; - } - } - - public function onFreeNetworkFoundXrd(XML_XRD $xrd, ?Actor &$actor = null): bool - { - $addr = null; - foreach ($xrd->aliases as $alias) { - if (Discovery::isAcct($alias)) { - $addr = Discovery::normalize($alias); - } - } - if (is_null($addr)) { - return Event::next; - } else { - if (!FreeNetworkActorProtocol::canIAddr('activitypub', $addr)) { - return Event::next; - } - } - try { - $ap_actor = ActivitypubActor::fromXrd($addr, $xrd); - $actor = Actor::getById($ap_actor->getActorId()); - FreeNetworkActorProtocol::protocolSucceeded('activitypub', $actor, $addr); - return Event::stop; - } catch (Exception $e) { - Log::error("ActivityPub Actor from URL Mention check failed: " . $e->getMessage()); - return Event::next; - } - } - - /** - * Allow remote profile references to be used in commands: - * sub update@status.net - * whois evan@identi.ca - * reply http://identi.ca/evan hey what's up - * - * @param Command $command - * @param string $arg - * @param Actor &$profile - * @return bool hook return code - * @author GNU social - */ - //public function onStartCommandGetProfile($command, $arg, &$profile) - //{ - // $aprofile = ActivitypubActor::fromUri($arg); - // if (!($aprofile instanceof ActivitypubActor)) { - // // No remote ActivityPub profile found - // return Event::next; - // } - // - // return Event::stop; - //} - - /******************************************************** - * Discovery Events * - ********************************************************/ - - /** - * Profile from URI. - * - * @param string $uri - * @param Actor &$profile in/out param: Profile got from URI - * @return mixed hook return code - * @author GNU social - */ - //public function onStartGetProfileFromURI($uri, &$profile) - //{ - // try { - // $profile = Explorer::get_profile_from_url($uri); - // return Event::stop; - // } catch (Exception) { - // return Event::next; // It's not an ActivityPub profile as far as we know, continue event handling - // } - //} - - /** - * Try to grab and store the remote profile by the given uri - * - * @param string $uri - * @param Actor|null &$profile - * @return bool - */ - //public function onRemoteFollowPullProfile(string $uri, ?Actor &$profile): bool - //{ - // $aprofile = ActivitypubActor::fromUri($uri); - // if (!($aprofile instanceof ActivitypubActor)) { - // // No remote ActivityPub profile found - // return Event::next; - // } - // - // return is_null($profile) ? Event::next : Event::stop; - //} } diff --git a/plugins/ActivityPub/Controller/Inbox.php b/plugins/ActivityPub/Controller/Inbox.php index 2ef9042e21..16701c72e8 100644 --- a/plugins/ActivityPub/Controller/Inbox.php +++ b/plugins/ActivityPub/Controller/Inbox.php @@ -1,9 +1,8 @@ . - // }}} +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + namespace Plugin\ActivityPub\Controller; use App\Core\Controller; @@ -28,30 +36,37 @@ use App\Core\DB\DB; use App\Core\Log; use App\Core\Router\Router; use App\Entity\Actor; +use App\Util\Exception\ClientException; use Component\FreeNetwork\Entity\FreeNetworkActorProtocol; +use Component\FreeNetwork\Util\Discovery; use Exception; use Plugin\ActivityPub\Entity\ActivitypubActor; use Plugin\ActivityPub\Entity\ActivitypubRsa; use Plugin\ActivityPub\Util\Explorer; use Plugin\ActivityPub\Util\HTTPSignature; +use Plugin\ActivityPub\Util\Model; +use Plugin\ActivityPub\Util\TypeResponse; use function App\Core\I18n\_m; -use App\Util\Exception\ClientException; -use Plugin\ActivityPub\ActivityPub; -use Plugin\ActivityPub\Util\Model\AS2ToEntity\AS2ToEntity; -use Plugin\ActivityPub\Util\Response\TypeResponse; -use Plugin\ActivityPub\Util\Type; -use Plugin\ActivityPub\Util\Type\Util; +use function is_null; +use const PHP_URL_HOST; +/** + * ActivityPub Inbox Handler + * + * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ class Inbox extends Controller { /** - * Inbox handler + * Create an Inbox Handler to receive something from someone. */ public function handle(?int $gsactor_id = null): TypeResponse { + $error = fn(string $m): TypeResponse => new TypeResponse(json_encode(['error' => $m])); $path = Router::url('activitypub_inbox', type: Router::ABSOLUTE_PATH); - if (!\is_null($gsactor_id)) { + if (!is_null($gsactor_id)) { try { $user = DB::findOneBy('local_user', ['id' => $gsactor_id]); $path = Router::url('activitypub_actor_inbox', ['gsactor_id' => $user->getId()], type: Router::ABSOLUTE_PATH); @@ -61,19 +76,19 @@ class Inbox extends Controller } Log::debug('ActivityPub Inbox: Received a POST request.'); - $body = (string) $this->request->getContent(); - $type = Type::fromJson($body); + $body = (string)$this->request->getContent(); + $type = Model::jsonToType($body); if ($type->has('actor') === false) { - ActivityPubReturn::error('Actor not found in the request.'); + $error('Actor not found in the request.'); } try { $ap_actor = ActivitypubActor::fromUri($type->get('actor')); $actor = Actor::getById($ap_actor->getActorId()); DB::flush(); - } catch (Exception) { - ActivityPubReturn::error('Invalid actor.'); + } catch (Exception $e) { + $error('Invalid actor.'); } $actor_public_key = ActivitypubRsa::getByActor($actor)->getPublicKey(); @@ -86,7 +101,7 @@ class Inbox extends Controller if (!isset($headers['signature'])) { Log::debug('ActivityPub Inbox: HTTP Signature: Missing Signature header.'); - ActivityPubReturn::error('Missing Signature header.', 400); + $error('Missing Signature header.', 400); // TODO: support other methods beyond HTTP Signatures } @@ -95,7 +110,7 @@ class Inbox extends Controller Log::debug('ActivityPub Inbox: HTTP Signature Data: ' . print_r($signatureData, true)); if (isset($signatureData['error'])) { Log::debug('ActivityPub Inbox: HTTP Signature: ' . json_encode($signatureData, JSON_PRETTY_PRINT)); - ActivityPubReturn::error(json_encode($signatureData, JSON_PRETTY_PRINT), 400); + $error(json_encode($signatureData, JSON_PRETTY_PRINT), 400); } list($verified, /*$headers*/) = HTTPSignature::verify($actor_public_key, $signatureData, $headers, $path, $body); @@ -105,12 +120,12 @@ class Inbox extends Controller try { $res = Explorer::get_remote_user_activity($ap_actor->getUri()); } catch (Exception) { - ActivityPubReturn::error('Invalid remote actor.'); + $error('Invalid remote actor.'); } try { $actor = ActivitypubActor::update_profile($ap_actor, $res); } catch (Exception) { - ActivityPubReturn::error('Failed to updated remote actor information.'); + $error('Failed to updated remote actor information.'); } [$verified, /*$headers*/] = HTTPSignature::verify($actor_public_key, $signatureData, $headers, $path, $body); @@ -119,7 +134,7 @@ class Inbox extends Controller // If it still failed despite profile update if ($verified !== 1) { Log::debug('ActivityPub Inbox: HTTP Signature: Invalid signature.'); - ActivityPubReturn::error('Invalid signature.'); + $error('Invalid signature.'); } // HTTP signature checked out, make sure the "actor" of the activity matches that of the signature @@ -128,8 +143,12 @@ class Inbox extends Controller // TODO: Check if Actor has authority over payload // Store Activity - $ap_act = AS2ToEntity::store(activity: $type->toArray(), source: 'ActivityPub'); - FreeNetworkActorProtocol::protocolSucceeded('activitypub', $actor->getId()); + $ap_act = Model\Activity::fromJson($type, ['source' => 'ActivityPub']); + FreeNetworkActorProtocol::protocolSucceeded( + 'activitypub', + $ap_actor->getActorId(), + Discovery::normalize($actor->getNickname() . '@' . parse_url($ap_actor->getInboxUri(), PHP_URL_HOST)) + ); DB::flush(); dd($ap_act, $act = $ap_act->getActivity(), $act->getActor(), $act->getObject()); diff --git a/plugins/ActivityPub/Entity/ActivitypubActivity.php b/plugins/ActivityPub/Entity/ActivitypubActivity.php index 81e7c9ca30..e3581b0a38 100644 --- a/plugins/ActivityPub/Entity/ActivitypubActivity.php +++ b/plugins/ActivityPub/Entity/ActivitypubActivity.php @@ -1,9 +1,8 @@ . - // }}} +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + namespace Plugin\ActivityPub\Entity; use App\Core\DB\DB; @@ -29,14 +37,9 @@ use App\Entity\Activity; use DateTimeInterface; /** - * Entity for all activities we know about + * Table Definition for activitypub_activity * - * @category DB - * @package GNUsocial - * - * @author Hugo Sales - * @author Diogo Peralta Cordeiro - * @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ class ActivitypubActivity extends Entity @@ -127,19 +130,19 @@ class ActivitypubActivity extends Entity public static function schemaDef(): array { return [ - 'name' => 'activitypub_activity', + 'name' => 'activitypub_activity', 'fields' => [ - 'activity_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Activity.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'activity_id to give attention'], - 'activity_uri' => ['type' => 'text', 'not null' => true, 'description' => 'Activity\'s URI'], - 'object_uri' => ['type' => 'text', 'not null' => true, 'description' => 'Object\'s URI'], - 'is_local' => ['type' => 'bool', 'not null' => true, 'description' => 'whether this was a locally generated or an imported activity'], - 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], - 'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], + 'activity_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Activity.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'activity_id to give attention'], + 'activity_uri' => ['type' => 'text', 'not null' => true, 'description' => 'Activity\'s URI'], + 'object_uri' => ['type' => 'text', 'not null' => true, 'description' => 'Object\'s URI'], + 'is_local' => ['type' => 'bool', 'not null' => true, 'description' => 'whether this was a locally generated or an imported activity'], + 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], + 'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], ], 'primary key' => ['activity_uri'], - 'indexes' => [ + 'indexes' => [ 'activity_activity_uri_idx' => ['activity_uri'], - 'activity_object_uri_idx' => ['object_uri'], + 'activity_object_uri_idx' => ['object_uri'], ], ]; } diff --git a/plugins/ActivityPub/Entity/ActivitypubActor.php b/plugins/ActivityPub/Entity/ActivitypubActor.php index fef9f4e507..eb99f449a7 100644 --- a/plugins/ActivityPub/Entity/ActivitypubActor.php +++ b/plugins/ActivityPub/Entity/ActivitypubActor.php @@ -1,8 +1,8 @@ . - // }}} /** * ActivityPub implementation for GNU social * * @package GNUsocial - * - * @author Diogo Peralta Cordeiro + * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ @@ -34,20 +33,21 @@ namespace Plugin\ActivityPub\Entity; use App\Core\Cache; use App\Core\Entity; -use function App\Core\I18n\_m; use App\Core\Log; -use App\Entity\Actor; use Component\FreeNetwork\Util\Discovery; use DateTimeInterface; use Exception; use Plugin\ActivityPub\Util\DiscoveryHints; use Plugin\ActivityPub\Util\Explorer; +use XML_XRD; +use function App\Core\I18n\_m; +use function array_key_exists; +use function is_null; /** * Table Definition for activitypub_actor * - * @author Diogo Peralta Cordeiro false); + $uri = Cache::get(sprintf('ActivitypubActor-webfinger-%s', urlencode($addr)), fn() => false); if ($uri !== false) { - if (\is_null($uri)) { + if (is_null($uri)) { // TRANS: Exception. throw new Exception(_m('Not a valid WebFinger address (via cache).')); } @@ -189,14 +189,14 @@ class ActivitypubActor extends Entity return self::fromXrd($addr, $xrd); } - public static function fromXrd(string $addr, \XML_XRD $xrd): self + public static function fromXrd(string $addr, XML_XRD $xrd): self { $hints = array_merge( ['webfinger' => $addr], DiscoveryHints::fromXRD($xrd), ); - if (\array_key_exists('activitypub', $hints)) { + if (array_key_exists('activitypub', $hints)) { $uri = $hints['activitypub']; try { LOG::info("Discovery on acct:{$addr} with URI:{$uri}"); @@ -240,17 +240,17 @@ class ActivitypubActor extends Entity public static function schemaDef(): array { return [ - 'name' => 'activitypub_actor', + 'name' => 'activitypub_actor', 'fields' => [ - 'uri' => ['type' => 'text', 'not null' => true], - 'actor_id' => ['type' => 'int', 'not null' => true], - 'inbox_uri' => ['type' => 'text', 'not null' => true], + 'uri' => ['type' => 'text', 'not null' => true], + 'actor_id' => ['type' => 'int', 'not null' => true], + 'inbox_uri' => ['type' => 'text', 'not null' => true], 'inbox_shared_uri' => ['type' => 'text'], - 'url' => ['type' => 'text'], - 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], - 'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], + 'url' => ['type' => 'text'], + 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], + 'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], ], - 'primary key' => ['actor_id'], + 'primary key' => ['actor_id'], 'foreign keys' => [ 'activitypub_actor_actor_id_fkey' => ['actor', ['actor_id' => 'id']], ], diff --git a/plugins/ActivityPub/Entity/ActivitypubRsa.php b/plugins/ActivityPub/Entity/ActivitypubRsa.php index 727362dc55..96b0fc5dd9 100644 --- a/plugins/ActivityPub/Entity/ActivitypubRsa.php +++ b/plugins/ActivityPub/Entity/ActivitypubRsa.php @@ -1,4 +1,8 @@ . +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ namespace Plugin\ActivityPub\Entity; @@ -22,25 +37,11 @@ use App\Core\Log; use App\Entity\Actor; use App\Util\Exception\ServerException; use DateTimeInterface; -use Doctrine\ORM\UnitOfWork; -use Exception; - -/** - * ActivityPub implementation for GNU social - * - * @package GNUsocial - * @author Diogo Peralta Cordeiro <@diogo.site> - * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org - * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later - * @link http://www.gnu.org/software/social/ - */ /** * ActivityPub Keys System * - * @category Plugin - * @package GNUsocial - * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ class ActivitypubRsa extends Entity @@ -137,7 +138,7 @@ class ActivitypubRsa extends Entity * Guarantees RSA keys for a given actor. * * @param Actor $gsactor - * @param bool $fetch=true Should attempt to fetch keys from a remote profile? + * @param bool $fetch =true Should attempt to fetch keys from a remote profile? * @return ActivitypubRsa The keys (private key is null for remote actors) * @throws ServerException It should never occur, but if so, we break everything! */ diff --git a/plugins/ActivityPub/Util/DiscoveryHints.php b/plugins/ActivityPub/Util/DiscoveryHints.php index 3e9a662e28..f00cd70678 100644 --- a/plugins/ActivityPub/Util/DiscoveryHints.php +++ b/plugins/ActivityPub/Util/DiscoveryHints.php @@ -1,6 +1,33 @@ . +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ namespace Plugin\ActivityPub\Util; @@ -19,31 +46,24 @@ namespace Plugin\ActivityPub\Util; // You should have received a copy of the GNU Affero General Public License // along with GNU social. If not, see . use App\Core\Event; -use App\Core\HTTPClient; -use Component\FreeNetwork\Util\Discovery; -use Component\FreeNetwork\Util\WebfingerResource\WebfingerResourceActor; -use Mf2 as Mf2; use XML_XRD; /** - * ActivityPub implementation for GNU social + * DiscoveryHints implementation for GNU social * - * @package GNUsocial * - * @author Evan Prodromou - * @author Brion Vibber - * @author James Walker - * @author Siebrand Mazeland - * @author Mikael Nordfeldth - * @author Diogo Cordeiro - * @copyright 2010, 2019, 2021 Free Software Foundation, Inc http://www.fsf.org + * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later - * - * @see http://www.gnu.org/software/social/ */ class DiscoveryHints { - public static function fromXRD(XML_XRD $xrd) + /** + * Search the WebFinger XRD after an ActivityPub URI + * + * @param XML_XRD $xrd + * @return array + */ + public static function fromXRD(XML_XRD $xrd): array { $hints = []; @@ -59,121 +79,4 @@ class DiscoveryHints return $hints; } -} -//class DiscoveryHints -//{ -// public static function fromXRD(XML_XRD $xrd) -// { -// $hints = []; -// -// if (Event::handle('StartDiscoveryHintsFromXRD', [$xrd, &$hints])) { -// foreach ($xrd->links as $link) { -// switch ($link->rel) { -// case WebfingerResourceActor::PROFILEPAGE: -// $hints['profileurl'] = $link->href; -// break; -// case Discovery::UPDATESFROM: -// if (empty($link->type) || $link->type == 'application/atom+xml') { -// $hints['feedurl'] = $link->href; -// } -// break; -// case Discovery::HCARD: -// case Discovery::MF2_HCARD: -// $hints['hcard'] = $link->href; -// break; -// default: -// break; -// } -// } -// Event::handle('EndDiscoveryHintsFromXRD', [$xrd, &$hints]); -// } -// -// return $hints; -// } -// -// public static function fromHcardUrl($url) -// { -// $response = HTTPClient::get($url, ['headers' => ['Accept' => 'text/html,application/xhtml+xml']]); -// -// if (!HTTPClient::statusCodeIsOkay($response)) { -// return null; -// } -// -// return self::hcardHints( -// $response->getContent(), -// HTTPClient::getEffectiveUrl($response) -// ); -// } -// -// public static function hcardHints($body, $url) -// { -// $hcard = self::hcard($body, $url); -// -// if (empty($hcard)) { -// return []; -// } -// -// $hints = []; -// -// // XXX: don't copy stuff into an array and then copy it again -// -// if (array_key_exists('nickname', $hcard) && !empty($hcard['nickname'][0])) { -// $hints['nickname'] = $hcard['nickname'][0]; -// } -// -// if (array_key_exists('name', $hcard) && !empty($hcard['name'][0])) { -// $hints['fullname'] = $hcard['name'][0]; -// } -// -// if (array_key_exists('photo', $hcard) && count($hcard['photo'])) { -// $hints['avatar'] = $hcard['photo'][0]; -// } -// -// if (array_key_exists('note', $hcard) && !empty($hcard['note'][0])) { -// $hints['bio'] = $hcard['note'][0]; -// } -// -// if (array_key_exists('adr', $hcard) && !empty($hcard['adr'][0])) { -// $hints['location'] = $hcard['adr'][0]['value']; -// } -// -// if (array_key_exists('url', $hcard) && !empty($hcard['url'][0])) { -// $hints['homepage'] = $hcard['url'][0]; -// } -// -// return $hints; -// } -// -// private static function hcard($body, $url) -// { -// $mf2 = new Mf2\Parser($body, $url); -// $mf2 = $mf2->parse(); -// -// if (empty($mf2['items'])) { -// return null; -// } -// -// $hcards = []; -// -// foreach ($mf2['items'] as $item) { -// if (!in_array('h-card', $item['type'])) { -// continue; -// } -// -// // We found a match, return it immediately -// if (isset($item['properties']['url']) && in_array($url, $item['properties']['url'])) { -// return $item['properties']; -// } -// -// // Let's keep all the hcards for later, to return one of them at least -// $hcards[] = $item['properties']; -// } -// -// // No match immediately for the url we expected, but there were h-cards found -// if (count($hcards) > 0) { -// return $hcards[0]; -// } -// -// return null; -// } -//} +} \ No newline at end of file diff --git a/plugins/ActivityPub/Util/Explorer.php b/plugins/ActivityPub/Util/Explorer.php index f0bae30f7f..b9e235fde1 100644 --- a/plugins/ActivityPub/Util/Explorer.php +++ b/plugins/ActivityPub/Util/Explorer.php @@ -1,7 +1,8 @@ . - -namespace Plugin\ActivityPub\Util; - -use App\Core\DB\DB; -use App\Core\HTTPClient; -use App\Core\Log; -use App\Core\Security; -use App\Entity\Actor; -use App\Util\Exception\NoSuchActorException; -use App\Util\Formatting; -use DateTime; -use Exception; -use Plugin\ActivityPub\ActivityPub; -use Plugin\ActivityPub\Entity\ActivitypubActor; -use Plugin\ActivityPub\Entity\ActivitypubRsa; -use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; -use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; -use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; -use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +// }}} /** * ActivityPub implementation for GNU social * * @package GNUsocial - * + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later - * - * @see http://www.gnu.org/software/social/ */ +namespace Plugin\ActivityPub\Util; + +use App\Core\HTTPClient; +use App\Core\Log; +use App\Util\Exception\NoSuchActorException; +use Exception; +use Plugin\ActivityPub\ActivityPub; +use Plugin\ActivityPub\Entity\ActivitypubActor; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use function in_array; +use function is_null; +use const JSON_UNESCAPED_SLASHES; + /** * ActivityPub's own Explorer * * Allows to discovery new remote actors * - * @author Diogo Peralta Cordeiro (@diogo.site) - * - * @category Plugin - * @package GNUsocial - * - * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ class Explorer { - private $discovered_actor_profiles = []; + private array $discovered_actor_profiles = []; /** * Shortcut function to get a single profile from its URL. * + * @param string $url * @param bool $grab_online whether to try online grabbing, defaults to true * + * @return ActivitypubActor * @throws ClientExceptionInterface * @throws NoSuchActorException * @throws RedirectionExceptionInterface * @throws ServerExceptionInterface * @throws TransportExceptionInterface - * - * @return Actor */ public static function get_profile_from_url(string $url, bool $grab_online = true): ActivitypubActor { @@ -92,8 +86,8 @@ class Explorer * This function cleans the $this->discovered_actor_profiles array * so that there is no erroneous data * - * @param string $url User's url - * @param bool $grab_online whether to try online grabbing, defaults to true + * @param string $url User's url + * @param bool $grab_online whether to try online grabbing, defaults to true * * @throws ClientExceptionInterface * @throws NoSuchActorException @@ -101,11 +95,11 @@ class Explorer * @throws ServerExceptionInterface * @throws TransportExceptionInterface * - * @return array of Profile objects + * @return array of Actor objects */ public function lookup(string $url, bool $grab_online = true) { - if (\in_array($url, ActivityPub::PUBLIC_TO)) { + if (in_array($url, ActivityPub::PUBLIC_TO)) { return []; } @@ -120,8 +114,8 @@ class Explorer * This is a recursive function that will accumulate the results on * $discovered_actor_profiles array * - * @param string $url User's url - * @param bool $grab_online whether to try online grabbing, defaults to true + * @param string $url User's url + * @param bool $grab_online whether to try online grabbing, defaults to true * * @throws ClientExceptionInterface * @throws NoSuchActorException @@ -193,95 +187,38 @@ class Explorer { Log::debug('ActivityPub Explorer: Trying to grab a remote actor for ' . $url); $response = HTTPClient::get($url, ['headers' => ACTIVITYPUB::HTTP_CLIENT_HEADERS]); - $res = json_decode($response->getContent(), true); + $res = json_decode($response->getContent(), true); if ($response->getStatusCode() == 410) { // If it was deleted return true; // Nothing to add. } elseif (!HTTPClient::statusCodeIsOkay($response)) { // If it is unavailable return false; // Try to add at another time. } - if (\is_null($res)) { - Log::debug('ActivityPub Explorer: Invalid JSON returned from given Actor URL: ' . $response->getContent()); + if (is_null($res)) { + Log::debug('ActivityPub Explorer: Invalid response returned from given Actor URL: ' . $res); return true; // Nothing to add. } - if (isset($res['type']) && $res['type'] === 'OrderedCollection' && isset($res['first'])) { // It's a potential collection of actors!!! + if ($res['type'] === 'OrderedCollection') { // It's a potential collection of actors!!! Log::debug('ActivityPub Explorer: Found a collection of actors for ' . $url); $this->travel_collection($res['first']); return true; - } elseif (self::validate_remote_response($res)) { - Log::debug('ActivityPub Explorer: Found a valid remote actor for ' . $url); - $this->discovered_actor_profiles[] = $this->store_profile($res); - return true; } else { - Log::debug('ActivityPub Explorer: Invalid potential remote actor while grabbing remotely: ' . $url . '. He returned the following: ' . json_encode($res, \JSON_UNESCAPED_SLASHES)); - return false; + try { + $this->discovered_actor_profiles[] = Model\Actor::fromJson(json_encode($res)); + return true; + } catch (Exception $e) { + Log::debug( + 'ActivityPub Explorer: Invalid potential remote actor while grabbing remotely: ' . $url + . '. He returned the following: ' . json_encode($res, JSON_UNESCAPED_SLASHES) + . ' and the following exception: ' . $e->getMessage() + ); + return false; + } } return false; } - /** - * Save remote user profile in known instance - * - * @param array $res remote response - * - * @throws Exception - * @throws NoSuchActorException - * - * @return Actor remote Profile object - */ - private function store_profile(array $res): ActivitypubActor - { - // Actor - $actor_map = [ - 'nickname' => $res['preferredUsername'], - 'fullname' => $res['name'] ?? null, - 'created' => new DateTime($res['published'] ?? 'now'), - 'bio' => isset($res['summary']) ? mb_substr(Security::sanitize($res['summary']), 0, 1000) : null, - 'is_local' => false, - 'modified' => new DateTime(), - ]; - - $actor = new Actor(); - foreach ($actor_map as $prop => $val) { - $set = Formatting::snakeCaseToCamelCase("set_{$prop}"); - $actor->{$set}($val); - } - - DB::persist($actor); - - // ActivityPub Actor - $aprofile = ActivitypubActor::create([ - 'inbox_uri' => $res['inbox'], - 'inbox_shared_uri' => $res['endpoints']['sharedInbox'], - 'uri' => $res['id'], - 'actor_id' => $actor->getId(), - 'url' => $res['url'] ?? null, - ]); - - DB::persist($aprofile); - - // Public Key - $apRSA = ActivitypubRsa::create([ - 'actor_id' => $actor->getID(), - 'public_key' => $res['publicKey']['publicKeyPem'], - ]); - - DB::persist($apRSA); - - // Avatar - //if (isset($res['icon']['url'])) { - // try { - // $this->update_avatar($profile, $res['icon']['url']); - // } catch (Exception $e) { - // // Let the exception go, it isn't a serious issue - // Log::debug('ActivityPub Explorer: An error ocurred while grabbing remote avatar: ' . $e->getMessage()); - // } - //} - - return $aprofile; - } - /** * Validates a remote response in order to determine whether this * response is a valid profile or not @@ -305,18 +242,24 @@ class Explorer public static function get_aprofile_by_url(string $v): ActivitypubActor|bool { $aprofile = ActivitypubActor::getWithPK(['uri' => $v]); - return \is_null($aprofile) ? false : ActivitypubActor::getWithPK(['uri' => $v]); + return is_null($aprofile) ? false : ActivitypubActor::getWithPK(['uri' => $v]); } /** * Allows the Explorer to transverse a collection of persons. * + * @param string $url + * @return bool + * @throws ClientExceptionInterface * @throws NoSuchActorException + * @throws RedirectionExceptionInterface + * @throws ServerExceptionInterface + * @throws TransportExceptionInterface */ private function travel_collection(string $url): bool { $response = HTTPClient::get($url, ['headers' => ACTIVITYPUB::HTTP_CLIENT_HEADERS]); - $res = json_decode($response->getContent(), true); + $res = json_decode($response->getContent(), true); if (!isset($res['orderedItems'])) { return false; @@ -328,7 +271,7 @@ class Explorer } } // Go through entire collection - if (!\is_null($res['next'])) { + if (!is_null($res['next'])) { $this->travel_collection($res['next']); } @@ -359,7 +302,7 @@ class Explorer throw new Exception('Non Ok Status Code for given Actor URL.'); } $res = json_decode($response->getContent(), true); - if (\is_null($res)) { + if (is_null($res)) { Log::debug('ActivityPub Explorer: Invalid JSON returned from given Actor URL: ' . $response->getContent()); throw new Exception('Given Actor URL didn\'t return a valid JSON.'); } diff --git a/plugins/ActivityPub/Util/HTTPSignature.php b/plugins/ActivityPub/Util/HTTPSignature.php index 8cbd37f321..9a358648f4 100644 --- a/plugins/ActivityPub/Util/HTTPSignature.php +++ b/plugins/ActivityPub/Util/HTTPSignature.php @@ -64,7 +64,7 @@ class HTTPSignature } /** - * @param array|string array or json string $body + * @param array|string $body array or json string $body * @return string */ private static function _digest(array|string $body): string diff --git a/plugins/ActivityPub/Util/Model.php b/plugins/ActivityPub/Util/Model.php new file mode 100644 index 0000000000..327309b9f3 --- /dev/null +++ b/plugins/ActivityPub/Util/Model.php @@ -0,0 +1,143 @@ +. +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + +namespace Plugin\ActivityPub\Util; + +use ActivityPhp\Type; +use ActivityPhp\Type\TypeConfiguration; +use ActivityPhp\Type\TypeResolver; +use App\Core\Entity; +use App\Core\Event; +use App\Util\Exception\ClientException; +use Exception; +use InvalidArgumentException; +use Plugin\ActivityPub\Util\Model\Activity; +use Plugin\ActivityPub\Util\Model\Note; + +/** + * This class handles translation between JSON and GS Entities + * + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +abstract class Model +{ + /** + * Create a Type from an ActivityStreams 2.0 JSON string + * + * @param string|array $data + * @return Type\AbstractObject + * @throws Exception + */ + public static function jsonToType(string|array $data): Type\AbstractObject + { + if (is_string($data)) { + $attributes = json_decode($data, true); + if (json_last_error() !== JSON_ERROR_NONE + || !is_array($attributes) + ) { + throw new Exception( + sprintf( + "An error occurred during the JSON decoding.\n '%s'", + $data + ) + ); + } + } else { + $attributes = $data; + } + + if (!array_key_exists('type', $attributes)) { + throw new InvalidArgumentException('Missing "type" attribute in $data: ' . var_export($data, true)); + } + unset($data); + + try { + $type = TypeResolver::getClass($attributes['type']); + } catch (Exception $e) { + $message = json_encode($attributes, JSON_PRETTY_PRINT); + throw new Exception( + $e->getMessage() . "\n$message" + ); + } + + if (is_string($type)) { + $type = new $type(); + } + + // Add our own extensions + $validators = []; + if (Event::handle('ActivityPubValidateActivityStreamsTwoData', [$attributes['type'], &$validators]) === Event::next) { + foreach ($validators as $name => $class) { + Type::addValidator($name, $class); + $type->extend($name); + } + } + + TypeConfiguration::set('undefined_properties', 'include'); + foreach ($attributes as $name => $value) { + $type->set($name, $value); + } + + return $type; + } + + /** + * Create an Entity from an ActivityStreams 2.0 JSON string + * + * @param string|Type\AbstractObject $json + * @param array $options + * @return Entity + */ + abstract public static function fromJson(string|Type\AbstractObject $json, array $options = []): Entity; + + /** + * Get a JSON + * + * @param mixed $object + * @param ?int $options PHP JSON options + * @return string + * @throws ClientException + */ + public static function toJson(mixed $object, int $options = null): string + { + switch ($object::class) { + case 'App\Entity\Activity': + return Activity::toJson($object, $options); + case 'App\Entity\Note': + return Note::toJson($object, $options); + default: + $type = self::jsonToType($object); + Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]); + return $type->toJson($options); + } + } +} \ No newline at end of file diff --git a/plugins/ActivityPub/Util/Model/AS2ToEntity/AS2ToEntity.php b/plugins/ActivityPub/Util/Model/AS2ToEntity/AS2ToEntity.php deleted file mode 100644 index 3692723f3c..0000000000 --- a/plugins/ActivityPub/Util/Model/AS2ToEntity/AS2ToEntity.php +++ /dev/null @@ -1,82 +0,0 @@ - 'create', - default => throw new ClientException('Invalid verb'), - }; - } - - public static function activity_stream_two_object_type_to_gs_table(string $object): string - { - return match ($object) { - 'Note' => 'note', - default => throw new ClientException('Invalid verb'), - }; - } - - /** - * @throws ClientException - */ - public static function store(array $activity, ?string $source = null): ActivitypubActivity - { - $ap_act = ActivitypubActivity::getWithPK(['activity_uri' => $activity['id']]); - if (\is_null($ap_act)) { - $actor = ActivityPub::getActorByUri($activity['actor']); - // Store Object - $obj = null; - switch ($activity['object']['type']) { - case 'Note': - $obj = AS2ToNote::translate($activity['object'], $source, $activity['actor'], $actor->getId()); - break; - default: - if (!Event::handle('ActivityPubObject', [$activity['object']['type'], $activity['object'], &$obj])) { - throw new ClientException('Unsupported Object type.'); - } - break; - } - DB::persist($obj); - // Store Activity - $act = Activity::create([ - 'actor_id' => $actor->getId(), - 'verb' => self::activity_stream_two_verb_to_gs_verb($activity['type']), - 'object_type' => self::activity_stream_two_object_type_to_gs_table($activity['object']['type']), - 'object_id' => $obj->getId(), - 'is_local' => false, - 'created' => new DateTime($activity['published'] ?? 'now'), - 'source' => $source, - ]); - DB::persist($act); - // Store ActivityPub Activity - $ap_act = ActivitypubActivity::create([ - 'activity_id' => $act->getId(), - 'activity_uri' => $activity['id'], - 'object_uri' => $activity['object']['id'], - 'is_local' => false, - 'created' => new DateTime($activity['published'] ?? 'now'), - 'modified' => new DateTime(), - ]); - DB::persist($ap_act); - } - - return $ap_act; - } -} diff --git a/plugins/ActivityPub/Util/Model/AS2ToEntity/AS2ToNote.php b/plugins/ActivityPub/Util/Model/AS2ToEntity/AS2ToNote.php deleted file mode 100644 index af24d89328..0000000000 --- a/plugins/ActivityPub/Util/Model/AS2ToEntity/AS2ToNote.php +++ /dev/null @@ -1,67 +0,0 @@ -getId(); - } - $map = [ - 'is_local' => false, - 'created' => new DateTime($object['published'] ?? 'now'), - 'content' => $object['content'] ?? null, - 'content_type' => 'text/html', - 'language_id' => $object['contentLang'] ?? null, - 'url' => \array_key_exists('url', $object) ? $object['url'] : $object['id'], - 'actor_id' => $actor_id, - 'modified' => new DateTime(), - 'source' => $source, - ]; - if ($map['content'] !== null) { - $mentions = []; - Event::handle('RenderNoteContent', [ - $map['content'], - $map['content_type'], - &$map['rendered'], - Actor::getById($actor_id), - $map['language_id'], - &$mentions, - ]); - } - - $obj = new Note(); - - if (!is_null($map['language_id'])) { - $map['language_id'] = Language::getFromLocale($map['language_id'])->getId(); - } else { - $map['language_id'] = null; - } - - foreach ($map as $prop => $val) { - $set = Formatting::snakeCaseToCamelCase("set_{$prop}"); - $obj->{$set}($val); - } - - Event::handle('NewNoteFromActivityStreamsTwo', [$source, $obj, $actor_id]); - - return $obj; - } -} diff --git a/plugins/ActivityPub/Util/Model/Activity.php b/plugins/ActivityPub/Util/Model/Activity.php new file mode 100644 index 0000000000..d2272cd84e --- /dev/null +++ b/plugins/ActivityPub/Util/Model/Activity.php @@ -0,0 +1,160 @@ +. +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + +namespace Plugin\ActivityPub\Util\Model; + +use ActivityPhp\Type\AbstractObject; +use App\Core\DB\DB; +use App\Core\Event; +use App\Core\Router\Router; +use App\Entity\Activity as GSActivity; +use App\Util\Exception\ClientException; +use App\Util\Exception\NoSuchActorException; +use DateTime; +use DateTimeInterface; +use InvalidArgumentException; +use Plugin\ActivityPub\ActivityPub; +use Plugin\ActivityPub\Entity\ActivitypubActivity; +use Plugin\ActivityPub\Util\Model; + +/** + * This class handles translation between JSON and ActivityPub Activities + * + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +class Activity extends Model +{ + /** + * Create an Entity from an ActivityStreams 2.0 JSON string + * This will persist new GSActivities, GSObjects, and APActivity + * + * @param string|AbstractObject $json + * @param array $options + * @return ActivitypubActivity + * @throws ClientException + * @throws NoSuchActorException + */ + public static function fromJson(string|AbstractObject $json, array $options = []): ActivitypubActivity + { + $type_activity = is_string($json) ? self::jsonToType($json) : $json; + + $activity_stream_two_verb_to_gs_verb = fn(string $verb): string => match ($verb) { + 'Create' => 'create', + default => throw new ClientException('Invalid verb'), + }; + + $activity_stream_two_object_type_to_gs_table = fn(string $object): string => match ($object) { + 'Note' => 'note', + default => throw new ClientException('Invalid verb'), + }; + + $ap_act = ActivitypubActivity::getWithPK(['activity_uri' => $type_activity->get('id')]); + if (is_null($ap_act)) { + $actor = ActivityPub::getActorByUri($type_activity->get('actor')); + // Store Object + $obj = null; + if (!$type_activity->has('object') || !isset($type_activity->get('object')['type'])) { + throw new InvalidArgumentException('Activity Object or Activity Object Type is missing.'); + } + switch ($type_activity->get('object')['type']) { + case 'Note': + $obj = Note::toJson($type_activity->get('object'), ['source' => $source, 'actor_uri' => $type_activity->get('actor'), 'actor_id' => $actor->getId()]); + break; + default: + if (!Event::handle('ActivityPubObject', [$type_activity->get('object')['type'], $type_activity->get('object'), &$obj])) { + throw new ClientException('Unsupported Object type.'); + } + break; + } + DB::persist($obj); + // Store Activity + $act = GSActivity::create([ + 'actor_id' => $actor->getId(), + 'verb' => $activity_stream_two_verb_to_gs_verb($type_activity->get('type')), + 'object_type' => $activity_stream_two_object_type_to_gs_table($type_activity->get('object')['type']), + 'object_id' => $obj->getId(), + 'is_local' => false, + 'created' => new DateTime($activity['published'] ?? 'now'), + 'source' => $source, + ]); + DB::persist($act); + // Store ActivityPub Activity + $ap_act = ActivitypubActivity::create([ + 'activity_id' => $act->getId(), + 'activity_uri' => $activity['id'], + 'object_uri' => $activity['object']['id'], + 'is_local' => false, + 'created' => new DateTime($activity['published'] ?? 'now'), + 'modified' => new DateTime(), + ]); + DB::persist($ap_act); + } + + Event::handle('ActivityPubNewActivity', [&$ap_act, &$act, &$obj]); + return $ap_act; + } + + /** + * Get a JSON + * + * @param mixed $object + * @param int|null $options + * @return string + * @throws ClientException + */ + public static function toJson(mixed $object, ?int $options = null): string + { + if ($object::class !== 'App\Entity\Activity') { + throw new InvalidArgumentException('First argument type is Activity'); + } + + $gs_verb_to_activity_stream_two_verb = fn($verb): string => match ($verb) { + 'create' => 'Create', + default => throw new ClientException('Invalid verb'), + }; + + $attr = [ + 'type' => $gs_verb_to_activity_stream_two_verb($object->getVerb()), + '@context' => 'https://www.w3.org/ns/activitystreams', + 'id' => Router::url('activity_view', ['id' => $object->getId()], Router::ABSOLUTE_URL), + 'published' => $object->getCreated()->format(DateTimeInterface::RFC3339), + 'actor' => $object->getActor()->getUri(Router::ABSOLUTE_URL), + 'to' => ['https://www.w3.org/ns/activitystreams#Public'], // TODO: implement proper scope address + 'cc' => ['https://www.w3.org/ns/activitystreams#Public'], + 'object' => self::jsonToType(self::toJson($object->getObject())), + ]; + + $type = self::jsonToType($attr); + Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]); + return $type->toJson($options); + } +} \ No newline at end of file diff --git a/plugins/ActivityPub/Util/Model/Actor.php b/plugins/ActivityPub/Util/Model/Actor.php new file mode 100644 index 0000000000..01a99c9a8b --- /dev/null +++ b/plugins/ActivityPub/Util/Model/Actor.php @@ -0,0 +1,174 @@ +. +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + +namespace Plugin\ActivityPub\Util\Model; + +use ActivityPhp\Type\AbstractObject; +use App\Core\DB\DB; +use App\Core\Event; +use App\Core\Router\Router; +use App\Core\Security; +use App\Entity\Actor as GSActor; +use App\Util\Exception\ServerException; +use App\Util\Formatting; +use Component\Avatar\Avatar; +use Component\Avatar\Exception\NoAvatarException; +use DateTime; +use DateTimeInterface; +use Exception; +use InvalidArgumentException; +use Plugin\ActivityPub\Entity\ActivitypubActor; +use Plugin\ActivityPub\Entity\ActivitypubRsa; +use Plugin\ActivityPub\Util\Model; + +/** + * This class handles translation between JSON and GSActors + * + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +class Actor extends Model +{ + + /** + * Create an Entity from an ActivityStreams 2.0 JSON string + * This will persist a new GSActor, ActivityPubRSA, and ActivityPubActor + * + * @param string|AbstractObject $json + * @param array $options + * @return GSActor + * @throws Exception + */ + public static function fromJson(string|AbstractObject $json, array $options = []): GSActor + { + $person = is_string($json) ? self::jsonToType($json) : $json; + + // Actor + $actor_map = [ + 'nickname' => $person->get('preferredUsername'), + 'fullname' => $person->get('name'), + 'created' => new DateTime($person->get('published') ?? 'now'), + 'bio' => $person->has('summary') ? mb_substr(Security::sanitize($person->get('summary')), 0, 1000) : null, + 'is_local' => false, + 'modified' => new DateTime(), + ]; + + $actor = new GSActor(); + foreach ($actor_map as $prop => $val) { + $set = Formatting::snakeCaseToCamelCase("set_{$prop}"); + $actor->{$set}($val); + } + + DB::persist($actor); + + // ActivityPub Actor + $aprofile = ActivitypubActor::create([ + 'inbox_uri' => $person->get('inbox'), + 'inbox_shared_uri' => ($person->has('endpoints') && isset($person->get('endpoints')['sharedInbox'])) ? $person->get('endpoints')['sharedInbox'] : null, + 'uri' => $person->get('id'), + 'actor_id' => $actor->getId(), + 'url' => $person->get('url') ?? null, + ]); + + DB::persist($aprofile); + + // Public Key + $apRSA = ActivitypubRsa::create([ + 'actor_id' => $actor->getID(), + 'public_key' => ($person->has('publicKey') && isset($person->get('publicKey')['publicKeyPem'])) ? $person->get('publicKey')['publicKeyPem'] : null, + ]); + + DB::persist($apRSA); + + // Avatar + //if (isset($res['icon']['url'])) { + // try { + // $this->update_avatar($profile, $res['icon']['url']); + // } catch (Exception $e) { + // // Let the exception go, it isn't a serious issue + // Log::debug('ActivityPub Explorer: An error occurred while grabbing remote avatar: ' . $e->getMessage()); + // } + //} + + Event::handle('ActivityPubNewActor', [&$aprofile, &$actor, &$apRSA]); + return $aprofile; + } + + /** + * Get a JSON + * + * @param mixed $object + * @param int|null $options PHP JSON options + * @return string + * @throws ServerException + */ + public static function toJson(mixed $object, ?int $options = null): string + { + if ($object::class !== 'App\Entity\Actor') { + throw new InvalidArgumentException('First argument type is Actor'); + } + $rsa = ActivitypubRsa::getByActor($object); + $public_key = $rsa->getPublicKey(); + $uri = null; + $attr = [ + '@context' => 'https://www.w3.org/ns/activitystreams', + 'type' => 'Person', + 'id' => $object->getUri(Router::ABSOLUTE_URL), + 'inbox' => Router::url('activitypub_actor_inbox', ['gsactor_id' => $object->getId()], Router::ABSOLUTE_URL), + 'outbox' => Router::url('activitypub_actor_outbox', ['gsactor_id' => $object->getId()], Router::ABSOLUTE_URL), + 'following' => Router::url('actor_subscriptions_id', ['id' => $object->getId()], Router::ABSOLUTE_URL), + 'followers' => Router::url('actor_subscribers_id', ['id' => $object->getId()], Router::ABSOLUTE_URL), + 'liked' => Router::url('favourites_view_by_actor_id', ['id' => $object->getId()], Router::ABSOLUTE_URL), + //'streams' => + 'preferredUsername' => $object->getNickname(), + 'publicKey' => [ + 'id' => $uri . "#public-key", + 'owner' => $uri, + 'publicKeyPem' => $public_key + ], + 'name' => $object->getFullname(), + 'location' => $object->getLocation(), + 'published' => $object->getCreated()->format(DateTimeInterface::RFC3339), + 'summary' => $object->getBio(), + //'tag' => $object->getSelfTags(), + 'updated' => $object->getModified()->format(DateTimeInterface::RFC3339), + 'url' => $object->getUrl(Router::ABSOLUTE_URL), + ]; + try { + $attr['icon'] = Avatar::getAvatar($object->getId())->getUrl(type: Router::ABSOLUTE_URL); + } catch (NoAvatarException) { + // No icon for this actor + } + + $type = self::jsonToType($attr); + return $type->toJson($options); + } +} \ No newline at end of file diff --git a/plugins/ActivityPub/Util/Model/EntityToType/ActivityToType.php b/plugins/ActivityPub/Util/Model/EntityToType/ActivityToType.php deleted file mode 100644 index 3d2c9d3f0f..0000000000 --- a/plugins/ActivityPub/Util/Model/EntityToType/ActivityToType.php +++ /dev/null @@ -1,41 +0,0 @@ - 'Create', - default => throw new ClientException('Invalid verb'), - }; - } - - /** - * @throws Exception - */ - public static function translate(Activity $activity): Type\Core\Activity - { - $attr = [ - 'type' => self::gs_verb_to_activity_stream_two_verb($activity->getVerb()), - '@context' => 'https://www.w3.org/ns/activitystreams', - 'id' => Router::url('activity_view', ['id' => $activity->getId()], Router::ABSOLUTE_URL), - 'published' => $activity->getCreated()->format(DateTimeInterface::RFC3339), - 'actor' => $activity->getActor()->getUri(Router::ABSOLUTE_URL), - 'to' => ['https://www.w3.org/ns/activitystreams#Public'], // TODO: implement proper scope address - 'cc' => ['https://www.w3.org/ns/activitystreams#Public'], - 'object' => EntityToType::translate($activity->getObject()), - ]; - return Type::create($attr); - } -} diff --git a/plugins/ActivityPub/Util/Model/EntityToType/EntityToType.php b/plugins/ActivityPub/Util/Model/EntityToType/EntityToType.php deleted file mode 100644 index df4f53cc8b..0000000000 --- a/plugins/ActivityPub/Util/Model/EntityToType/EntityToType.php +++ /dev/null @@ -1,31 +0,0 @@ - 'Object', - ]; - return Type::create($map); - } - } -} diff --git a/plugins/ActivityPub/Util/Model/EntityToType/GSActorToType.php b/plugins/ActivityPub/Util/Model/EntityToType/GSActorToType.php deleted file mode 100644 index a6fab9da07..0000000000 --- a/plugins/ActivityPub/Util/Model/EntityToType/GSActorToType.php +++ /dev/null @@ -1,58 +0,0 @@ -getPublicKey(); - $uri = null; - $attr = [ - '@context' => 'https://www.w3.org/ns/activitystreams', - 'id' => $gsactor->getUri(Router::ABSOLUTE_URL), - 'inbox' => Router::url('activitypub_actor_inbox', ['gsactor_id' => $gsactor->getId()], Router::ABSOLUTE_URL), - 'outbox' => Router::url('activitypub_actor_outbox', ['gsactor_id' => $gsactor->getId()], Router::ABSOLUTE_URL), - 'following' => Router::url('actor_subscriptions_id', ['id' => $gsactor->getId()], Router::ABSOLUTE_URL), - 'followers' => Router::url('actor_subscribers_id', ['id' => $gsactor->getId()], Router::ABSOLUTE_URL), - 'liked' => Router::url('favourites_view_by_actor_id', ['id' => $gsactor->getId()], Router::ABSOLUTE_URL), - //'streams' => - 'preferredUsername' => $gsactor->getNickname(), - 'publicKey' => [ - 'id' => $uri . "#public-key", - 'owner' => $uri, - 'publicKeyPem' => $public_key - ], - 'name' => $gsactor->getFullname(), - 'location' => $gsactor->getLocation(), - 'published' => $gsactor->getCreated()->format(DateTimeInterface::RFC3339), - 'summary' => $gsactor->getBio(), - //'tag' => $gsactor->getSelfTags(), - 'updated' => $gsactor->getModified()->format(DateTimeInterface::RFC3339), - 'url' => $gsactor->getUrl(Router::ABSOLUTE_URL), - ]; - try { - $attr['icon'] = Avatar::getAvatar($gsactor->getId())->getUrl(type: Router::ABSOLUTE_URL); - } catch (NoAvatarException) { - // No icon for this actor - } - - return Type::create(type: 'Person', attributes: $attr); - } -} diff --git a/plugins/ActivityPub/Util/Model/EntityToType/NoteToType.php b/plugins/ActivityPub/Util/Model/EntityToType/NoteToType.php deleted file mode 100644 index aabc70d1cd..0000000000 --- a/plugins/ActivityPub/Util/Model/EntityToType/NoteToType.php +++ /dev/null @@ -1,32 +0,0 @@ - 'https://www.w3.org/ns/activitystreams', - 'id' => Router::url('note_view', ['id' => $note->getId()], Router::ABSOLUTE_URL), - 'published' => $note->getCreated()->format(DateTimeInterface::RFC3339), - 'attributedTo' => $note->getActor()->getUri(Router::ABSOLUTE_URL), - 'to' => ['https://www.w3.org/ns/activitystreams#Public'], // TODO: implement proper scope address - 'cc' => ['https://www.w3.org/ns/activitystreams#Public'], - 'content' => $note->getRendered(), - //'tag' => $tags - ]; - return Type::create(type: 'Note', attributes: $attr); - } -} diff --git a/plugins/ActivityPub/Util/Model/Note.php b/plugins/ActivityPub/Util/Model/Note.php new file mode 100644 index 0000000000..61a7f4df4f --- /dev/null +++ b/plugins/ActivityPub/Util/Model/Note.php @@ -0,0 +1,145 @@ +. +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + +namespace Plugin\ActivityPub\Util\Model; + +use ActivityPhp\Type\AbstractObject; +use App\Core\Event; +use App\Core\Router\Router; +use App\Entity\Actor; +use App\Entity\Language; +use App\Entity\Note as GSNote; +use App\Util\Formatting; +use DateTime; +use DateTimeInterface; +use Exception; +use InvalidArgumentException; +use Plugin\ActivityPub\ActivityPub; +use Plugin\ActivityPub\Util\Model; + +/** + * This class handles translation between JSON and GSNotes + * + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +class Note extends Model +{ + + /** + * Create an Entity from an ActivityStreams 2.0 JSON string + * This will persist a new GSNote + * + * @param string|AbstractObject $json + * @param array $options + * @return GSNote + * @throws Exception + */ + public static function fromJson(string|AbstractObject $json, array $options = []): GSNote + { + $source = $options['source']; + $actor_uri = $options['actor_uri']; + $actor_id = $options['actor_id']; + $type_note = is_string($json) ? self::jsonToType($json) : $json; + + if (is_null($actor_uri) || $actor_uri !== $type_note->get('attributedTo')) { + $actor_id = ActivityPub::getActorByUri($type_note->get('attributedTo'))->getId(); + } + $map = [ + 'is_local' => false, + 'created' => new DateTime($type_note->get('published') ?? 'now'), + 'content' => $type_note->get('content') ?? null, + 'content_type' => 'text/html', + 'language_id' => $type_note->get('contentLang') ?? null, + 'url' => $type_note->get('url') ?? $type_note->get('id'), + 'actor_id' => $actor_id, + 'modified' => new DateTime(), + 'source' => $source, + ]; + if ($map['content'] !== null) { + $mentions = []; + Event::handle('RenderNoteContent', [ + $map['content'], + $map['content_type'], + &$map['rendered'], + Actor::getById($actor_id), + $map['language_id'], + &$mentions, + ]); + } + + $obj = new GSNote(); + + if (!is_null($map['language_id'])) { + $map['language_id'] = Language::getFromLocale($map['language_id'])->getId(); + } else { + $map['language_id'] = null; + } + + foreach ($map as $prop => $val) { + $set = Formatting::snakeCaseToCamelCase("set_{$prop}"); + $obj->{$set}($val); + } + + Event::handle('ActivityPubNewNote', [&$obj]); + return $obj; + } + + /** + * Get a JSON + * + * @param mixed $object + * @param int|null $options + * @return string + * @throws Exception + */ + public static function toJson(mixed $object, ?int $options = null): string + { + if ($object::class !== 'App\Entity\Note') { + throw new InvalidArgumentException('First argument type is Note'); + } + + $attr = [ + '@context' => 'https://www.w3.org/ns/activitystreams', + 'id' => Router::url('note_view', ['id' => $object->getId()], Router::ABSOLUTE_URL), + 'published' => $object->getCreated()->format(DateTimeInterface::RFC3339), + 'attributedTo' => $object->getActor()->getUri(Router::ABSOLUTE_URL), + 'to' => ['https://www.w3.org/ns/activitystreams#Public'], // TODO: implement proper scope address + 'cc' => ['https://www.w3.org/ns/activitystreams#Public'], + 'content' => $object->getRendered(), + //'tag' => $tags + ]; + + $type = self::jsonToType($attr); + Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]); + return $type->toJson($options); + } +} \ No newline at end of file diff --git a/plugins/ActivityPub/Util/ModelResponse.php b/plugins/ActivityPub/Util/ModelResponse.php new file mode 100644 index 0000000000..13b9e61870 --- /dev/null +++ b/plugins/ActivityPub/Util/ModelResponse.php @@ -0,0 +1,56 @@ +. +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + +namespace Plugin\ActivityPub\Util; + +/** + * Provides a response in application/ld+json to GS Entities + * + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +abstract class ModelResponse +{ + /** + * Provides a response in application/ld+json for ActivityStreams 2.0 Types + * + * @param mixed $object (Entity) + * @param int $status The response status code + * @return TypeResponse + */ + public static function handle(mixed $object, int $status = 200): TypeResponse + { + return new TypeResponse( + json: Model::toJson($object), + status: $status, + ); + } +} diff --git a/plugins/ActivityPub/Util/ModelValidator.php b/plugins/ActivityPub/Util/ModelValidator.php new file mode 100644 index 0000000000..cc308e872b --- /dev/null +++ b/plugins/ActivityPub/Util/ModelValidator.php @@ -0,0 +1,50 @@ +. +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + +namespace Plugin\ActivityPub\Util; + +use ActivityPhp\Type\ValidatorInterface; +use ActivityPhp\Type\ValidatorTools; + +/** + * \Plugin\ActivityPub\Util\ModelValidator is an abstract class for + * attribute validation. + * Its purpose is to be extended by Plugin\ActivityPub\Util\Validator\* + * classes. + * It provides some methods to make some regular validations. + * It implements \ActivityPhp\Type\ValidatorInterface. + * + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +abstract class ModelValidator extends ValidatorTools implements ValidatorInterface +{ +} diff --git a/plugins/ActivityPub/Util/Response/AbstractResponse.php b/plugins/ActivityPub/Util/Response/AbstractResponse.php deleted file mode 100644 index b3c9f18913..0000000000 --- a/plugins/ActivityPub/Util/Response/AbstractResponse.php +++ /dev/null @@ -1,26 +0,0 @@ -. +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + +namespace Plugin\ActivityPub\Util\Response; + +use App\Entity\Activity as GSActivity; +use App\Util\Exception\ClientException; +use Plugin\ActivityPub\Util\Model\Activity as ModelActivity; +use Plugin\ActivityPub\Util\TypeResponse; + +/** + * Provides a response in application/ld+json to GSActivity + * + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +abstract class ActivityResponse +{ + /** + * Provides a response in application/ld+json to GSActivity + * + * @param GSActivity $activity + * @param int $status The response status code + * @return TypeResponse + * @throws ClientException + */ + public static function handle(GSActivity $activity, int $status = 200): TypeResponse + { + return new TypeResponse(json: ModelActivity::toJson($activity), status: $status); + } +} diff --git a/plugins/ActivityPub/Util/Response/ActorResponse.php b/plugins/ActivityPub/Util/Response/ActorResponse.php index 625178747b..06c1d920ef 100644 --- a/plugins/ActivityPub/Util/Response/ActorResponse.php +++ b/plugins/ActivityPub/Util/Response/ActorResponse.php @@ -1,25 +1,61 @@ . +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ namespace Plugin\ActivityPub\Util\Response; -use App\Entity\Actor; +use App\Entity\Actor as GSActor; use App\Util\Exception\ClientException; -use Exception; -use Plugin\ActivityPub\Util\Model\EntityToType\GSActorToType; +use Plugin\ActivityPub\Util\Model\Actor as ModelActor; +use Plugin\ActivityPub\Util\TypeResponse; +/** + * Provides a response in application/ld+json to GSActors + * + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ abstract class ActorResponse { /** - * @param int $status The response status code + * Provides a response in application/ld+json to GSActors * - *@throws Exception + * @param GSActor $gsactor + * @param int $status The response status code + * @return TypeResponse + * @throws ClientException */ - public static function handle(Actor $gsactor, int $status = 200): TypeResponse + public static function handle(GSActor $gsactor, int $status = 200): TypeResponse { if ($gsactor->getIsLocal()) { - return new TypeResponse(data: GSActorToType::translate($gsactor), status: $status); + return new TypeResponse(json: ModelActor::toJson($gsactor), status: $status); } else { throw new ClientException('This is a remote actor, you should request it to its source of authority instead.'); } diff --git a/plugins/ActivityPub/Util/Response/NoteResponse.php b/plugins/ActivityPub/Util/Response/NoteResponse.php index 98d739265a..f800f065a0 100644 --- a/plugins/ActivityPub/Util/Response/NoteResponse.php +++ b/plugins/ActivityPub/Util/Response/NoteResponse.php @@ -1,25 +1,57 @@ . +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ namespace Plugin\ActivityPub\Util\Response; -use App\Entity\Note; -use Exception; -use Plugin\ActivityPub\Util\Model\EntityToType\NoteToType; +use App\Entity\Note as GSNote; +use Plugin\ActivityPub\Util\Model\Note as ModelNote; +use Plugin\ActivityPub\Util\TypeResponse; +/** + * Provides a response in application/ld+json to GSNotes + * + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ abstract class NoteResponse -//class NoteResponse extends Controller { /** - * @param int $status The response status code + * Provides a response in application/ld+json to GSNotes * - * @throws Exception + * @param GSNote $note + * @param int $status The response status code + * @return TypeResponse */ - public static function handle(Note $note, int $status = 200): TypeResponse - // public function handle(Request $request, int $id): JsonResponse + public static function handle(GSNote $note, int $status = 200): TypeResponse { - // $note = DB::findOneBy('note', ['id' => $id]); - return new TypeResponse(data: NoteToType::translate($note), status: $status); + return new TypeResponse(json: ModelNote::toJson($note), status: $status); } } diff --git a/plugins/ActivityPub/Util/Response/TypeResponse.php b/plugins/ActivityPub/Util/Response/TypeResponse.php deleted file mode 100644 index f9c52af1aa..0000000000 --- a/plugins/ActivityPub/Util/Response/TypeResponse.php +++ /dev/null @@ -1,28 +0,0 @@ -toJson() : null, - status: $status, - headers: ['content-type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'], - json: true, - ); - } -} diff --git a/plugins/ActivityPub/Util/Type.php b/plugins/ActivityPub/Util/Type.php deleted file mode 100644 index 1231f2d5ec..0000000000 --- a/plugins/ActivityPub/Util/Type.php +++ /dev/null @@ -1,125 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util; - -use Exception; -use Plugin\ActivityPub\Util\Type\AbstractObject; -use Plugin\ActivityPub\Util\Type\TypeResolver; -use Plugin\ActivityPub\Util\Type\Validator; - -/** - * \ActivityPhp\Type is a Factory for ActivityStreams 2.0 types. - * - * It provides shortcuts methods for type instantiation and more. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#types - * @see https://www.w3.org/TR/activitystreams-vocabulary/#activity-types - * @see https://www.w3.org/TR/activitystreams-vocabulary/#actor-types - * @see https://www.w3.org/TR/activitystreams-vocabulary/#object-types - */ -abstract class Type -{ - /** - * Factory method to create type instance and set attributes values - * - * To see which default types are defined and their attributes: - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#types - * @see https://www.w3.org/TR/activitystreams-vocabulary/#activity-types - * @see https://www.w3.org/TR/activitystreams-vocabulary/#actor-types - * @see https://www.w3.org/TR/activitystreams-vocabulary/#object-types - * - * @param array|string $type - * @param array $attributes - * - * @throws Exception - */ - public static function create($type, array $attributes = []): mixed - { - if (!\is_string($type) && !\is_array($type)) { - throw new Exception( - 'Type parameter must be a string or an array. Given=' - . \gettype($type), - ); - } - - if (\is_array($type)) { - if (!isset($type['type'])) { - throw new Exception( - "Type parameter must have a 'type' key", - ); - } - - $attributes = $type; - } - - try { - $class = \is_array($type) - ? TypeResolver::getClass($type['type']) - : TypeResolver::getClass($type); - } catch (Exception $exception) { - $message = json_encode($attributes, \JSON_PRETTY_PRINT); - throw new Exception( - $exception->getMessage() . "\n{$message}", - ); - } - - if (\is_string($class)) { - $class = new $class(); - } - - foreach ($attributes as $name => $value) { - try { - $class->set($name, $value); - } catch (Exception) { - // Discard invalid properties - } - } - - return $class; - } - - /** - * Create an activitystream type from a JSON string - */ - public static function fromJson(string $json): AbstractObject - { - $data = json_decode($json, true); - - if (json_last_error() === \JSON_ERROR_NONE - && \is_array($data) - ) { - return self::create($data); - } - - throw new Exception( - sprintf( - "An error occurred during the JSON decoding.\n '%s'", - $json, - ), - ); - } - - /** - * Add a custom validator for an attribute. - * It checks that it implements Validator\Interface - * - * @param string $name an attribute name to validate - * @param string $class A validator class name - */ - public static function addValidator(string $name, string $class): void - { - Validator::add($name, $class); - } -} diff --git a/plugins/ActivityPub/Util/Type/AbstractObject.php b/plugins/ActivityPub/Util/Type/AbstractObject.php deleted file mode 100644 index ab995b3a59..0000000000 --- a/plugins/ActivityPub/Util/Type/AbstractObject.php +++ /dev/null @@ -1,365 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type; - -use Exception; -use Plugin\ActivityPub\Util\Type; -use ReflectionClass; -use ReflectionProperty; - -/** - * \ActivityPhp\Type\ObjectAbstract is an abstract class for all - * Activity Streams Core Types. - * - * @see https://www.w3.org/TR/activitystreams-core/#model - */ -abstract class AbstractObject -{ - /** - * Keep all properties values that have been set - */ - private array $_props = []; - - protected string $type = 'AbstractObject'; - - /** - * Standard setter method - * - Perform content validation if a validator exists - * - * @throws Exception - * - * @return $this - */ - public function set(string $name, mixed $value): static - { - // Throws an exception when property is undefined - if ($name !== '@context') { - $this->has($name); - } - - // Validate given value - if (!Validator::validate($name, $value, $this)) { - $message = "Rejected value. Type='%s', Property='%s', value='%s'"; - throw new Exception( - sprintf( - $message, - static::class, - $name, - print_r($value, true), - ) - . \PHP_EOL, - ); - } - - // @context has a special role - if ($name === '@context') { - $this->_props[$name] = $value; - - // All modes and property defined - } elseif ($this->has($name)) { - $this->_props[$name] = $this->transform($value); - - // Undefined property but it's valid as it was - // tested in the if clause above (no exception) so, let's include it - } else { - $this->_props[$name] = $this->transform($value); - } - - return $this; - } - - /** - * Affect a value to a property or an extended property - * - * @throws Exception - */ - private function transform(mixed $value): mixed - { - // Deep typing - if (\is_array($value)) { - if (isset($value['type'])) { - return Type::create($value); - } elseif (\is_int(key($value))) { - return array_map( - static function ($value) { - return \is_array($value) && isset($value['type']) - ? Type::create($value) - : $value; - }, - $value, - ); - // Empty array, array that should not be cast as ActivityStreams types - } else { - return $value; - } - } else { - // Scalars - return $value; - } - } - - /** - * Standard getter method - * - * @throws Exception - */ - public function get(string $name): mixed - { - // Throws an exception when property is undefined - $this->has($name); - - return $this->_props[$name]; - } - - /** - * Checks that property exists - * - * @throws Exception - */ - public function has(string $name): bool - { - if (isset($this->{$name})) { - if (!\array_key_exists($name, $this->_props)) { - $this->_props[$name] = $this->{$name}; - } - - return true; - } - - if (\array_key_exists($name, $this->_props)) { - return true; - } - - $reflect = new ReflectionClass(Type::create($this->type)); - $allowed_props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC | ReflectionProperty::IS_PROTECTED); - $allowed = []; - foreach ($allowed_props as $prop) { - $allowed[] = $prop->getName(); - } - if (!\in_array($name, $allowed)) { - sort($allowed); - throw new Exception( - sprintf( - 'Property "%s" is not defined. Type="%s", ' - . 'Class="%s"' . \PHP_EOL . 'Allowed properties: %s', - $name, - $this->get('type'), - static::class, - implode(', ', $allowed), - ), - ); - } else { - return false; - } - } - - /** - * Get a list of all properties names - */ - public function getProperties(): array - { - return array_values( - array_unique( - array_merge( - array_keys($this->_props), - array_keys( - array_diff_key( - get_object_vars($this), - ['_props' => '1'], - ), - ), - ), - ), - ); - } - - /** - * Get a list of all properties and their values - * as an associative array. - * Null values are not returned. - */ - public function toArray(): array - { - $keys = array_keys( - array_filter( - get_object_vars($this), - static fn ($value, $key): bool => !\is_null($value) && $key !== '_props', - \ARRAY_FILTER_USE_BOTH, - ), - ); - - $stack = []; - - // native properties - foreach ($keys as $key) { - if ($this->{$key} instanceof self) { - $stack[$key] = $this->{$key}->toArray(); - } elseif (!\is_array($this->{$key})) { - $stack[$key] = $this->{$key}; - } elseif (\is_array($this->{$key})) { - if (\is_int(key($this->{$key}))) { - $stack[$key] = array_map( - static function ($value) { - return $value instanceof self - ? $value->toArray() - : $value; - }, - $this->{$key}, - ); - } else { - $stack[$key] = $this->{$key}; - } - } - } - - // _props - foreach ($this->_props as $key => $value) { - if (\is_null($value)) { - continue; - } - - if ($value instanceof self) { - $stack[$key] = $value->toArray(); - } elseif (!\is_array($value)) { - $stack[$key] = $value; - } else { - if (\is_int(key($value))) { - $stack[$key] = array_map( - static function ($value) { - return $value instanceof self - ? $value->toArray() - : $value; - }, - $value, - ); - } else { - $stack[$key] = $value; - } - } - } - - return $stack; - } - - /** - * Get a JSON - * - * @param null|int $options PHP JSON options - */ - public function toJson(?int $options = null): string - { - return json_encode( - value: $this->toArray(), - flags: (int) $options, - ); - } - - /** - * Get a copy of current object and return a new instance - * - * @throws Exception - * - * @return self A new instance of this object - */ - public function copy(): self - { - return Type::create( - $this->type, - $this->toArray(), - ); - } - - /** - * Extend current type properties - * - * @param mixed $default - * - * @throws Exception - */ - public function extend(string $property, mixed $default = null): void - { - if ($this->has($property)) { - return; - } - - if (!\array_key_exists($property, $this->_props)) { - $this->_props[$property] = $default; - } - } - - /** - * Magical isset method - */ - public function __isset(string $name): bool - { - return property_exists($this, $name) - || \array_key_exists($name, $this->_props); - } - - /** - * Magical setter method - * - * @throws Exception - */ - public function __set(string $name, mixed $value): void - { - $this->set($name, $value); - } - - /** - * Magical getter method - * - * @throws Exception - */ - public function __get(string $name): mixed - { - return $this->get($name); - } - - /** - * Overloading methods - * - * @throws Exception - */ - public function __call(string $name, ?array $arguments = []): mixed - { - // Getters - if (str_starts_with($name, 'get')) { - $attr = lcfirst(mb_substr($name, 3)); - return $this->get($attr); - } - - // Setters - if (str_starts_with($name, 'set')) { - if (\count($arguments) === 1) { - $attr = lcfirst(mb_substr($name, 3)); - return $this->set($attr, $arguments[0]); - } else { - throw new Exception( - sprintf( - 'Expected exactly one argument for method "%s()"', - $name, - ), - ); - } - } - - throw new Exception( - sprintf( - 'Method "%s" is not defined', - $name, - ), - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Core/AbstractActivity.php b/plugins/ActivityPub/Util/Type/Core/AbstractActivity.php deleted file mode 100644 index 64aa241296..0000000000 --- a/plugins/ActivityPub/Util/Type/Core/AbstractActivity.php +++ /dev/null @@ -1,110 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Core; - -/** - * \Plugin\ActivityPub\Util\Type\Core\AbstractActivity implements only common - * attributes between Activity and IntransitiveActivity. - * - * It SHOULD NOT be used as if. - * - * Please use IntransitiveActivity or Activity instead. - * - * @see https://www.w3.org/TR/activitystreams-core/#activities - * @see https://www.w3.org/TR/activitystreams-core/#intransitiveactivities - */ -abstract class AbstractActivity extends ObjectType -{ - public string $id; - - /** - * Describes one or more entities that either performed or are - * expected to perform the activity. - * Any single activity can have multiple actors. - * The actor MAY be specified using an indirect Link. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-actor - * - * @var string - * | \Plugin\ActivityPub\Util\Type\Extended\AbstractActor - * | array - * | array - * | Link - */ - protected string $actor; - - /** - * The indirect object, or target, of the activity. - * The precise meaning of the target is largely dependent on the - * type of action being described but will often be the object of - * the English preposition "to". - * For instance, in the activity "John added a movie to his - * wishlist", the target of the activity is John's wishlist. - * An activity can have more than one target. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-target - * - * @var string - * | ObjectType - * | array - * | Link - * | array - */ - protected string $target; - - /** - * Describes the result of the activity. - * For instance, if a particular action results in the creation of - * a new resource, the result property can be used to describe - * that new resource. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-result - * - * @var string - * | ObjectType - * | Link - * | null - */ - protected string $result; - - /** - * An indirect object of the activity from which the - * activity is directed. - * The precise meaning of the origin is the object of the English - * preposition "from". - * For instance, in the activity "John moved an item to List B - * from List A", the origin of the activity is "List A". - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-origin - * - * @var string - * | ObjectType - * | Link - * | null - */ - protected string $origin; - - /** - * One or more objects used (or to be used) in the completion of an - * Activity. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-instrument - * - * @var string - * | ObjectType - * | Link - * | null - */ - protected string $instrument; -} diff --git a/plugins/ActivityPub/Util/Type/Core/Activity.php b/plugins/ActivityPub/Util/Type/Core/Activity.php deleted file mode 100644 index 839cc22d59..0000000000 --- a/plugins/ActivityPub/Util/Type/Core/Activity.php +++ /dev/null @@ -1,45 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Core; - -use Plugin\ActivityPub\Util\Type; - -/** - * \Plugin\ActivityPub\Util\Type\Core\Activity is an implementation of one of the - * Activity Streams Core Types. - * - * Activity objects are specializations of the base Object type that - * provide information about actions that have either already occurred, - * are in the process of occurring, or may occur in the future. - * - * @see https://www.w3.org/TR/activitystreams-core/#activities - */ -class Activity extends AbstractActivity -{ - protected string $type = 'Activity'; - - /** - * Describes the direct object of the activity. - * For instance, in the activity "John added a movie to his - * wishlist", the object of the activity is the movie added. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-object-term - * - * @var string - * | ObjectType - * | Link - * | null - */ - protected ObjectType $object; -} diff --git a/plugins/ActivityPub/Util/Type/Core/Collection.php b/plugins/ActivityPub/Util/Type/Core/Collection.php deleted file mode 100644 index b3a416b4f7..0000000000 --- a/plugins/ActivityPub/Util/Type/Core/Collection.php +++ /dev/null @@ -1,103 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Core; - -/** - * \Plugin\ActivityPub\Util\Type\Core\Collection is an implementation of one of the - * Activity Streams Core Types. - * - * Collection objects are a specialization of the base Object that serve - * as a container for other Objects or Links. - * - * @see https://www.w3.org/TR/activitystreams-core/#collections - */ -class Collection extends ObjectType -{ - protected string $type = 'Collection'; - - public string $id; - - /** - * A non-negative integer specifying the total number of objects - * contained by the logical view of the collection. - * This number might not reflect the actual number of items - * serialized within the Collection object instance. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-totalitems - */ - protected int $totalItems; - - /** - * In a paged Collection, indicates the page that contains the most - * recently updated member items. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-current - * - * @var string - * | Link - * | CollectionPage - * | null - */ - protected string $current; - - /** - * The furthest preceding page of items in the collection. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-last - * - * @var string - * | Link - * | CollectionPage - * | null - */ - protected string $first; - - /** - * The furthest proceeding page of the collection. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-last - * - * @var string - * | Link - * | CollectionPage - * | null - */ - protected string $last; - - /** - * The items contained in a collection. - * The items are considered as unordered. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-items - * - * @var array - * | Link - * | array - * | array - */ - protected array $items = []; - - /** - * The items contained in a collection. - * The items are considered as ordered. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-items - * - * @var array - * | Link - * | array - * | array - */ - protected array $orderedItems = []; -} diff --git a/plugins/ActivityPub/Util/Type/Core/CollectionPage.php b/plugins/ActivityPub/Util/Type/Core/CollectionPage.php deleted file mode 100644 index 9a95f40d22..0000000000 --- a/plugins/ActivityPub/Util/Type/Core/CollectionPage.php +++ /dev/null @@ -1,66 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Core; - -/** - * CollectionPage is an implementation of one - * of the Activity Streams Core Types. - * - * Used to represent distinct subsets of items from a Collection. - * - * @see https://www.w3.org/TR/activitystreams-core/#paging - */ -class CollectionPage extends Collection -{ - protected string $type = 'CollectionPage'; - - public string $id; - - /** - * Identifies the Collection to which CollectionPage objects items - * belong. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-partof - * - * @var string - * | Link - * | Collection - * | null - */ - protected string $partOf; - - /** - * Indicates the next page of items. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-next - * - * @var string - * | Link - * | CollectionPage - * | null - */ - protected string $next; - - /** - * Identifies the previous page of items. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-prev - * - * @var string - * | Link - * | CollectionPage - * | null - */ - protected string $prev; -} diff --git a/plugins/ActivityPub/Util/Type/Core/IntransitiveActivity.php b/plugins/ActivityPub/Util/Type/Core/IntransitiveActivity.php deleted file mode 100644 index 735f255177..0000000000 --- a/plugins/ActivityPub/Util/Type/Core/IntransitiveActivity.php +++ /dev/null @@ -1,29 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Core; - -/** - * \Plugin\ActivityPub\Util\Type\Core\IntransitiveActivity is an implementation of - * one of the Activity Streams Core Types. - * - * IntransitiveActivity objects are specializations of the Activity type - * that represent intransitive actions. IntransitiveActivity objects do - * not have an object property. - * - * @see https://www.w3.org/TR/activitystreams-core/#intransitiveactivities - */ -class IntransitiveActivity extends AbstractActivity -{ - protected string $type = 'IntransitiveActivity'; -} diff --git a/plugins/ActivityPub/Util/Type/Core/Link.php b/plugins/ActivityPub/Util/Type/Core/Link.php deleted file mode 100644 index 728ddcf353..0000000000 --- a/plugins/ActivityPub/Util/Type/Core/Link.php +++ /dev/null @@ -1,116 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Core; - -use Plugin\ActivityPub\Util\Type\AbstractObject; - -/** - * \Plugin\ActivityPub\Util\Type\Core\Link is an implementation of one of the - * Activity Streams Core Types. - * - * A Link describes a qualified, indirect reference to another resource. - * The properties of the Link object are not the properties of the - * referenced resource, but are provided as hints for rendering agents - * to understand how to make use of the resource. - * - * @see https://www.w3.org/TR/activitystreams-core/#link - */ -class Link extends AbstractObject -{ - protected string $type = 'Link'; - - protected string $id; - - /** - * A simple, human-readable, plain-text name for the object. - * HTML markup MUST NOT be included. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-name - * - * @var null|string xsd:string - */ - protected ?string $name; - - /** - * The name MAY be expressed using multiple language-tagged values. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-name - * - * @var null|array rdf:langString - */ - protected ?array $nameMap; - - /** - * The target resource pointed to by a Link. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-href - */ - protected ?string $href; - - /** - * Hints as to the language used by the target resource. - * Value MUST be a BCP47 Language-Tag. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-hreflang - */ - protected ?string $hreflang; - - /** - * The MIME media type of the referenced resource. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-mediatype - */ - protected ?string $mediaType; - - /** - * A link relation associated with a Link. - * The value MUST conform to both the HTML5 - * and RFC5988 "link relation" definitions. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-rel - */ - protected string|array|null $rel; - - /** - * Specifies a hint as to the rendering height - * in device-independentpixels of the linked resource - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-height - * - * @var null|int A non negative integer - */ - protected ?int $height; - - /** - * An entity that provides a preview of this link. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-preview - * - * @var string - * | Object - * | Link - * | null - */ - protected string $preview; - - /** - * On a Link, specifies a hint as to the rendering width in - * device-independent pixels of the linked resource. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-width - * - * @var null|int A non negative integer - */ - protected ?int $width; -} diff --git a/plugins/ActivityPub/Util/Type/Core/ObjectType.php b/plugins/ActivityPub/Util/Type/Core/ObjectType.php deleted file mode 100644 index 2d7a72636d..0000000000 --- a/plugins/ActivityPub/Util/Type/Core/ObjectType.php +++ /dev/null @@ -1,423 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Core; - -use Plugin\ActivityPub\Util\Type\AbstractObject; - -/** - * ObjectType is an implementation of one of the - * Activity Streams Core Types. - * - * The Object is the primary base type for the Activity Streams - * vocabulary. - * - * Note: Object is a reserved keyword in PHP. It has been suffixed with - * 'Type' for this reason. - * - * @see https://www.w3.org/TR/activitystreams-core/#object - */ -class ObjectType extends AbstractObject -{ - /** - * The object's unique global identifier - * - * @see https://www.w3.org/TR/activitypub/#obj-id - */ - public string $id; - - protected string $type = 'Object'; - - /** - * A resource attached or related to an object that potentially - * requires special handling. - * The intent is to provide a model that is at least semantically - * similar to attachments in email. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-attachment - * - * @var string - * | ObjectType - * | Link - * | array - * | array - * | null - */ - protected string $attachment; - - /** - * One or more entities to which this object is attributed. - * The attributed entities might not be Actors. For instance, an - * object might be attributed to the completion of another activity. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-attributedto - * - * @var string - * | ObjectType - * | Link - * | array - * | array - * | null - */ - protected string $attributedTo; - - /** - * One or more entities that represent the total population of - * entities for which the object can considered to be relevant. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audience - * - * @var string - * | ObjectType - * | Link - * | array - * | array - * | null - */ - protected string $audience; - - /** - * The content or textual representation of the Object encoded as a - * JSON string. By default, the value of content is HTML. - * The mediaType property can be used in the object to indicate a - * different content type. - * - * The content MAY be expressed using multiple language-tagged - * values. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-content - */ - protected ?string $content; - - /** - * The context within which the object exists or an activity was - * performed. - * The notion of "context" used is intentionally vague. - * The intended function is to serve as a means of grouping objects - * and activities that share a common originating context or - * purpose. An example could be all activities relating to a common - * project or event. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-context - * - * @var string - * | ObjectType - * | Link - * | null - */ - protected string $context; - - /** - * The content MAY be expressed using multiple language-tagged - * values. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-content - */ - protected ?array $contentMap; - - /** - * A simple, human-readable, plain-text name for the object. - * HTML markup MUST NOT be included. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-name - * - * @var null|string xsd:string - */ - protected ?string $name; - - /** - * The name MAY be expressed using multiple language-tagged values. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-name - * - * @var null|array rdf:langString - */ - protected ?array $nameMap; - - /** - * The date and time describing the actual or expected ending time - * of the object. - * When used with an Activity object, for instance, the endTime - * property specifies the moment the activity concluded or - * is expected to conclude. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-endtime - */ - protected ?string $endTime; - - /** - * The entity (e.g. an application) that generated the object. - */ - protected ?string $generator; - - /** - * An entity that describes an icon for this object. - * The image should have an aspect ratio of one (horizontal) - * to one (vertical) and should be suitable for presentation - * at a small size. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-icon - * - * @var string - * | Image - * | Link - * | array - * | array - * | null - */ - protected string $icon; - - /** - * An entity that describes an image for this object. - * Unlike the icon property, there are no aspect ratio - * or display size limitations assumed. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image-term - * - * @var string - * | Image - * | Link - * | array - * | array - * | null - */ - protected string $image; - - /** - * One or more entities for which this object is considered a - * response. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-inreplyto - * - * @var string - * | ObjectType - * | Link - * | array - * | array - * | null - */ - protected string $inReplyTo; - - /** - * One or more physical or logical locations associated with the - * object. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-location - * - * @var string - * | ObjectType - * | Link - * | array - * | array - * | null - */ - protected string $location; - - /** - * An entity that provides a preview of this object. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-preview - * - * @var string - * | ObjectType - * | Link - * | null - */ - protected string $preview; - - /** - * The date and time at which the object was published - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-published - * - * @var null|string xsd:dateTime - */ - protected ?string $published; - - /** - * A Collection containing objects considered to be responses to - * this object. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-replies - * - * @var string - * | Collection - * | Link - * | null - */ - protected string $replies; - - /** - * The date and time describing the actual or expected starting time - * of the object. - * When used with an Activity object, for instance, the startTime - * property specifies the moment the activity began - * or is scheduled to begin. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-starttime - * - * @var null|string xsd:dateTime - */ - protected ?string $startTime; - - /** - * A natural language summarization of the object encoded as HTML. - * Multiple language tagged summaries MAY be provided. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-summary - * - * @var string - * | ObjectType - * | Link - * | null - */ - protected string $summary; - - /** - * The content MAY be expressed using multiple language-tagged - * values. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-summary - * - * @var null|array - */ - protected mixed $summaryMap; - - /** - * One or more "tags" that have been associated with an objects. - * A tag can be any kind of Object. - * The key difference between attachment and tag is that the former - * implies association by inclusion, while the latter implies - * associated by reference. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tag - * - * @var string - * | ObjectType - * | Link - * | array - * | array - * | null - */ - protected string $tag; - - /** - * The date and time at which the object was updated - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-updated - * - * @var null|string xsd:dateTime - */ - protected ?string $updated; - - /** - * One or more links to representations of the object. - * - * @var string - * | array - * | Link - * | array - * | null - */ - protected string $url; - - /** - * An entity considered to be part of the public primary audience - * of an Object - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-to - * - * @var string - * | ObjectType - * | Link - * | array - * | array - * | null - */ - protected string $to; - - /** - * An Object that is part of the private primary audience of this - * Object. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-bto - * - * @var string - * | ObjectType - * | Link - * | array - * | array - * | null - */ - protected string $bto; - - /** - * An Object that is part of the public secondary audience of this - * Object. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-cc - * - * @var string - * | ObjectType - * | Link - * | array - * | array - * | null - */ - protected string $cc; - - /** - * One or more Objects that are part of the private secondary - * audience of this Object. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-bcc - * - * @var string - * | ObjectType - * | Link - * | array - * | array - * | null - */ - protected string $bcc; - - /** - * The MIME media type of the value of the content property. - * If not specified, the content property is assumed to contain - * text/html content. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-mediatype - */ - protected ?string $mediaType; - - /** - * When the object describes a time-bound resource, such as an audio - * or video, a meeting, etc, the duration property indicates the - * object's approximate duration. - * The value MUST be expressed as an xsd:duration as defined by - * xmlschema11-2, section 3.3.6 (e.g. a period of 5 seconds is - * represented as "PT5S"). - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration - */ - protected ?string $duration; - - /** - * Intended to convey some sort of source from which the content - * markup was derived, as a form of provenance, or to support - * future editing by clients. - * - * @see https://www.w3.org/TR/activitypub/#source-property - */ - protected ObjectType $source; -} diff --git a/plugins/ActivityPub/Util/Type/Core/OrderedCollection.php b/plugins/ActivityPub/Util/Type/Core/OrderedCollection.php deleted file mode 100644 index 65714f3be3..0000000000 --- a/plugins/ActivityPub/Util/Type/Core/OrderedCollection.php +++ /dev/null @@ -1,28 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Core; - -/** - * \Plugin\ActivityPub\Util\Type\Core\OrderedCollection is an implementation of one - * of the Activity Streams Core Types. - * - * A subtype of Collection in which members of the logical collection - * are assumed to always be strictly ordered. - * - * @see https://www.w3.org/TR/activitystreams-core/#collections - */ -class OrderedCollection extends Collection -{ - protected string $type = 'OrderedCollection'; -} diff --git a/plugins/ActivityPub/Util/Type/Core/OrderedCollectionPage.php b/plugins/ActivityPub/Util/Type/Core/OrderedCollectionPage.php deleted file mode 100644 index bfc85bf1c5..0000000000 --- a/plugins/ActivityPub/Util/Type/Core/OrderedCollectionPage.php +++ /dev/null @@ -1,38 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Core; - -/** - * \Plugin\ActivityPub\Util\Type\Core\OrderedCollection is an implementation of one - * of the Activity Streams Core Types. - * - * The OrderedCollectionPage type extends from both CollectionPage and - * OrderedCollection. In addition to the properties inherited from each - * of those, the OrderedCollectionPage may contain an additional - * startIndex property whose value indicates the relative index position - * of the first item contained by the page within the OrderedCollection - * to which the page belongs. - * - * @see https://www.w3.org/TR/activitystreams-core/#paging - */ -class OrderedCollectionPage extends CollectionPage -{ - protected string $type = 'OrderedCollectionPage'; - - /** - * A non-negative integer value identifying the relative position - * within the logical view of a strictly ordered collection. - */ - protected int $startIndex; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/AbstractActor.php b/plugins/ActivityPub/Util/Type/Extended/AbstractActor.php deleted file mode 100644 index ac19db2e9d..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/AbstractActor.php +++ /dev/null @@ -1,114 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended; - -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Core\OrderedCollection; - -/** - * \ActivityPhp\Type\Extended\AbstractActor is an abstract class that - * provides dedicated Actor's properties - */ -abstract class AbstractActor extends ObjectType -{ - /** - * A reference to an ActivityStreams OrderedCollection comprised of - * all the messages received by the actor. - * - * @see https://www.w3.org/TR/activitypub/#inbox - * - * @var OrderedCollection - * | \ActivityPhp\Type\Core\OrderedCollectionPage - * | null - */ - protected OrderedCollection $inbox; - - /** - * A reference to an ActivityStreams OrderedCollection comprised of - * all the messages produced by the actor. - * - * @see https://www.w3.org/TR/activitypub/#outbox - * - * @var OrderedCollection - * | \ActivityPhp\Type\Core\OrderedCollectionPage - * | null - */ - protected OrderedCollection $outbox; - - /** - * A link to an ActivityStreams collection of the actors that this - * actor is following. - * - * @see https://www.w3.org/TR/activitypub/#following - */ - protected string $following; - - /** - * A link to an ActivityStreams collection of the actors that - * follow this actor. - * - * @see https://www.w3.org/TR/activitypub/#followers - */ - protected string $followers; - - /** - * A link to an ActivityStreams collection of objects this actor has - * liked. - * - * @see https://www.w3.org/TR/activitypub/#liked - */ - protected string $liked; - - /** - * A list of supplementary Collections which may be of interest. - * - * @see https://www.w3.org/TR/activitypub/#streams-property - */ - protected array $streams = []; - - /** - * A short username which may be used to refer to the actor, with no - * uniqueness guarantees. - * - * @see https://www.w3.org/TR/activitypub/#preferredUsername - */ - protected ?string $preferredUsername; - - /** - * A JSON object which maps additional typically server/domain-wide - * endpoints which may be useful either for this actor or someone - * referencing this actor. This mapping may be nested inside the - * actor document as the value or may be a link to a JSON-LD - * document with these properties. - * - * @see https://www.w3.org/TR/activitypub/#endpoints - */ - protected string|array|null $endpoints; - - /** - * It's not part of the ActivityPub protocol, but it's a quite common - * practice handling an actor public key with a publicKey array: - * [ - * 'id' => 'https://my-example.com/actor#main-key' - * 'owner' => 'https://my-example.com/actor', - * 'publicKeyPem' => '-----BEGIN PUBLIC KEY----- - * MIIBI [...] - * DQIDAQAB - * -----END PUBLIC KEY-----' - * ] - * - * @see https://www.w3.org/wiki/SocialCG/ActivityPub/Authentication_Authorization#Signing_requests_using_HTTP_Signatures - */ - protected string|array|null $publicKey; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Accept.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Accept.php deleted file mode 100644 index a98de4ad6b..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Accept.php +++ /dev/null @@ -1,31 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Accept is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor accepts the object. The target property can - * be used in certain circumstances to indicate the context into which - * the object has been accepted. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accept - */ -class Accept extends Activity -{ - protected string $type = 'Accept'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Announce.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Announce.php deleted file mode 100644 index 698c66a07d..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Announce.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Announce is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor is calling the target's attention the - * object. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-announce - */ -class Announce extends Activity -{ - protected string $type = 'Announce'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Block.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Block.php deleted file mode 100644 index 44807dac13..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Block.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Block is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor is blocking the object. Blocking is a - * stronger form of Ignore. The typical use is to support social systems - * that allow one user to block activities or content of other users. - * The target and origin typically have no defined meaning. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-block - */ -class Block extends Ignore -{ - protected string $type = 'Block'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Create.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Create.php deleted file mode 100644 index 334a2b7398..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Create.php +++ /dev/null @@ -1,29 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Create is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor has created the object. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-create - */ -class Create extends Activity -{ - protected string $type = 'Create'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Delete.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Delete.php deleted file mode 100644 index 44eef94fc5..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Delete.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Delete is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor has deleted the object. If specified, the - * origin indicates the context from which the object was deleted. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-delete - */ -class Delete extends Activity -{ - protected string $type = 'Delete'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Follow.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Follow.php deleted file mode 100644 index 3e2100398e..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Follow.php +++ /dev/null @@ -1,33 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Follow is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor is "following" the object. Following is - * defined in the sense typically used within Social systems in which - * the actor is interested in any activity performed by or on the - * object. - * The target and origin typically have no defined meaning. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-follow - */ -class Follow extends Activity -{ - protected string $type = 'Follow'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Ignore.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Ignore.php deleted file mode 100644 index 5db6ef5908..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Ignore.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \ActivityPhp\Type\Extended\Activity\Ignore is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor is ignoring the object. - * The target and origin typically have no defined meaning. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-ignore - */ -class Ignore extends Activity -{ - protected string $type = 'Ignore'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Join.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Join.php deleted file mode 100644 index 1144760d69..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Join.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Join is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor has joined the object. - * The target and origin typically have no defined meaning. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-join - */ -class Join extends Activity -{ - protected string $type = 'Join'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Leave.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Leave.php deleted file mode 100644 index 5281b40ac8..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Leave.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Leave is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor has left the object. - * The target and origin typically have no meaning. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-leave - */ -class Leave extends Activity -{ - protected string $type = 'Leave'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Like.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Like.php deleted file mode 100644 index 85286209fa..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Like.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Like is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor likes, recommends or endorses the object. - * The target and origin typically have no defined meaning. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-like - */ -class Like extends Activity -{ - protected string $type = 'Like'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Question.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Question.php deleted file mode 100644 index 882652965d..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Question.php +++ /dev/null @@ -1,75 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\IntransitiveActivity; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Question is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents a question being asked. Question objects are an extension - * of IntransitiveActivity. That is, the Question object is an Activity, - * but the direct object is the question itself, and therefore it would - * not contain an object property. - * - * Either of the anyOf and oneOf properties MAY be used to express - * possible answers, but a Question object MUST NOT have both properties - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-move - */ -class Question extends IntransitiveActivity -{ - protected string $type = 'Question'; - - /** - * An exclusive option for a Question - * Use of oneOf implies that the Question can have only a - * single answer. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-oneof - * - * @var array - * | array<\Plugin\ActivityPub\Util\Type\Core\Link> - * | null - */ - protected array $oneOf; - - /** - * An inclusive option for a Question. - * Use of anyOf implies that the Question can have multiple answers. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-anyof - * - * @var array - * | array<\Plugin\ActivityPub\Util\Type\Core\Link> - * | null - */ - protected array $anyOf; - - /** - * Indicates that a question has been closed, and answers are no - * longer accepted. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-closed - * - * @var ObjectType - * | \Plugin\ActivityPub\Util\Type\Core\Link - * | \DateTime - * | bool - * | null - */ - protected ObjectType $closed; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Reject.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Reject.php deleted file mode 100644 index 07cd9b5059..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Reject.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Reject is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor is rejecting the object. - * The target and origin typically have no defined meaning. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-reject - */ -class Reject extends Activity -{ - protected string $type = 'Reject'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Remove.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Remove.php deleted file mode 100644 index e56bcf3944..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Remove.php +++ /dev/null @@ -1,31 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Remove is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor is removing the object. - * If specified, the origin indicates the context from which the object - * is being removed. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-remove - */ -class Remove extends Activity -{ - protected string $type = 'Remove'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Undo.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Undo.php deleted file mode 100644 index 85af6fded8..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Undo.php +++ /dev/null @@ -1,35 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Undo is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor is undoing the object. In most cases, the - * object will be an Activity describing some previously performed - * action (for instance, a person may have previously "liked" an article - * but, for whatever reason, might choose to undo that like at some - * later point in time). - * - * The target and origin typically have no defined meaning. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-undo - */ -class Undo extends Activity -{ - protected string $type = 'Undo'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Activity/Update.php b/plugins/ActivityPub/Util/Type/Extended/Activity/Update.php deleted file mode 100644 index 53717a1189..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Activity/Update.php +++ /dev/null @@ -1,33 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Activity; - -use Plugin\ActivityPub\Util\Type\Core\Activity; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Activity\Update is an implementation of - * one of the Activity Streams Extended Types. - * - * Indicates that the actor has updated the object. Note, however, that - * this vocabulary does not define a mechanism for describing the actual - * set of modifications made to object. - * - * The target and origin typically have no defined meaning. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-update - */ -class Update extends Activity -{ - protected string $type = 'Update'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Actor/Application.php b/plugins/ActivityPub/Util/Type/Extended/Actor/Application.php deleted file mode 100644 index 0cd57884b7..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Actor/Application.php +++ /dev/null @@ -1,29 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Actor; - -use Plugin\ActivityPub\Util\Type\Extended\AbstractActor; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Actor\Application is an implementation of - * one of the Activity Streams Extended Types. - * - * Describes a software application. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-application - */ -class Application extends AbstractActor -{ - protected string $type = 'Application'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Actor/Group.php b/plugins/ActivityPub/Util/Type/Extended/Actor/Group.php deleted file mode 100644 index 87bb24632c..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Actor/Group.php +++ /dev/null @@ -1,29 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Actor; - -use Plugin\ActivityPub\Util\Type\Extended\AbstractActor; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Actor\Group is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents a formal or informal collective of Actors. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-group - */ -class Group extends AbstractActor -{ - protected string $type = 'Group'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Actor/Organization.php b/plugins/ActivityPub/Util/Type/Extended/Actor/Organization.php deleted file mode 100644 index eaa0203876..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Actor/Organization.php +++ /dev/null @@ -1,29 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Actor; - -use Plugin\ActivityPub\Util\Type\Extended\AbstractActor; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Actor\Organization is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents a formal or informal collective of Actors. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-organization - */ -class Organization extends AbstractActor -{ - protected string $type = 'Organization'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Actor/Person.php b/plugins/ActivityPub/Util/Type/Extended/Actor/Person.php deleted file mode 100644 index 918c4a2eb1..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Actor/Person.php +++ /dev/null @@ -1,29 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Actor; - -use Plugin\ActivityPub\Util\Type\Extended\AbstractActor; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Actor\Person is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents an individual person. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person - */ -class Person extends AbstractActor -{ - protected string $type = 'Person'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Actor/Service.php b/plugins/ActivityPub/Util/Type/Extended/Actor/Service.php deleted file mode 100644 index b01eaf9a1a..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Actor/Service.php +++ /dev/null @@ -1,29 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Actor; - -use Plugin\ActivityPub\Util\Type\Extended\AbstractActor; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Actor\Service is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents a service of any kind. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-service - */ -class Service extends AbstractActor -{ - protected string $type = 'Service'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Object/Article.php b/plugins/ActivityPub/Util/Type/Extended/Object/Article.php deleted file mode 100644 index cd96efcee2..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Object/Article.php +++ /dev/null @@ -1,29 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Object; - -use Plugin\ActivityPub\Util\Type\Core\ObjectType; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Object\Article is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents any kind of multi-paragraph written work. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-article - */ -class Article extends ObjectType -{ - protected string $type = 'Article'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Object/Audio.php b/plugins/ActivityPub/Util/Type/Extended/Object/Audio.php deleted file mode 100644 index e4da0feb30..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Object/Audio.php +++ /dev/null @@ -1,27 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Object; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Object\Audio is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents a document of any kind. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audio - */ -class Audio extends Document -{ - protected string $type = 'Audio'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Object/Document.php b/plugins/ActivityPub/Util/Type/Extended/Object/Document.php deleted file mode 100644 index 7a140f9f78..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Object/Document.php +++ /dev/null @@ -1,29 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Object; - -use Plugin\ActivityPub\Util\Type\Core\ObjectType; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Object\Document is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents an audio document of any kind. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-document - */ -class Document extends ObjectType -{ - protected string $type = 'Document'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Object/Event.php b/plugins/ActivityPub/Util/Type/Extended/Object/Event.php deleted file mode 100644 index e00fb5b6b4..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Object/Event.php +++ /dev/null @@ -1,29 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Object; - -use Plugin\ActivityPub\Util\Type\Core\ObjectType; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Object\Event is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents any kind of event. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-event - */ -class Event extends ObjectType -{ - protected string $type = 'Event'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Object/Image.php b/plugins/ActivityPub/Util/Type/Extended/Object/Image.php deleted file mode 100644 index 328dd6df48..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Object/Image.php +++ /dev/null @@ -1,27 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Object; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Object\Image is an implementation of - * one of the Activity Streams Extended Types. - * - * An image document of any kind. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image - */ -class Image extends Document -{ - protected string $type = 'Image'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Object/Mention.php b/plugins/ActivityPub/Util/Type/Extended/Object/Mention.php deleted file mode 100644 index f672502dd0..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Object/Mention.php +++ /dev/null @@ -1,29 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Object; - -use Plugin\ActivityPub\Util\Type\Core\Link; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Object\Mention is an implementation of - * one of the Activity Streams Extended Types. - * - * A specialized Link that represents an @mention. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-mention - */ -class Mention extends Link -{ - protected string $type = 'Mention'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Object/Note.php b/plugins/ActivityPub/Util/Type/Extended/Object/Note.php deleted file mode 100644 index d4606bc432..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Object/Note.php +++ /dev/null @@ -1,30 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Object; - -use Plugin\ActivityPub\Util\Type\Core\ObjectType; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Object\Note is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents a short written work typically less than a single - * paragraph in length. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note - */ -class Note extends ObjectType -{ - protected string $type = 'Note'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Object/Page.php b/plugins/ActivityPub/Util/Type/Extended/Object/Page.php deleted file mode 100644 index a8132dd3c5..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Object/Page.php +++ /dev/null @@ -1,27 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Object; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Object\Page is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents a Web Page. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-page - */ -class Page extends Document -{ - protected string $type = 'Page'; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Object/Place.php b/plugins/ActivityPub/Util/Type/Extended/Object/Place.php deleted file mode 100644 index a138be9ba5..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Object/Place.php +++ /dev/null @@ -1,83 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Object; - -use Plugin\ActivityPub\Util\Type\Core\ObjectType; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Object\Place is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents a logical or physical location. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-place - */ -class Place extends ObjectType -{ - protected string $type = 'Place'; - - /** - * Indicates the accuracy of position coordinates on a Place - * objects. Expressed in properties of percentage. - * e.g. "94.0" means "94.0% accurate". - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-accuracy - */ - protected ?float $accuracy; - - /** - * The altitude of a place. - * The measurement units is indicated using the units' property. - * If units is not specified, the default is assumed to be "m" - * indicating meters. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-altitude - */ - protected ?float $altitude; - - /** - * The latitude of a place. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-latitude - */ - protected int|null|float $latitude; - - /** - * The longitude of a place. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-longitude - */ - protected int|null|float $longitude; - - /** - * The radius from the given latitude and longitude for a Place. - * The units are expressed by the units' property. - * If units is not specified, the default is assumed to be "m" - * indicating "meters". - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-radius - */ - protected int|null|float $radius; - - /** - * Specifies the measurement units for the radius and altitude - * properties on a Place object. - * If not specified, the default is assumed to be "m" for "meters". - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-units - * - * "cm" | " feet" | " inches" | " km" | " m" | " miles" | xsd:anyURI - */ - protected string $units; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Object/Profile.php b/plugins/ActivityPub/Util/Type/Extended/Object/Profile.php deleted file mode 100644 index 11d6f6427f..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Object/Profile.php +++ /dev/null @@ -1,37 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Object; - -use Plugin\ActivityPub\Util\Type\Core\ObjectType; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Object\Profile is an implementation of - * one of the Activity Streams Extended Types. - * - * A Profile is a content object that describes another Object, - * typically used to describe Actor Type objects. - * The describes property is used to reference the object being - * described by the profile. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-profile - */ -class Profile extends ObjectType -{ - protected string $type = 'Profile'; - - /** - * Identify the object described by the Profile. - */ - protected ObjectType $describes; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Object/Tombstone.php b/plugins/ActivityPub/Util/Type/Extended/Object/Tombstone.php deleted file mode 100644 index 2c83bdf179..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Object/Tombstone.php +++ /dev/null @@ -1,47 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Object; - -use Plugin\ActivityPub\Util\Type\Core\ObjectType; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Object\Tombstone is an implementation of - * one of the Activity Streams Extended Types. - * - * A Tombstone represents a content object that has been deleted. It can - * be used in Collections to signify that there used to be an object at - * this position, but it has been deleted. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tombstone - */ -class Tombstone extends ObjectType -{ - protected string $type = 'Tombstone'; - - /** - * The type of the object that was deleted. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-formertype - */ - protected ?string $formerType; - - /** - * A timestamp for when the object was deleted. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-deleted - * - * @var null|string xsd:dateTime formatted - */ - protected ?string $deleted; -} diff --git a/plugins/ActivityPub/Util/Type/Extended/Object/Video.php b/plugins/ActivityPub/Util/Type/Extended/Object/Video.php deleted file mode 100644 index 965f25aca2..0000000000 --- a/plugins/ActivityPub/Util/Type/Extended/Object/Video.php +++ /dev/null @@ -1,27 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Extended\Object; - -/** - * \Plugin\ActivityPub\Util\Type\Extended\Object\Video is an implementation of - * one of the Activity Streams Extended Types. - * - * Represents a video document of any kind. - * - * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-video - */ -class Video extends Document -{ - protected string $type = 'Video'; -} diff --git a/plugins/ActivityPub/Util/Type/TypeResolver.php b/plugins/ActivityPub/Util/Type/TypeResolver.php deleted file mode 100644 index 36b82964e0..0000000000 --- a/plugins/ActivityPub/Util/Type/TypeResolver.php +++ /dev/null @@ -1,134 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type; - -use Exception; - -/** - * \Plugin\ActivityPub\Util\Type\TypeResolver is an abstract class for - * resolving class names called by their short names (AS types). - */ -abstract class TypeResolver -{ - /** - * A list of core types - */ - protected static array $coreTypes = [ - 'Activity', 'Collection', 'CollectionPage', - 'IntransitiveActivity', 'Link', 'ObjectType', - 'OrderedCollection', 'OrderedCollectionPage', - 'Object', - ]; - - /** - * A list of actor types - */ - protected static array $actorTypes = [ - 'Application', 'Group', 'Organization', 'Person', 'Service', - ]; - - /** - * A list of activity types - */ - protected static array $activityTypes = [ - 'Accept', 'Add', 'Announce', 'Block', - 'Create', 'Delete', 'Follow', 'Ignore', - 'Invite', 'Join', 'Leave', 'Like', - 'Question', 'Reject', 'Remove', 'Undo', - ]; - - /** - * A list of object types - */ - protected static array $objectTypes = [ - 'Article', 'Audio', 'Document', 'Event', 'Image', - 'Mention', 'Note', 'Page', 'Place', 'Profile', - 'Tombstone', 'Video', - ]; - - /** - * Get namespaced class for a given short type - * - * @throws Exception - * - * @return string Related namespace - * @throw \Exception if a namespace was not found. - */ - public static function getClass(string $type): string - { - $ns = __NAMESPACE__; - - if ($type == 'Object') { - $type .= 'Type'; - } - - switch ($type) { - case \in_array($type, self::$coreTypes): - $ns .= '\Core'; - break; - case \in_array($type, self::$activityTypes): - $ns .= '\Extended\Activity'; - break; - case \in_array($type, self::$actorTypes): - $ns .= '\Extended\Actor'; - break; - case \in_array($type, self::$objectTypes): - $ns .= '\Extended\Object'; - break; - default: - throw new Exception( - "Undefined scope for type '{$type}'", - ); - } - - return $ns . '\\' . $type; - } - - /** - * Validate an object pool type with type attribute - * - * @param string $poolname An expected pool name - */ - public static function isScope(object $item, string $poolname = 'all'): bool - { - if (!\is_object($item) - || !isset($item->type) - || !\is_string($item->type) - ) { - return false; - } - - return match (mb_strtolower($poolname)) { - 'all' => self::exists($item->type), - 'actor' => \in_array($item->type, self::$actorTypes), - default => false, - }; - } - - /** - * Verify that a type exists - */ - public static function exists(string $name): bool - { - return \in_array( - $name, - array_merge( - self::$coreTypes, - self::$activityTypes, - self::$actorTypes, - self::$objectTypes, - ), - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Util.php b/plugins/ActivityPub/Util/Type/Util.php deleted file mode 100644 index 282a256025..0000000000 --- a/plugins/ActivityPub/Util/Type/Util.php +++ /dev/null @@ -1,472 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type; - -use DateInterval; -use DateTime; -use Exception; -use Plugin\ActivityPub\Util\Type; - -/** - * \Plugin\ActivityPub\Util\Type\Util is an abstract class for - * supporting validators checks & transformations. - */ -abstract class Util -{ - /** - * Allowed units - * - * @var array - */ - protected static array $units = [ - 'cm', 'feet', 'inches', 'km', 'm', 'miles', - ]; - - /** - * Transform an array into an ActivityStreams type - * - * @throws Exception - * - * @return AbstractObject|array an ActivityStreams - * type or given array if type key is not defined - */ - public static function arrayToType(array $item): AbstractObject|array - { - // Maybe an array representing an AS object - // It must have a type key - if (isset($item['type'])) { - return Type::create($item['type'], $item); - } - - return $item; - } - - /** - * Validate an URL - */ - public static function validateUrl(mixed $value): bool - { - return \is_string($value) - && filter_var($value, \FILTER_VALIDATE_URL) !== false - && \in_array( - parse_url($value, \PHP_URL_SCHEME), - ['http', 'https', 'magnet'], - ); - } - - /** - * Validate a magnet link - * - * @see https://en.wikipedia.org/wiki/Magnet_URI_scheme - * - * @todo Make a better validation as xs is not the only parameter - */ - public static function validateMagnet(mixed $value): bool - { - return \is_string($value) - && mb_strlen($value) < 262144 - && preg_match( - '#^magnet:\?xs=(https?)://.*$#iu', - urldecode($value), - ); - } - - /** - * Validate an OStatus tag string - */ - public static function validateOstatusTag(mixed $value): bool - { - return \is_string($value) - && mb_strlen($value) < 262144 - && preg_match( - '#^tag:([\w\-\.]+),([\d]{4}-[\d]{2}-[\d]{2}):([\w])+Id=([\d]+):objectType=([\w]+)#iu', - $value, - ); - } - - /** - * Validate a rel attribute value. - * - * @see https://tools.ietf.org/html/rfc5988 - */ - public static function validateRel(string $value): bool - { - return \is_string($value) - && preg_match("/^[^\\s\r\n\\,]+\\z/i", $value); - } - - /** - * Validate a non negative integer. - */ - public static function validateNonNegativeInteger(int $value): bool - { - return \is_int($value) - && $value >= 0; - } - - /** - * Validate a non negative number. - */ - public static function validateNonNegativeNumber(float|int $value): bool - { - return is_numeric($value) - && $value >= 0; - } - - /** - * Validate units format. - */ - public static function validateUnits(string $value): bool - { - if (\is_string($value)) { - if (\in_array($value, self::$units) - || self::validateUrl($value) - ) { - return true; - } - } - - return false; - } - - /** - * Validate an Object type - * - * @throws Exception - */ - public static function validateObject(object $item): bool - { - return self::hasProperties($item, ['type']) - && \is_string($item->type) - && $item->type === 'Object'; - } - - /** - * Decode a JSON string - * - * @throws Exception if JSON decoding process has failed - */ - public static function decodeJson(string $value): array - { - $json = json_decode($value, true); - - if (json_last_error() !== \JSON_ERROR_NONE) { - throw new Exception( - 'JSON decoding failed for string: ' . $value, - ); - } - - return $json; - } - - /** - * Checks that all properties exist for a stdClass - * - * @param bool $strict If true throws an \Exception, - * otherwise, returns false - * - * @throws Exception if a property is not set - */ - public static function hasProperties( - object $item, - array $properties, - bool $strict = false, - ): bool { - foreach ($properties as $property) { - if (!property_exists($item, $property)) { - if ($strict) { - throw new Exception( - sprintf( - 'Attribute "%s" MUST be set for item: %s', - $property, - print_r($item, true), - ), - ); - } - - return false; - } - } - - return true; - } - - /** - * Validate a reference with a Link or an Object with a URL - * - * @throws Exception - */ - public static function isLinkOrUrlObject(object $item): bool - { - self::hasProperties($item, ['type'], true); - - // Validate Link type - if ($item->type === 'Link') { - return self::validateLink($item); - } - - // Validate Object type - self::hasProperties($item, ['url'], true); - - return self::validateUrl($item->url); - } - - /** - * Validate a reference as Link - * - * @throws Exception - */ - public static function validateLink(object|array $item): bool - { - if (\is_array($item)) { - $item = (object) $item; - } - - if (!\is_object($item)) { - return false; - } - - self::hasProperties($item, ['type'], true); - - // Validate Link type - if ($item->type !== 'Link') { - return false; - } - - // Validate Object type - self::hasProperties($item, ['href'], true); - - return self::validateUrl($item->href) - || self::validateMagnet($item->href); - } - - /** - * Validate a datetime - */ - public static function validateDatetime($value): bool - { - if (!\is_string($value) - || !preg_match( - '/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(.*)$/', - $value, - ) - ) { - return false; - } - - try { - $dt = new DateTime($value); - return true; - } catch (Exception $e) { - return false; - } - } - - /** - * Check that container class is a subclass of a given class - * - * @param bool $strict If true, throws an exception - * - * @throws Exception - */ - public static function subclassOf(object $container, array|string $classes, bool $strict = false): bool - { - if (!\is_array($classes)) { - $classes = [$classes]; - } - - foreach ($classes as $class) { - if (\get_class($container) === $class - || is_subclass_of($container, $class) - ) { - return true; - } - } - - if ($strict) { - throw new Exception( - sprintf( - 'Class "%s" MUST be a subclass of "%s"', - \get_class($container), - implode(', ', $classes), - ), - ); - } - - return false; - } - - /** - * Checks that a numeric value is part of a range. - * If a minimal value is null, value has to be inferior to max value - * If a maximum value is null, value has to be superior to min value - */ - public static function between(float|int $value, float|int|null $min, float|int|null $max): bool - { - if (!is_numeric($value)) { - return false; - } - - return match (true) { - \is_null($min) && \is_null($max) => false, - \is_null($min) => $value <= $max, - \is_null($max) => $value >= $min, - default => $value >= $min - && $value <= $max, - }; - } - - /** - * Check that a given string is a valid XML Schema xsd:duration - * - * @param bool $strict If true, throws an exception - * - * @throws Exception - */ - public static function isDuration(string $duration, bool $strict = false): bool - { - try { - new DateInterval($duration); - return true; - } catch (Exception $e) { - if ($strict) { - throw new Exception( - sprintf( - 'Duration "%s" MUST respect xsd:duration', - $duration, - ), - ); - } - } - - return false; - } - - /** - * Checks that it's an object type - */ - public static function isObjectType(object $item): bool - { - return TypeResolver::isScope($item); - } - - /** - * Checks that it's an actor type - */ - public static function isActorType(object $item): bool - { - return TypeResolver::isScope($item, 'actor'); - } - - /** - * Validate an object type with type attribute - * - * @param string $type An expected type - */ - public static function isType(object $item, string $type): bool - { - // Validate that container is a certain type - if (!\is_object($item)) { - return false; - } - - return (bool) ( - property_exists($item, 'type') - && \is_string($item->type) - && $item->type === $type - ); - } - - /** - * Validate a BCP 47 language value - */ - public static function validateBcp47(string $value): bool - { - return \is_string($value) - && preg_match( - '/^(((en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((([A-Za-z]{2,3}(-([A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-([A-Za-z]{4}))?(-([A-Za-z]{2}|[0-9]{3}))?(-([A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-([0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(x(-[A-Za-z0-9]{1,8})+))?)|(x(-[A-Za-z0-9]{1,8})+))$/', - $value, - ); - } - - /** - * Validate a plain text value - */ - public static function validatePlainText(string $value): bool - { - return \is_string($value) - && preg_match( - '/^([^<]+)$/', - $value, - ); - } - - /** - * Validate mediaType format - */ - public static function validateMediaType(string $value): bool - { - return \is_string($value) - && preg_match( - '#^(([\w]+[\w\-]+[\w+])/(([\w]+[\w\-\.\+]+[\w]+)|(\*));?)+$#', - $value, - ); - } - - /** - * Validate a Collection type - * - * @throws Exception - */ - public static function validateCollection(object $item): bool - { - if (is_scalar($item)) { - return false; - } - - if (!\is_object($item)) { - $item = (object) $item; - } - - self::hasProperties( - $item, - [/*totalItems', 'current', 'first', 'last', */ 'items'], - true, - ); - - return true; - } - - /** - * Validate a CollectionPage type - * - * @throws Exception - */ - public static function validateCollectionPage(object $item): bool - { - - // Must be a Collection - if (!self::validateCollection($item)) { - return false; - } - - self::hasProperties( - $item, - ['partOf'/*, 'next', 'prev'*/], - true, - ); - - return true; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator.php b/plugins/ActivityPub/Util/Type/Validator.php deleted file mode 100644 index 1ed41ef9aa..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator.php +++ /dev/null @@ -1,98 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type; - -use Exception; - -/** - * \Plugin\ActivityPub\Util\Type\Validator is an abstract class for - * attribute validation. - */ -abstract class Validator -{ - /** - * Contains all custom validators - * - * @var array - * - * [ 'attributeName' => CustomValidatorClassName::class ] - */ - protected static array $validators = []; - - /** - * Validate an attribute value for given attribute name and - * container object. - * - * @param mixed $container An object - * - * @throws Exception if $container is not an object - */ - public static function validate(string $name, mixed $value, mixed $container): bool - { - if (!\is_object($container)) { - throw new Exception( - 'Given container is not an object', - ); - } - - // Perform validation - if (isset(self::$validators[$name])) { - return self::$validators[$name]->validate( - $value, - $container, - ); - } - - // Try to load a default validator - $validatorName = sprintf( - '\Plugin\ActivityPub\Util\Type\Validator\%sValidator', - ucfirst($name), - ); - - if (class_exists($validatorName)) { - self::add($name, $validatorName); - return self::validate($name, $value, $container); - } - - // There is no validator for this attribute - return true; - } - - /** - * Add a new validator in the pool. - * It checks that it implements Validator\Interface - * - * @param string $name an attribute name to validate - * @param object|string $class A validator class name - * - * @throws Exception if validator class does not implement - * \Plugin\ActivityPub\Util\Type\Helper\ValidatorInterface - */ - public static function add(string $name, object|string $class): void - { - $validator = new $class(); - - if (!($validator instanceof ValidatorInterface)) { - throw new Exception( - sprintf( - 'Validator "%s" MUST implement "%s" interface', - \get_class($validator), - ValidatorInterface::class, - ), - ); - } - - self::$validators[$name] = $validator; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/AccuracyValidator.php b/plugins/ActivityPub/Util/Type/Validator/AccuracyValidator.php deleted file mode 100644 index df3b645cfb..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/AccuracyValidator.php +++ /dev/null @@ -1,35 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\AccuracyValidator is a dedicated - * validator for accuracy attribute. - */ -class AccuracyValidator implements ValidatorInterface -{ - /** - * Validate an ACCURACY attribute value - * - * @param mixed $container An object - */ - public function validate(mixed $value, mixed $container): bool - { - return is_numeric($value) - && (float) $value >= 0 - && (float) $value <= 100.0; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/ActorValidator.php b/plugins/ActivityPub/Util/Type/Validator/ActorValidator.php deleted file mode 100644 index 36ed339be4..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/ActorValidator.php +++ /dev/null @@ -1,112 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Collection; -use Plugin\ActivityPub\Util\Type\Core\Link; -use Plugin\ActivityPub\Util\Type\Extended\AbstractActor; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\ActorValidator is a dedicated - * validator for actor attribute. - */ -class ActorValidator implements ValidatorInterface -{ - /** - * Validate an ACTOR attribute value - * - * @param mixed $container An object - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Can be an indirect link - if (\is_string($value) && Util::validateUrl($value)) { - return true; - } - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - // A collection - if (\is_array($value)) { - return $this->validateObjectCollection($value); - } - - // Must be an object - if (!\is_object($value)) { - return false; - } - - // A single actor - return $this->validateObject($value); - } - - /** - * Validate an Actor object type - * - * @throws Exception - */ - protected function validateObject(object|array $item): bool - { - if (\is_array($item)) { - $item = Util::arrayToType($item); - } - - Util::subclassOf( - $item, - [ - AbstractActor::class, - Link::class, - Collection::class, - ], - true, - ); - - return true; - } - - /** - * Validate a list of object - * Collection can contain: - * - Indirect URL - * - An actor object - * - * @throws Exception - * @throws Exception - */ - protected function validateObjectCollection(array $collection): bool - { - foreach ($collection as $item) { - if (\is_array($item) && $this->validateObject($item)) { - continue; - } - if (\is_object($item) && $this->validateObject($item)) { - continue; - } - if (\is_string($item) && Util::validateUrl($item)) { - continue; - } - - return false; - } - - return \count($collection) > 0; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/AltitudeValidator.php b/plugins/ActivityPub/Util/Type/Validator/AltitudeValidator.php deleted file mode 100644 index cc106c15e0..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/AltitudeValidator.php +++ /dev/null @@ -1,33 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\AltitudeValidator is a dedicated - * validator for altitude attribute. - */ -class AltitudeValidator implements ValidatorInterface -{ - /** - * Validate an ALTITUDE attribute value - * - * @param mixed $container An object - */ - public function validate(mixed $value, mixed $container): bool - { - return (bool) (\is_float($value) || \is_int($value)); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/AnyOfValidator.php b/plugins/ActivityPub/Util/Type/Validator/AnyOfValidator.php deleted file mode 100644 index 66a60c3bb7..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/AnyOfValidator.php +++ /dev/null @@ -1,56 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Extended\Activity\Question; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\AnyOfValidator is a dedicated - * validator for anyOf attribute. - */ -class AnyOfValidator extends ValidatorTools -{ - /** - * Validate an ANYOF attribute value - * - * @param mixed $container An object - * - * @throws Exception - * - * @todo Choices can contain Indirect references. - * This validation should validate this kind of usage. - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is a Question type - Util::subclassOf($container, Question::class, true); - - // A collection - if (!\is_array($value)) { - return false; - } - - if (!\count($value)) { - return false; - } - - return $this->validateObjectCollection( - $value, - $this->getQuestionAnswerValidator(), - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/AttachmentValidator.php b/plugins/ActivityPub/Util/Type/Validator/AttachmentValidator.php deleted file mode 100644 index 1f104d577e..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/AttachmentValidator.php +++ /dev/null @@ -1,44 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\AttachmentValidator is a dedicated - * validator for attachment attribute. - */ -class AttachmentValidator extends ValidatorTools -{ - /** - * Validate an attachment value - * - * @param mixed $container An Object type - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - if (\is_array($value) && !\count($value)) { - return true; - } - - return $this->validateListOrObject( - $value, - $container, - $this->getAttachmentValidator(), - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/AttributedToValidator.php b/plugins/ActivityPub/Util/Type/Validator/AttributedToValidator.php deleted file mode 100644 index 8f8055193e..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/AttributedToValidator.php +++ /dev/null @@ -1,40 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\AttributedToValidator is a dedicated - * validator for attributedTo attribute. - */ -class AttributedToValidator extends ValidatorTools -{ - /** - * Validate an attributedTo value - * - * @param mixed $container An Object type - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - return $this->validateListOrObject( - $value, - $container, - $this->getCollectionActorsValidator(), - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/AudienceValidator.php b/plugins/ActivityPub/Util/Type/Validator/AudienceValidator.php deleted file mode 100644 index ebd310fbbe..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/AudienceValidator.php +++ /dev/null @@ -1,40 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\AudienceValidator is a dedicated - * validator for audience attribute. - */ -class AudienceValidator extends ValidatorTools -{ - /** - * Validate an audience value - * - * @param mixed $container An Object type - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - return $this->validateListOrObject( - $value, - $container, - $this->getLinkOrNamedObjectValidator(), - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/BccValidator.php b/plugins/ActivityPub/Util/Type/Validator/BccValidator.php deleted file mode 100644 index 8accd0a28a..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/BccValidator.php +++ /dev/null @@ -1,40 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\BccValidator is a dedicated - * validator for bcc attribute. - */ -class BccValidator extends ValidatorTools -{ - /** - * Validate a bcc value - * - * @param mixed $container An Object type - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - return $this->validateListOrObject( - $value, - $container, - $this->getLinkOrUrlObjectValidator(), - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/BtoValidator.php b/plugins/ActivityPub/Util/Type/Validator/BtoValidator.php deleted file mode 100644 index 48eeee57a6..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/BtoValidator.php +++ /dev/null @@ -1,40 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\BtoValidator is a dedicated - * validator for bto attribute. - */ -class BtoValidator extends ValidatorTools -{ - /** - * Validate a bto value - * - * @param mixed $container An Object type - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - return $this->validateListOrObject( - $value, - $container, - $this->getLinkOrUrlObjectValidator(), - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/CcValidator.php b/plugins/ActivityPub/Util/Type/Validator/CcValidator.php deleted file mode 100644 index dd2a1628a5..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/CcValidator.php +++ /dev/null @@ -1,40 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\CcValidator is a dedicated - * validator for cc attribute. - */ -class CcValidator extends ValidatorTools -{ - /** - * Validate a cc value - * - * @param mixed $container An Object type - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - return $this->validateListOrObject( - $value, - $container, - $this->getLinkOrUrlObjectValidator(), - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/ClosedValidator.php b/plugins/ActivityPub/Util/Type/Validator/ClosedValidator.php deleted file mode 100644 index 528edfc3bc..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/ClosedValidator.php +++ /dev/null @@ -1,68 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Extended\Activity\Question; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\ClosedValidator is a dedicated - * validator for closed attribute. - */ -class ClosedValidator implements ValidatorInterface -{ - /** - * Validate an CLOSED attribute value - * - * @param mixed $container A Question type - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is a Question type - Util::subclassOf($container, Question::class, true); - - // Can be a boolean - if (\is_bool($value)) { - return true; - } - - if (\is_string($value)) { - // Can be a datetime - if (Util::validateDatetime($value)) { - return true; - } - - // Can be a URL - if (Util::validateUrl($value)) { - return true; - } - } - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - // An Object or a Link - if (\is_object($value)) { - return Util::validateLink($value) - || Util::validateObject($value); - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/ContentMapValidator.php b/plugins/ActivityPub/Util/Type/Validator/ContentMapValidator.php deleted file mode 100644 index 9bc1378b78..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/ContentMapValidator.php +++ /dev/null @@ -1,34 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\ContentMapValidator is a dedicated - * validator for contentMap attribute. - */ -class ContentMapValidator extends ValidatorTools -{ - /** - * Validate a contentMap value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - return $this->validateMap('content', $value, $container); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/ContentValidator.php b/plugins/ActivityPub/Util/Type/Validator/ContentValidator.php deleted file mode 100644 index 8907938567..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/ContentValidator.php +++ /dev/null @@ -1,32 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\ContentValidator is a dedicated - * validator for content attribute. - */ -class ContentValidator implements ValidatorInterface -{ - /** - * Validate a content attribute value - */ - public function validate(mixed $value, mixed $container): bool - { - // Must be a string or null - return (bool) (\is_null($value) || \is_string($value)); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/ContextValidator.php b/plugins/ActivityPub/Util/Type/Validator/ContextValidator.php deleted file mode 100644 index 41db6939b0..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/ContextValidator.php +++ /dev/null @@ -1,50 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\ContextValidator is a dedicated - * validator for context attribute. - */ -class ContextValidator implements ValidatorInterface -{ - /** - * Validate a context attribute value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // URL - if (Util::validateUrl($value)) { - return true; - } - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - // Link or Object - if (\is_object($value)) { - return Util::validateLink($value) - || Util::validateObject($value); - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/CurrentValidator.php b/plugins/ActivityPub/Util/Type/Validator/CurrentValidator.php deleted file mode 100644 index 6131f31fb0..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/CurrentValidator.php +++ /dev/null @@ -1,46 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Collection; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\CurrentValidator is a dedicated - * validator for current attribute. - */ -class CurrentValidator implements ValidatorInterface -{ - /** - * Validate a current attribute value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container must be a Collection - Util::subclassOf($container, Collection::class, true); - - // URL - if (Util::validateUrl($value)) { - return true; - } - - // Link or CollectionPage - return Util::validateLink($value) - || Util::validateCollectionPage($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/DeletedValidator.php b/plugins/ActivityPub/Util/Type/Validator/DeletedValidator.php deleted file mode 100644 index 091d663085..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/DeletedValidator.php +++ /dev/null @@ -1,48 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Extended\Object\Tombstone; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\DeletedValidator is a dedicated - * validator for deleted attribute. - */ -class DeletedValidator implements ValidatorInterface -{ - /** - * Validate a DELETED attribute value - * - * @param mixed $container A Tombstone type - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is a Tombstone type - Util::subclassOf($container, Tombstone::class, true); - - if (\is_string($value)) { - // MUST be a datetime - if (Util::validateDatetime($value)) { - return true; - } - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/DescribesValidator.php b/plugins/ActivityPub/Util/Type/Validator/DescribesValidator.php deleted file mode 100644 index 48e26704aa..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/DescribesValidator.php +++ /dev/null @@ -1,47 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Extended\Object\Profile; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\DescribesValidator is a dedicated - * validator for describes attribute. - */ -class DescribesValidator implements ValidatorInterface -{ - /** - * Validate an DESCRIBES attribute value - * - * @param mixed $container A Profile type - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is a Tombstone type - Util::subclassOf($container, Profile::class, true); - - if (\is_object($value)) { - // MUST be an Object - return Util::subclassOf($value, ObjectType::class, true); - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/DurationValidator.php b/plugins/ActivityPub/Util/Type/Validator/DurationValidator.php deleted file mode 100644 index 7bce136c31..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/DurationValidator.php +++ /dev/null @@ -1,44 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\DurationValidator is a dedicated - * validator for duration attribute. - */ -class DurationValidator implements ValidatorInterface -{ - /** - * Validate an DURATION attribute value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container has an ObjectType type - Util::subclassOf($container, ObjectType::class, true); - - if (\is_string($value)) { - // MUST be an XML 8601 Duration formatted string - return Util::isDuration($value, true); - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/EndTimeValidator.php b/plugins/ActivityPub/Util/Type/Validator/EndTimeValidator.php deleted file mode 100644 index c11ddaccf4..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/EndTimeValidator.php +++ /dev/null @@ -1,40 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\EndTimeValidator is a dedicated - * validator for endTime attribute. - */ -class EndTimeValidator implements ValidatorInterface -{ - /** - * Validate an ENDTIME attribute value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container has an ObjectType type - Util::subclassOf($container, ObjectType::class, true); - - // MUST be a valid xsd:dateTime - return Util::validateDatetime($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/EndpointsValidator.php b/plugins/ActivityPub/Util/Type/Validator/EndpointsValidator.php deleted file mode 100644 index c0dc111319..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/EndpointsValidator.php +++ /dev/null @@ -1,75 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Extended\AbstractActor; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\EndpointsValidator is a dedicated - * validator for endpoints attribute. - */ -class EndpointsValidator implements ValidatorInterface -{ - /** - * Validate ENDPOINTS value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is an AbstractActor type - Util::subclassOf($container, AbstractActor::class, true); - - // A link to a JSON-LD document - if (Util::validateUrl($value)) { - return true; - } - - // A map - return \is_array($value) && $this->validateObject($value); - } - - /** - * Validate endpoints mapping - */ - protected function validateObject(array $item): bool - { - foreach ($item as $key => $value) { - switch ($key) { - case 'proxyUrl': - case 'oauthAuthorizationEndpoint': - case 'oauthTokenEndpoint': - case 'provideClientKey': - case 'signClientKey': - case 'sharedInbox': - if (!Util::validateUrl($value)) { - return false; - } - break; - // All other keys are not allowed - default: - return false; - } - - if (is_numeric($key)) { - return false; - } - } - - return true; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/FirstValidator.php b/plugins/ActivityPub/Util/Type/Validator/FirstValidator.php deleted file mode 100644 index f67b4668a6..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/FirstValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\FirstValidator is a dedicated - * validator for first attribute. - */ -class FirstValidator extends CurrentValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/FollowersValidator.php b/plugins/ActivityPub/Util/Type/Validator/FollowersValidator.php deleted file mode 100644 index d1fb0808c3..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/FollowersValidator.php +++ /dev/null @@ -1,65 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Collection; -use Plugin\ActivityPub\Util\Type\Core\OrderedCollection; -use Plugin\ActivityPub\Util\Type\Extended\AbstractActor; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\FollowersValidator is a dedicated - * validator for followers attribute. - */ -class FollowersValidator implements ValidatorInterface -{ - /** - * Validate a FOLLOWERS attribute value - * - * @throws Exception - * - * @todo Support indirect reference for followers attribute? - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is an AbstractActor type - Util::subclassOf($container, AbstractActor::class, true); - - if (\is_string($value)) { - return Util::validateUrl($value); - } - - // A collection - return \is_object($value) && $this->validateObject($value); - } - - /** - * Validate that it is an OrderedCollection or a Collection - * - * @throws Exception - * @throws Exception - */ - protected function validateObject(object $collection): bool - { - return Util::subclassOf( - $collection, - OrderedCollection::class, - ) || Util::subclassOf( - $collection, - Collection::class, - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/FollowingValidator.php b/plugins/ActivityPub/Util/Type/Validator/FollowingValidator.php deleted file mode 100644 index 9c7c39c808..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/FollowingValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\FollowingValidator is a dedicated - * validator for followers attribute. - */ -class FollowingValidator extends FollowersValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/FormerTypeValidator.php b/plugins/ActivityPub/Util/Type/Validator/FormerTypeValidator.php deleted file mode 100644 index b58c8a943e..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/FormerTypeValidator.php +++ /dev/null @@ -1,44 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Extended\Object\Tombstone; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\FormerTypeValidator is a dedicated - * validator for formerType attribute. - */ -class FormerTypeValidator implements ValidatorInterface -{ - /** - * Validate a formerType attribute value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container has a Tombstone type - Util::subclassOf($container, Tombstone::class, true); - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - // MUST be a valid Object type - return Util::isObjectType($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/GeneratorValidator.php b/plugins/ActivityPub/Util/Type/Validator/GeneratorValidator.php deleted file mode 100644 index e6f3b11080..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/GeneratorValidator.php +++ /dev/null @@ -1,48 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\GeneratorValidator is a dedicated - * validator for generator attribute. - */ -class GeneratorValidator implements ValidatorInterface -{ - /** - * Validate a generator attribute value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container has an ObjectType type - Util::subclassOf($container, ObjectType::class, true); - - if (Util::validateUrl($value)) { - return true; - } - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - // MUST be a valid Actor type - return Util::isActorType($value) || Util::validateLink($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/HeightValidator.php b/plugins/ActivityPub/Util/Type/Validator/HeightValidator.php deleted file mode 100644 index 3a7ecf8e1f..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/HeightValidator.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Link; -use Plugin\ActivityPub\Util\Type\Extended\Object\Image; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\HeightValidator is a dedicated - * validator for height attribute. - */ -class HeightValidator implements ValidatorInterface -{ - /** - * Validate height value - * - * @param mixed $container An object - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is a Link - Util::subclassOf($container, [Link::class, Image::class], true); - - // Must be a non-negative integer - return Util::validateNonNegativeInteger($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/HrefValidator.php b/plugins/ActivityPub/Util/Type/Validator/HrefValidator.php deleted file mode 100644 index 9c3c1bf483..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/HrefValidator.php +++ /dev/null @@ -1,48 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Link; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\HrefValidator is a dedicated - * validator for href attribute. - */ -class HrefValidator implements ValidatorInterface -{ - /** - * Validate href value - * - * @param mixed $container An object - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is a Link or an Object - Util::subclassOf( - $container, - [Link::class, ObjectType::class], - true, - ); - - // Must be a valid URL or a valid magnet link - return Util::validateUrl($value) - || Util::validateMagnet($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/HreflangValidator.php b/plugins/ActivityPub/Util/Type/Validator/HreflangValidator.php deleted file mode 100644 index e60c80d7e1..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/HreflangValidator.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Link; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\HreflangValidator is a dedicated - * validator for hreflang attribute. - */ -class HreflangValidator implements ValidatorInterface -{ - /** - * Validate href value - * - * @param mixed $container An object - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is a Link - Util::subclassOf($container, Link::class, true); - - // Must be a valid URL - return Util::validateBcp47($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/IconValidator.php b/plugins/ActivityPub/Util/Type/Validator/IconValidator.php deleted file mode 100644 index fc043d6028..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/IconValidator.php +++ /dev/null @@ -1,82 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\IconValidator is a dedicated - * validator for icon attribute. - */ -class IconValidator implements ValidatorInterface -{ - /** - * Validate icon item - * - * @param mixed $container An object - * - * @throws Exception - * - * @todo Implement size checks - * @todo Support Image objects and Link objects - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is a ObjectType - Util::subclassOf($container, ObjectType::class, true); - - if (\is_string($value)) { - return Util::validateUrl($value); - } - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - if (\is_array($value)) { - foreach ($value as $item) { - if (\is_array($item)) { - $item = Util::arrayToType($item); - } - - if (\is_string($item) && Util::validateUrl($item)) { - continue; - } - - if (!$this->validateObject($item)) { - return false; - } - } - - return true; - } - - // Must be an Image or a Link - return $this->validateObject($value); - } - - /** - * Validate an object format - * - * @throws Exception - */ - protected function validateObject(object $item): bool - { - return Util::validateLink($item) - || Util::isType($item, 'Image'); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/IdValidator.php b/plugins/ActivityPub/Util/Type/Validator/IdValidator.php deleted file mode 100644 index f6aa3b337a..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/IdValidator.php +++ /dev/null @@ -1,35 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\IdValidator is a dedicated - * validator for id attribute. - */ -class IdValidator implements ValidatorInterface -{ - /** - * Validate an ID attribute value - * - * @param mixed $container An object - */ - public function validate(mixed $value, mixed $container): bool - { - return Util::validateUrl($value) - || Util::validateOstatusTag($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/ImageValidator.php b/plugins/ActivityPub/Util/Type/Validator/ImageValidator.php deleted file mode 100644 index 72475b43c2..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/ImageValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\ImageValidator is a dedicated - * validator for image attribute. - */ -class ImageValidator extends IconValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/InReplyToValidator.php b/plugins/ActivityPub/Util/Type/Validator/InReplyToValidator.php deleted file mode 100644 index 4322676d9c..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/InReplyToValidator.php +++ /dev/null @@ -1,63 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\InReplyToValidator is a dedicated - * validator for inReplyTo attribute. - */ -class InReplyToValidator implements ValidatorInterface -{ - /** - * Validate inReplyTo value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container is an ObjectType - Util::subclassOf( - $container, - ObjectType::class, - true, - ); - - // null - if (\is_null($value)) { - return true; - } - - // URL - if (\is_string($value)) { - return Util::validateUrl($value); - } - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - // Link or Object - if (\is_object($value)) { - return Util::validateLink($value) - || Util::isObjectType($value); - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/InboxValidator.php b/plugins/ActivityPub/Util/Type/Validator/InboxValidator.php deleted file mode 100644 index d44837e8c1..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/InboxValidator.php +++ /dev/null @@ -1,64 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\OrderedCollection; -use Plugin\ActivityPub\Util\Type\Core\OrderedCollectionPage; -use Plugin\ActivityPub\Util\Type\Extended\AbstractActor; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\InboxValidator is a dedicated - * validator for inbox attribute. - */ -class InboxValidator implements ValidatorInterface -{ - /** - * Validate a inbox attribute value - * - * @throws Exception - * - * @todo Support indirect reference for followers attribute? - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is an AbstractActor type - Util::subclassOf($container, AbstractActor::class, true); - - if (\is_string($value)) { - return Util::validateUrl($value); - } - - // An OrderedCollection - return \is_object($value) && $this->validateObject($value); - } - - /** - * Validate that it is an OrderedCollection - * - * @throws Exception - */ - protected function validateObject(object $collection): bool - { - return Util::subclassOf( - $collection, - OrderedCollection::class, - ) || Util::subclassOf( - $collection, - OrderedCollectionPage::class, - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/InstrumentValidator.php b/plugins/ActivityPub/Util/Type/Validator/InstrumentValidator.php deleted file mode 100644 index 7b82ed08c4..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/InstrumentValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\InstrumentValidator is a dedicated - * validator for instrument attribute. - */ -class InstrumentValidator extends ActorValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/ItemsValidator.php b/plugins/ActivityPub/Util/Type/Validator/ItemsValidator.php deleted file mode 100644 index f479e80ec2..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/ItemsValidator.php +++ /dev/null @@ -1,76 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Collection; -use Plugin\ActivityPub\Util\Type\Core\Link; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\ItemsValidator is a dedicated - * validator for items attribute. - */ -class ItemsValidator extends ValidatorTools -{ - /** - * Validate items value - * - * @param mixed $container A Collection type - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is a Collection - Util::subclassOf( - $container, - [Collection::class], - true, - ); - - // URL type - if (\is_string($value)) { - return Util::validateUrl($value); - } - - if (\is_array($value)) { - // Empty array - if (!\count($value)) { - return true; - } - $value = Util::arrayToType($value); - } - - // Link type - if (\is_object($value)) { - return Util::subclassOf($value, Link::class, true); - } - - // A Collection - if (!\is_array($value)) { - return false; - } - - if (!\count($value)) { - return false; - } - - return $this->validateObjectCollection( - $value, - $this->getCollectionItemsValidator(), - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/LastValidator.php b/plugins/ActivityPub/Util/Type/Validator/LastValidator.php deleted file mode 100644 index 575f10c9b6..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/LastValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\LastValidator is a dedicated - * validator for last attribute. - */ -class LastValidator extends CurrentValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/LatitudeValidator.php b/plugins/ActivityPub/Util/Type/Validator/LatitudeValidator.php deleted file mode 100644 index 45c176caa8..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/LatitudeValidator.php +++ /dev/null @@ -1,41 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Extended\Object\Place; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\LatitudeValidator is a dedicated - * validator for latitude attribute. - */ -class LatitudeValidator implements ValidatorInterface -{ - /** - * Validate a latitude attribute value - * - * @param mixed $container An object - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is a Place - Util::subclassOf($container, Place::class, true); - - return Util::between($value, -90, 90); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/LikedValidator.php b/plugins/ActivityPub/Util/Type/Validator/LikedValidator.php deleted file mode 100644 index e3e570e11f..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/LikedValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\LikedValidator is a dedicated - * validator for liked attribute. - */ -class LikedValidator extends FollowersValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/LocationValidator.php b/plugins/ActivityPub/Util/Type/Validator/LocationValidator.php deleted file mode 100644 index 158c347a33..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/LocationValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\LocationValidator is a dedicated - * validator for location attribute. - */ -class LocationValidator extends InReplyToValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/LongitudeValidator.php b/plugins/ActivityPub/Util/Type/Validator/LongitudeValidator.php deleted file mode 100644 index 98e3ae662b..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/LongitudeValidator.php +++ /dev/null @@ -1,41 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Extended\Object\Place; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\LongitudeValidator is a dedicated - * validator for longitude attribute. - */ -class LongitudeValidator implements ValidatorInterface -{ - /** - * Validate a longitude value - * - * @param mixed $container An object - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is a Place - Util::subclassOf($container, Place::class, true); - - return Util::between($value, -180, 180); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/MediaTypeValidator.php b/plugins/ActivityPub/Util/Type/Validator/MediaTypeValidator.php deleted file mode 100644 index d5c5767db8..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/MediaTypeValidator.php +++ /dev/null @@ -1,33 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\MediaTypeValidator is a dedicated - * validator for mediaType attribute. - */ -class MediaTypeValidator implements ValidatorInterface -{ - /** - * Validate a mediaType attribute value - */ - public function validate(mixed $value, mixed $container): bool - { - return \is_null($value) - || Util::validateMediaType($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/NameMapValidator.php b/plugins/ActivityPub/Util/Type/Validator/NameMapValidator.php deleted file mode 100644 index 7a9de91729..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/NameMapValidator.php +++ /dev/null @@ -1,34 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\NameMapValidator is a dedicated - * validator for nameMap attribute. - */ -class NameMapValidator extends ValidatorTools -{ - /** - * Validate a nameMap value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - return $this->validateMap('name', $value, $container); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/NameValidator.php b/plugins/ActivityPub/Util/Type/Validator/NameValidator.php deleted file mode 100644 index 3e4604ef96..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/NameValidator.php +++ /dev/null @@ -1,36 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\NameValidator is a dedicated - * validator for name attribute. - */ -class NameValidator implements ValidatorInterface -{ - /** - * Validate a name attribute value - */ - public function validate(mixed $value, mixed $container): bool - { - if (\is_null($value) || $value === '') { - return true; - } - - return Util::validatePlainText($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/NextValidator.php b/plugins/ActivityPub/Util/Type/Validator/NextValidator.php deleted file mode 100644 index 8053d20ddd..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/NextValidator.php +++ /dev/null @@ -1,59 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\CollectionPage; -use Plugin\ActivityPub\Util\Type\Core\OrderedCollectionPage; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\NextValidator is a dedicated - * validator for next attribute. - */ -class NextValidator implements ValidatorInterface -{ - /** - * Validate a next value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container is CollectionPage or OrderedCollectionPage type - Util::subclassOf( - $container, - [CollectionPage::class, OrderedCollectionPage::class], - true, - ); - - // URL - if (\is_string($value)) { - return Util::validateUrl($value); - } - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - // Link or Collection - if (\is_object($value)) { - return Util::validateLink($value) - || Util::validateCollectionPage($value); - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/ObjectValidator.php b/plugins/ActivityPub/Util/Type/Validator/ObjectValidator.php deleted file mode 100644 index c22700d8cd..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/ObjectValidator.php +++ /dev/null @@ -1,82 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Activity; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\ObjectValidator is a dedicated - * validator for object attribute. - */ -class ObjectValidator implements ValidatorInterface -{ - /** - * Validate an object value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container is an ObjectType or a Link - Util::subclassOf( - $container, - [Activity::class], - true, - ); - - // URL - if (\is_string($value)) { - return Util::validateUrl($value) - || Util::validateOstatusTag($value); - } - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - // Link or Object - if (\is_object($value)) { - return Util::validateLink($value) - || Util::isObjectType($value); - } - - // Collection - if (\is_array($value)) { - foreach ($value as $item) { - if (\is_string($item) && Util::validateUrl($item)) { - continue; - } - - if (\is_array($item)) { - $item = Util::arrayToType($item); - } - - if (\is_object($item) - && Util::subclassOf($item, [ObjectType::class], true)) { - continue; - } - - return false; - } - - return \count($value) > 0; - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/OneOfValidator.php b/plugins/ActivityPub/Util/Type/Validator/OneOfValidator.php deleted file mode 100644 index 16c1b30d56..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/OneOfValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\OneOfValidator is a dedicated - * validator for oneOf attribute. - */ -class OneOfValidator extends AnyOfValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/OrderedItemsValidator.php b/plugins/ActivityPub/Util/Type/Validator/OrderedItemsValidator.php deleted file mode 100644 index 0b72607e38..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/OrderedItemsValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\OrderedItemsValidator is a dedicated - * validator for orderedItems attribute. - */ -class OrderedItemsValidator extends ItemsValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/OriginValidator.php b/plugins/ActivityPub/Util/Type/Validator/OriginValidator.php deleted file mode 100644 index 05430199bc..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/OriginValidator.php +++ /dev/null @@ -1,58 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Activity; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\OriginValidator is a dedicated - * validator for origin attribute. - */ -class OriginValidator implements ValidatorInterface -{ - /** - * Validate an origin value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container is an Activity - Util::subclassOf( - $container, - [Activity::class], - true, - ); - - // URL - if (\is_string($value)) { - return Util::validateUrl($value); - } - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - // Link or Object - if (\is_object($value)) { - return Util::validateLink($value) - || Util::isObjectType($value); - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/OutboxValidator.php b/plugins/ActivityPub/Util/Type/Validator/OutboxValidator.php deleted file mode 100644 index a4041c8718..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/OutboxValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\OutboxValidator is a dedicated - * validator for outbox attribute. - */ -class OutboxValidator extends InboxValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/PartOfValidator.php b/plugins/ActivityPub/Util/Type/Validator/PartOfValidator.php deleted file mode 100644 index 793d836019..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/PartOfValidator.php +++ /dev/null @@ -1,61 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\CollectionPage; -use Plugin\ActivityPub\Util\Type\Core\OrderedCollectionPage; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\PartOfValidator is a dedicated - * validator for partOf attribute. - */ -class PartOfValidator implements ValidatorInterface -{ - /** - * Validate a partOf value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container is CollectionPage or OrderedCollectionPage type - Util::subclassOf( - $container, - [ - CollectionPage::class, OrderedCollectionPage::class, - ], - true, - ); - - // URL - if (\is_string($value)) { - return Util::validateUrl($value); - } - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - // Link or Collection - if (\is_object($value)) { - return Util::validateLink($value) - || Util::validateCollection($value); - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/PreferredUsernameValidator.php b/plugins/ActivityPub/Util/Type/Validator/PreferredUsernameValidator.php deleted file mode 100644 index 485742dd61..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/PreferredUsernameValidator.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Extended\AbstractActor; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\PreferredUsernameValidator is a dedicated - * validator for preferredUsername attribute. - */ -class PreferredUsernameValidator extends ValidatorTools -{ - /** - * Validate preferredUsername value - * - * @param mixed $container An Actor - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is an Actor - Util::subclassOf($container, AbstractActor::class, true); - - return $this->validateString( - $value, - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/PrevValidator.php b/plugins/ActivityPub/Util/Type/Validator/PrevValidator.php deleted file mode 100644 index a126607073..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/PrevValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\PrevValidator is a dedicated - * validator for prev attribute. - */ -class PrevValidator extends NextValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/PreviewValidator.php b/plugins/ActivityPub/Util/Type/Validator/PreviewValidator.php deleted file mode 100644 index 1bd999235c..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/PreviewValidator.php +++ /dev/null @@ -1,59 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Link; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\PreviewValidator is a dedicated - * validator for preview attribute. - */ -class PreviewValidator implements ValidatorInterface -{ - /** - * Validate a preview value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container is an ObjectType or a Link - Util::subclassOf( - $container, - [ObjectType::class, Link::class], - true, - ); - - // URL - if (\is_string($value)) { - return Util::validateUrl($value); - } - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - // Link or Object - if (\is_object($value)) { - return Util::validateLink($value) - || Util::isObjectType($value); - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/PublishedValidator.php b/plugins/ActivityPub/Util/Type/Validator/PublishedValidator.php deleted file mode 100644 index 3279f580e9..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/PublishedValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\PublishedValidator is a dedicated - * validator for published attribute. - */ -class PublishedValidator extends EndTimeValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/RadiusValidator.php b/plugins/ActivityPub/Util/Type/Validator/RadiusValidator.php deleted file mode 100644 index 3d5b71ebe5..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/RadiusValidator.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Extended\Object\Place; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\RadiusValidator is a dedicated - * validator for radius attribute. - */ -class RadiusValidator implements ValidatorInterface -{ - /** - * Validate radius value - * - * @param mixed $container A Place - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container must be Place - Util::subclassOf($container, Place::class, true); - - // Must be a valid radius - return Util::validateNonNegativeNumber($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/RelValidator.php b/plugins/ActivityPub/Util/Type/Validator/RelValidator.php deleted file mode 100644 index ce6d1abba2..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/RelValidator.php +++ /dev/null @@ -1,53 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Link; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\RelValidator is a dedicated - * validator for rel attribute. - */ -class RelValidator implements ValidatorInterface -{ - /** - * Validate rel value - * - * @param mixed $container A Link - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is a Link - Util::subclassOf($container, Link::class, true); - - // Must be a valid Rel - if (\is_array($value)) { - foreach ($value as $key => $item) { - if (!\is_int($key) - || !Util::validateRel($item)) { - return false; - } - } - - return true; - } - - return Util::validateRel($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/RepliesValidator.php b/plugins/ActivityPub/Util/Type/Validator/RepliesValidator.php deleted file mode 100644 index 59813a7fc0..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/RepliesValidator.php +++ /dev/null @@ -1,58 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\RepliesValidator is a dedicated - * validator for replies attribute. - */ -class RepliesValidator implements ValidatorInterface -{ - /** - * Validate replies value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container is an ObjectType - Util::subclassOf( - $container, - ObjectType::class, - true, - ); - - // URL - if (\is_string($value)) { - return Util::validateUrl($value); - } - - if (\is_array($value)) { - $value = Util::arrayToType($value); - } - - // Link or Collection - if (\is_object($value)) { - return Util::validateLink($value) - || Util::validateCollection($value); - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/ResultValidator.php b/plugins/ActivityPub/Util/Type/Validator/ResultValidator.php deleted file mode 100644 index b06b7b0ed4..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/ResultValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\ResultValidator is a dedicated - * validator for result attribute. - */ -class ResultValidator extends OriginValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/SourceValidator.php b/plugins/ActivityPub/Util/Type/Validator/SourceValidator.php deleted file mode 100644 index 1c087ad78b..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/SourceValidator.php +++ /dev/null @@ -1,55 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\SourceValidator is a dedicated - * validator for source attribute. - */ -class SourceValidator implements ValidatorInterface -{ - /** - * Validate source value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container is an ObjectType - Util::subclassOf( - $container, - ObjectType::class, - true, - ); - - if (\is_array($value)) { - $value = (object) $value; - } - - if (\is_object($value)) { - return Util::hasProperties( - $value, - ['content', 'mediaType'], - true, - ); - } - - return false; - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/StartIndexValidator.php b/plugins/ActivityPub/Util/Type/Validator/StartIndexValidator.php deleted file mode 100644 index 9e5404a934..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/StartIndexValidator.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\OrderedCollectionPage; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\StartIndexValidator is a dedicated - * validator for startIndex attribute. - */ -class StartIndexValidator implements ValidatorInterface -{ - /** - * Validate startIndex value - * - * @param mixed $container An OrderedCollectionPage - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container type is OrderedCollectionPage - Util::subclassOf($container, OrderedCollectionPage::class, true); - - // Must be a non-negative integer - return Util::validateNonNegativeInteger($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/StartTimeValidator.php b/plugins/ActivityPub/Util/Type/Validator/StartTimeValidator.php deleted file mode 100644 index 67b624b35f..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/StartTimeValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\StartTimeValidator is a dedicated - * validator for startTime attribute. - */ -class StartTimeValidator extends EndTimeValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/StreamsValidator.php b/plugins/ActivityPub/Util/Type/Validator/StreamsValidator.php deleted file mode 100644 index f835679997..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/StreamsValidator.php +++ /dev/null @@ -1,43 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Extended\AbstractActor; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\StreamsValidator is a dedicated - * validator for streams attribute. - */ -class StreamsValidator implements ValidatorInterface -{ - /** - * Validate streams value - * - * @param mixed $container An object - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is an Actor - Util::subclassOf($container, AbstractActor::class, true); - - // Must be an array - // @todo Better validation should be done - return \is_array($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/SummaryMapValidator.php b/plugins/ActivityPub/Util/Type/Validator/SummaryMapValidator.php deleted file mode 100644 index 0e2e73c118..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/SummaryMapValidator.php +++ /dev/null @@ -1,36 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\SummaryMapValidator is a dedicated - * validator for summaryMap attribute. - */ -class SummaryMapValidator extends ValidatorTools -{ - /** - * Validate a summaryMap attribute value - * - * @param mixed $container An Object type - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - return $this->validateMap('summary', $value, $container); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/SummaryValidator.php b/plugins/ActivityPub/Util/Type/Validator/SummaryValidator.php deleted file mode 100644 index 7c92e07f5e..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/SummaryValidator.php +++ /dev/null @@ -1,40 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\SummaryValidator is a dedicated - * validator for summary attribute. - */ -class SummaryValidator implements ValidatorInterface -{ - /** - * Validate a summary attribute value - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is an ObjectType type - Util::subclassOf($container, ObjectType::class, true); - - // Must be a string - return \is_null($value) || \is_string($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/TagValidator.php b/plugins/ActivityPub/Util/Type/Validator/TagValidator.php deleted file mode 100644 index e76f9fceb3..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/TagValidator.php +++ /dev/null @@ -1,40 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\TagValidator is a dedicated - * validator for tag attribute. - */ -class TagValidator extends ValidatorTools -{ - /** - * Validate a tag value - * - * @param mixed $container An Object type - */ - public function validate(mixed $value, mixed $container): bool - { - if (!\count($value)) { - return true; - } - - return $this->validateObjectCollection( - $value, - $this->getCollectionItemsValidator(), - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/TargetValidator.php b/plugins/ActivityPub/Util/Type/Validator/TargetValidator.php deleted file mode 100644 index e1440881fb..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/TargetValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\TargetValidator is a dedicated - * validator for target attribute. - */ -class TargetValidator extends ActorValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/ToValidator.php b/plugins/ActivityPub/Util/Type/Validator/ToValidator.php deleted file mode 100644 index 90e6bec303..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/ToValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\ToValidator is a dedicated - * validator for to attribute. - */ -class ToValidator extends BtoValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/TotalItemsValidator.php b/plugins/ActivityPub/Util/Type/Validator/TotalItemsValidator.php deleted file mode 100644 index eba0a03725..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/TotalItemsValidator.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Collection; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\TotalItemsValidator is a dedicated - * validator for totalItems attribute. - */ -class TotalItemsValidator implements ValidatorInterface -{ - /** - * Validate totalItems value - * - * @param mixed $container A Collection - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container type is Collection - Util::subclassOf($container, Collection::class, true); - - // Must be a non-negative integer - return Util::validateNonNegativeInteger($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/TypeValidator.php b/plugins/ActivityPub/Util/Type/Validator/TypeValidator.php deleted file mode 100644 index 1e02c90a7c..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/TypeValidator.php +++ /dev/null @@ -1,48 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Link; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorTools; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\TypeValidator is a dedicated - * validator for type attribute. - */ -class TypeValidator extends ValidatorTools -{ - /** - * Validate a type value - * - * @param mixed $container An Object type - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is an ObjectType or a Link - Util::subclassOf( - $container, - [ObjectType::class, Link::class], - true, - ); - - return $this->validateString( - $value, - ); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/UnitsValidator.php b/plugins/ActivityPub/Util/Type/Validator/UnitsValidator.php deleted file mode 100644 index 359e92ae08..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/UnitsValidator.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Extended\Object\Place; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\UnitsValidator is a dedicated - * validator for units attribute. - */ -class UnitsValidator implements ValidatorInterface -{ - /** - * Validate units value - * - * @param mixed $container A Place - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Container must be Place - Util::subclassOf($container, Place::class, true); - - // Must be a valid units - return Util::validateUnits($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/UpdatedValidator.php b/plugins/ActivityPub/Util/Type/Validator/UpdatedValidator.php deleted file mode 100644 index 8b5baa7873..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/UpdatedValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\UpdatedValidator is a dedicated - * validator for updated attribute. - */ -class UpdatedValidator extends EndTimeValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/Validator/UrlValidator.php b/plugins/ActivityPub/Util/Type/Validator/UrlValidator.php deleted file mode 100644 index 2cc7bb17af..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/UrlValidator.php +++ /dev/null @@ -1,65 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\Link; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Util; -use Plugin\ActivityPub\Util\Type\ValidatorInterface; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\UrlValidator is a dedicated - * validator for url attribute. - */ -class UrlValidator implements ValidatorInterface -{ - /** - * Validate url value - * - * @param mixed $container A Link - * - * @throws Exception - */ - public function validate(mixed $value, mixed $container): bool - { - // Validate that container is an ObjectType - Util::subclassOf($container, ObjectType::class, true); - - // Must be a valid URL - if (\is_array($value) && \is_int(key($value))) { - foreach ($value as $key => $item) { - if (!$this->validateUrlOrLink($item)) { - return false; - } - } - - return true; - } - - return $this->validateUrlOrLink($value); - } - - /** - * Validate that a value is a Link or a URL - * - * @throws Exception - */ - protected function validateUrlOrLink(Link|string $value): bool - { - return Util::validateUrl($value) - || Util::validateLink($value) - || Util::validateMagnet($value); - } -} diff --git a/plugins/ActivityPub/Util/Type/Validator/WidthValidator.php b/plugins/ActivityPub/Util/Type/Validator/WidthValidator.php deleted file mode 100644 index db7aa3a0a9..0000000000 --- a/plugins/ActivityPub/Util/Type/Validator/WidthValidator.php +++ /dev/null @@ -1,22 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type\Validator; - -/** - * \Plugin\ActivityPub\Util\Type\Validator\WidthValidator is a dedicated - * validator for width attribute. - */ -class WidthValidator extends HeightValidator -{ -} diff --git a/plugins/ActivityPub/Util/Type/ValidatorInterface.php b/plugins/ActivityPub/Util/Type/ValidatorInterface.php deleted file mode 100644 index 29ebd891bf..0000000000 --- a/plugins/ActivityPub/Util/Type/ValidatorInterface.php +++ /dev/null @@ -1,23 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type; - -/** - * \Plugin\ActivityPub\Util\Type\ValidatorInterface specifies methods that must be - * implemented for attribute (property) validation. - */ -interface ValidatorInterface -{ - public function validate(mixed $value, mixed $container): bool; -} diff --git a/plugins/ActivityPub/Util/Type/ValidatorTools.php b/plugins/ActivityPub/Util/Type/ValidatorTools.php deleted file mode 100644 index ec0de6796e..0000000000 --- a/plugins/ActivityPub/Util/Type/ValidatorTools.php +++ /dev/null @@ -1,292 +0,0 @@ -. - */ - -namespace Plugin\ActivityPub\Util\Type; - -use Exception; -use Plugin\ActivityPub\Util\Type\Core\ObjectType; -use Plugin\ActivityPub\Util\Type\Extended\AbstractActor; - -/** - * \Plugin\ActivityPub\Util\Type\ValidatorTools is an abstract class for - * attribute validation. - * Its purpose is to be extended by Plugin\ActivityPub\Util\Type\Validator\* - * classes. - * It provides some methods to make some regular validations. - * It implements \Plugin\ActivityPub\Util\Type\ValidatorInterface. - */ -abstract class ValidatorTools implements ValidatorInterface -{ - /** - * Validate a map attribute value. - * - * @param string $type An attribute name - * @param object $container A valid container - * - * @throws Exception - */ - protected function validateMap(string $type, mixed $map, object $container): bool - { - // A map - if (!\is_array($map)) { - return false; - } - - foreach ($map as $key => $value) { - if (!Util::validateBcp47($key) - || !Validator::validate($type, $value, $container) - ) { - return false; - } - } - - return true; - } - - /** - * Validate an attribute value - * - * @param mixed $container An object - * @param callable $callback A dedicated validator - * - * @throws Exception - */ - public function validateListOrObject(mixed $value, mixed $container, callable $callback): bool - { - Util::subclassOf($container, ObjectType::class, true); - - // Not supported: Can be a JSON string - // Must be a value like a URL, a text - if (\is_string($value)) { - return $callback($value); - } - - if (\is_array($value)) { - // Can be empty - if (!\count($value)) { - return true; - } - - // A collection - if (\is_int(key($value))) { - return $this->validateObjectCollection($value, $callback); - } - - $value = Util::arrayToType($value); - } - - if (!\is_object($value)) { - return false; - } - - return $callback($value); - } - - /** - * Validate a list of Collection - * - * @param callable $callback A dedicated validator - */ - protected function validateObjectCollection(array $collection, callable $callback): bool - { - foreach ($collection as $item) { - if ($callback($item)) { - continue; - } - - return false; - } - - return true; - } - - /** - * Validate that a value is a string - * - * @throws Exception - */ - protected function validateString(string $value): bool - { - if (!\is_string($value) || $value === '') { - throw new Exception( - sprintf( - 'Value must be a non-empty string. Given: "%s"', - print_r($value, true), - ), - ); - } - - return true; - } - - /** - * A callback function for validateListOrObject method - * - * It validates a Link or a named object - */ - protected function getLinkOrNamedObjectValidator(): callable - { - return - /** The implementation lambda */ - static function ($item): bool { - if (\is_string($item)) { - return Util::validateUrl($item); - } - - if (\is_array($item)) { - $item = Util::arrayToType($item); - } - - if (\is_object($item)) { - Util::hasProperties($item, ['type'], true); - - // Validate Link type - if ($item->type === 'Link') { - return Util::validateLink($item); - } - - // Validate Object type - Util::hasProperties($item, ['name'], true); - - return \is_string($item->name); - } - - return false; - }; - } - - /** - * A callback function for validateListOrObject method - * - * Validate a reference with a Link or an Object with a URL - */ - protected function getLinkOrUrlObjectValidator(): callable - { - return - /** The implementation lambda */ - static function ($item): bool { - if (\is_array($item)) { - $item = Util::arrayToType($item); - } - - if (\is_object($item) - && Util::isLinkOrUrlObject($item)) { - return true; - } - - return (bool) (Util::validateUrl($item)); - }; - } - - /** - * A callback function for attachment validation - * - * Validate a reference with a Link, an Object with a URL - * or an ObjectType - */ - protected function getAttachmentValidator(): callable - { - return - /** The implementation lambda */ - static function ($item): bool { - if (\is_array($item)) { - $item = Util::arrayToType($item); - } - - if (\is_object($item)) { - if (Util::isLinkOrUrlObject($item)) { - return true; - } - - return $item instanceof ObjectType; - } - - return (bool) (Util::validateUrl($item)); - }; - } - - /** - * Validate that a Question answer is a Note - */ - protected function getQuestionAnswerValidator(): callable - { - return - /** The implementation lambda */ - static function ($item): bool { - if (\is_array($item)) { - $item = Util::arrayToType($item); - } - - if (!\is_object($item)) { - return false; - } - - Util::hasProperties($item, ['type', 'name'], true); - - return $item->type === 'Note' - && is_scalar($item->name); - }; - } - - /** - * Validate that a list of items is valid - */ - protected function getCollectionItemsValidator(): callable - { - return - /** The implementation lambda */ - static function ($item): bool { - if (\is_string($item)) { - return Util::validateUrl($item); - } - - if (\is_array($item)) { - $item = Util::arrayToType($item); - } - - if (!\is_object($item)) { - return false; - } - - return Util::hasProperties($item, ['type'], true); - }; - } - - /** - * Validate that a list of items are actors - */ - protected function getCollectionActorsValidator(): callable - { - return - /** The implementation lambda */ - static function ($item): bool { - if (\is_string($item)) { - return Util::validateUrl($item); - } - - if (\is_array($item)) { - $item = Util::arrayToType($item); - } - - if (!\is_object($item)) { - return false; - } - // id must be filled - if ($item instanceof AbstractActor) { - return !\is_null($item->id); - } - - return Util::validateLink($item); - }; - } -} diff --git a/plugins/ActivityPub/Util/TypeResponse.php b/plugins/ActivityPub/Util/TypeResponse.php new file mode 100644 index 0000000000..51cd68e054 --- /dev/null +++ b/plugins/ActivityPub/Util/TypeResponse.php @@ -0,0 +1,60 @@ +. +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + +namespace Plugin\ActivityPub\Util; + +use ActivityPhp\Type\AbstractObject; +use Symfony\Component\HttpFoundation\JsonResponse; + +/** + * TypeResponse represents an HTTP response in application/ld+json format. + * + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +class TypeResponse extends JsonResponse +{ + /** + * Provides a response in application/ld+json for ActivityStreams 2.0 Types + * + * @param string|AbstractObject|null $json + * @param int $status The response status code + */ + public function __construct(string|AbstractObject|null $json = null, int $status = 202) + { + parent::__construct( + data: is_object($json) ? $json->toJson() : $json, + status: $status, + headers: ['content-type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'], + json: true, + ); + } +} diff --git a/plugins/ActivityPub/Util/Validator/contentLangModelValidator.php b/plugins/ActivityPub/Util/Validator/contentLangModelValidator.php new file mode 100644 index 0000000000..659e851603 --- /dev/null +++ b/plugins/ActivityPub/Util/Validator/contentLangModelValidator.php @@ -0,0 +1,63 @@ +. +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + +namespace Plugin\ActivityPub\Util\Validator; + +use ActivityPhp\Type; +use ActivityPhp\Type\Util; +use Exception; +use Plugin\ActivityPub\Util\ModelValidator; + +/** + * contentLangModelValidator is a dedicated + * validator for manuallyApprovesFollowers attribute. + * + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +class contentLangModelValidator extends ModelValidator +{ + /** + * Validate manuallyApprovesFollowers value + * + * @param string $value + * @param mixed $container A Note + * @return bool + * @throws Exception + */ + public function validate($value, $container): bool + { + // Validate that container is a Person + Util::subclassOf($container, Type\Extended\Object\Note::class, true); + + return $this->validateString($value); + } +} diff --git a/plugins/ActivityPub/Util/Validator/manuallyApprovesFollowersModelValidator.php b/plugins/ActivityPub/Util/Validator/manuallyApprovesFollowersModelValidator.php new file mode 100644 index 0000000000..61f89ea5fe --- /dev/null +++ b/plugins/ActivityPub/Util/Validator/manuallyApprovesFollowersModelValidator.php @@ -0,0 +1,64 @@ +. +// }}} + +/** + * ActivityPub implementation for GNU social + * + * @package GNUsocial + * @category ActivityPub + * @author Diogo Peralta Cordeiro <@diogo.site> + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ + +namespace Plugin\ActivityPub\Util\Validator; + +use ActivityPhp\Type; +use ActivityPhp\Type\Util; +use Exception; +use Plugin\ActivityPub\Util\ModelValidator; + +/** + * manuallyApprovesFollowersModelValidator is a dedicated + * validator for manuallyApprovesFollowers attribute. + * + * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org + * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later + */ +class manuallyApprovesFollowersModelValidator extends ModelValidator +{ + /** + * Validate manuallyApprovesFollowers value + * + * @param string $value + * @param mixed $container A Person + * @return bool + * @throws Exception + */ + public function validate($value, $container): bool + { + // Validate that container is a Person + Util::subclassOf($container, Type\Extended\Actor\Person::class, true); + + return true; + //return $this->validateString($value) && in_array($value, ['as:manuallyApprovesFollowers', true, false]); + } +} diff --git a/plugins/ActivityPub/composer.json b/plugins/ActivityPub/composer.json index d837ad3d68..14639e1794 100644 --- a/plugins/ActivityPub/composer.json +++ b/plugins/ActivityPub/composer.json @@ -1,5 +1,6 @@ { "require": { + "landrok/activitypub": "^0.5.6", "masterminds/html5": "^2.7", "mf2/mf2": "^0.4.6" } diff --git a/symfony.lock b/symfony.lock index 31192ff12f..b885f0fd84 100644 --- a/symfony.lock +++ b/symfony.lock @@ -148,6 +148,15 @@ "giggsey/locale": { "version": "1.9" }, + "guzzlehttp/guzzle": { + "version": "7.4.0" + }, + "guzzlehttp/promises": { + "version": "1.5.1" + }, + "guzzlehttp/psr7": { + "version": "2.1.0" + }, "jchook/phpunit-assert-throws": { "version": "v1.0.3" }, @@ -163,6 +172,9 @@ "laminas/laminas-zendframework-bridge": { "version": "1.2.0" }, + "landrok/activitypub": { + "version": "0.5.6" + }, "league/uri-parser": { "version": "1.4.1" }, @@ -223,6 +235,9 @@ "oscarotero/html-parser": { "version": "v0.1.6" }, + "paragonie/constant_time_encoding": { + "version": "v2.4.0" + }, "pear/xml_xrd": { "version": "v0.3.1" }, @@ -253,6 +268,9 @@ "phpdocumentor/type-resolver": { "version": "1.4.0" }, + "phpseclib/phpseclib": { + "version": "3.0.12" + }, "phpspec/prophecy": { "version": "1.13.0" }, @@ -315,6 +333,9 @@ "psy/psysh": { "version": "v0.10.8" }, + "ralouphie/getallheaders": { + "version": "3.0.3" + }, "sebastian/cli-parser": { "version": "1.0.1" },