├── .distignore ├── .editorconfig ├── Gruntfile.js ├── LICENSE ├── bin └── install-wp-tests.sh ├── composer.json ├── composer.lock ├── docker-compose.yml ├── includes ├── class-webfinger-admin.php ├── class-webfinger-legacy.php ├── class-webfinger.php └── functions.php ├── languages └── webfinger.pot ├── package.json ├── phpcs.xml ├── phpunit.xml.dist ├── readme.md ├── readme.txt ├── tests └── bootstrap.php └── webfinger.php /.distignore: -------------------------------------------------------------------------------- 1 | /.wordpress-org 2 | /.git 3 | /.github 4 | /node_modules 5 | /bin 6 | /sass 7 | /vendor 8 | /tests 9 | /config 10 | readme.md 11 | package.json 12 | composer.json 13 | composer.lock 14 | Gruntfile.js 15 | push.sh 16 | phpunit.xml 17 | phpunit.xml.dist 18 | phpcs.xml 19 | README.md 20 | readme.md 21 | .travis.yml 22 | .distignore 23 | .gitignore 24 | .gitattributes 25 | docker-compose.yml 26 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | charset = utf-8 11 | 12 | [*.php] 13 | indent_style = tab 14 | indent_size = 4 15 | 16 | [Gruntfile.js] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | [readme.txt] 21 | indent_style = space 22 | indent_size = 2 23 | 24 | [package.json] 25 | indent_style = space 26 | indent_size = 2 27 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | // Project configuration. 3 | grunt.initConfig({ 4 | wp_readme_to_markdown: { 5 | target: { 6 | files: { 7 | 'readme.md': 'readme.txt' 8 | }, 9 | }, 10 | }, 11 | makepot: { 12 | target: { 13 | options: { 14 | mainFile: 'webfinger.php', 15 | potFilename: 'languages/webfinger.pot', 16 | type: 'wp-plugin', 17 | updateTimestamp: true 18 | } 19 | } 20 | } 21 | }); 22 | 23 | grunt.loadNpmTasks('grunt-wp-readme-to-markdown'); 24 | grunt.loadNpmTasks('grunt-wp-i18n'); 25 | 26 | // Default task(s). 27 | grunt.registerTask('default', ['wp_readme_to_markdown', 'makepot']); 28 | }; 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Matthias Pfefferle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bin/install-wp-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ $# -lt 3 ]; then 4 | echo "usage: $0 [db-host] [wp-version]" 5 | exit 1 6 | fi 7 | 8 | DB_NAME=$1 9 | DB_USER=$2 10 | DB_PASS=$3 11 | DB_HOST=${4-localhost} 12 | WP_VERSION=${5-latest} 13 | 14 | WP_TESTS_DIR=${WP_TESTS_DIR-/tmp/wordpress-tests-lib} 15 | WP_CORE_DIR=${WP_CORE_DIR-/tmp/wordpress/} 16 | 17 | download() { 18 | if [ `which curl` ]; then 19 | curl -s "$1" > "$2"; 20 | elif [ `which wget` ]; then 21 | wget -nv -O "$2" "$1" 22 | fi 23 | } 24 | 25 | if [[ $WP_VERSION =~ [0-9]+\.[0-9]+(\.[0-9]+)? ]]; then 26 | WP_TESTS_TAG="tags/$WP_VERSION" 27 | elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then 28 | WP_TESTS_TAG="trunk" 29 | else 30 | # http serves a single offer, whereas https serves multiple. we only want one 31 | download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json 32 | grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json 33 | LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//') 34 | if [[ -z "$LATEST_VERSION" ]]; then 35 | echo "Latest WordPress version could not be found" 36 | exit 1 37 | fi 38 | WP_TESTS_TAG="tags/$LATEST_VERSION" 39 | fi 40 | 41 | set -ex 42 | 43 | install_wp() { 44 | 45 | if [ -d $WP_CORE_DIR ]; then 46 | return; 47 | fi 48 | 49 | mkdir -p $WP_CORE_DIR 50 | 51 | if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then 52 | mkdir -p /tmp/wordpress-nightly 53 | download https://wordpress.org/nightly-builds/wordpress-latest.zip /tmp/wordpress-nightly/wordpress-nightly.zip 54 | unzip -q /tmp/wordpress-nightly/wordpress-nightly.zip -d /tmp/wordpress-nightly/ 55 | mv /tmp/wordpress-nightly/wordpress/* $WP_CORE_DIR 56 | else 57 | if [ $WP_VERSION == 'latest' ]; then 58 | local ARCHIVE_NAME='latest' 59 | else 60 | local ARCHIVE_NAME="wordpress-$WP_VERSION" 61 | fi 62 | download https://wordpress.org/${ARCHIVE_NAME}.tar.gz /tmp/wordpress.tar.gz 63 | tar --strip-components=1 -zxmf /tmp/wordpress.tar.gz -C $WP_CORE_DIR 64 | fi 65 | 66 | download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php 67 | } 68 | 69 | install_test_suite() { 70 | # portable in-place argument for both GNU sed and Mac OSX sed 71 | if [[ $(uname -s) == 'Darwin' ]]; then 72 | local ioption='-i .bak' 73 | else 74 | local ioption='-i' 75 | fi 76 | 77 | # set up testing suite if it doesn't yet exist 78 | if [ ! -d $WP_TESTS_DIR ]; then 79 | # set up testing suite 80 | mkdir -p $WP_TESTS_DIR 81 | svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes 82 | fi 83 | 84 | cd $WP_TESTS_DIR 85 | 86 | if [ ! -f wp-tests-config.php ]; then 87 | download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php 88 | sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR':" "$WP_TESTS_DIR"/wp-tests-config.php 89 | sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php 90 | sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php 91 | sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php 92 | sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php 93 | fi 94 | 95 | } 96 | 97 | install_db() { 98 | # parse DB_HOST for port or socket references 99 | local PARTS=(${DB_HOST//\:/ }) 100 | local DB_HOSTNAME=${PARTS[0]}; 101 | local DB_SOCK_OR_PORT=${PARTS[1]}; 102 | local EXTRA="" 103 | 104 | if ! [ -z $DB_HOSTNAME ] ; then 105 | if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then 106 | EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" 107 | elif ! [ -z $DB_SOCK_OR_PORT ] ; then 108 | EXTRA=" --socket=$DB_SOCK_OR_PORT" 109 | elif ! [ -z $DB_HOSTNAME ] ; then 110 | EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" 111 | fi 112 | fi 113 | 114 | # create database 115 | mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA 116 | } 117 | 118 | install_wp 119 | install_test_suite 120 | install_db 121 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pfefferle/wordpress-webfinger", 3 | "description": "WebFinger for WordPress", 4 | "type": "wordpress-plugin", 5 | "license": "MIT", 6 | "authors": [{ 7 | "name": "Matthias Pfefferle", 8 | "homepage": "https://notiz.blog/" 9 | }], 10 | "require": { 11 | "php": ">=5.6.0", 12 | "composer/installers": "~2.2" 13 | }, 14 | "require-dev": { 15 | "phpcompatibility/php-compatibility": "*", 16 | "phpcompatibility/phpcompatibility-wp": "*", 17 | "squizlabs/php_codesniffer": "3.*", 18 | "wp-coding-standards/wpcs": "*", 19 | "dealerdirect/phpcodesniffer-composer-installer": "^1.0.0" 20 | }, 21 | "extra": { 22 | "installer-name": "webfinger" 23 | }, 24 | "config": { 25 | "allow-plugins": { 26 | "composer/installers": true, 27 | "dealerdirect/phpcodesniffer-composer-installer": true 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "3b559f11d53e3681b8e05ef62bb47cb1", 8 | "packages": [ 9 | { 10 | "name": "composer/installers", 11 | "version": "v2.3.0", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/composer/installers.git", 15 | "reference": "12fb2dfe5e16183de69e784a7b84046c43d97e8e" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/composer/installers/zipball/12fb2dfe5e16183de69e784a7b84046c43d97e8e", 20 | "reference": "12fb2dfe5e16183de69e784a7b84046c43d97e8e", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "composer-plugin-api": "^1.0 || ^2.0", 25 | "php": "^7.2 || ^8.0" 26 | }, 27 | "require-dev": { 28 | "composer/composer": "^1.10.27 || ^2.7", 29 | "composer/semver": "^1.7.2 || ^3.4.0", 30 | "phpstan/phpstan": "^1.11", 31 | "phpstan/phpstan-phpunit": "^1", 32 | "symfony/phpunit-bridge": "^7.1.1", 33 | "symfony/process": "^5 || ^6 || ^7" 34 | }, 35 | "type": "composer-plugin", 36 | "extra": { 37 | "class": "Composer\\Installers\\Plugin", 38 | "branch-alias": { 39 | "dev-main": "2.x-dev" 40 | }, 41 | "plugin-modifies-install-path": true 42 | }, 43 | "autoload": { 44 | "psr-4": { 45 | "Composer\\Installers\\": "src/Composer/Installers" 46 | } 47 | }, 48 | "notification-url": "https://packagist.org/downloads/", 49 | "license": [ 50 | "MIT" 51 | ], 52 | "authors": [ 53 | { 54 | "name": "Kyle Robinson Young", 55 | "email": "kyle@dontkry.com", 56 | "homepage": "https://github.com/shama" 57 | } 58 | ], 59 | "description": "A multi-framework Composer library installer", 60 | "homepage": "https://composer.github.io/installers/", 61 | "keywords": [ 62 | "Dolibarr", 63 | "Eliasis", 64 | "Hurad", 65 | "ImageCMS", 66 | "Kanboard", 67 | "Lan Management System", 68 | "MODX Evo", 69 | "MantisBT", 70 | "Mautic", 71 | "Maya", 72 | "OXID", 73 | "Plentymarkets", 74 | "Porto", 75 | "RadPHP", 76 | "SMF", 77 | "Starbug", 78 | "Thelia", 79 | "Whmcs", 80 | "WolfCMS", 81 | "agl", 82 | "annotatecms", 83 | "attogram", 84 | "bitrix", 85 | "cakephp", 86 | "chef", 87 | "cockpit", 88 | "codeigniter", 89 | "concrete5", 90 | "concreteCMS", 91 | "croogo", 92 | "dokuwiki", 93 | "drupal", 94 | "eZ Platform", 95 | "elgg", 96 | "expressionengine", 97 | "fuelphp", 98 | "grav", 99 | "installer", 100 | "itop", 101 | "known", 102 | "kohana", 103 | "laravel", 104 | "lavalite", 105 | "lithium", 106 | "magento", 107 | "majima", 108 | "mako", 109 | "matomo", 110 | "mediawiki", 111 | "miaoxing", 112 | "modulework", 113 | "modx", 114 | "moodle", 115 | "osclass", 116 | "pantheon", 117 | "phpbb", 118 | "piwik", 119 | "ppi", 120 | "processwire", 121 | "puppet", 122 | "pxcms", 123 | "reindex", 124 | "roundcube", 125 | "shopware", 126 | "silverstripe", 127 | "sydes", 128 | "sylius", 129 | "tastyigniter", 130 | "wordpress", 131 | "yawik", 132 | "zend", 133 | "zikula" 134 | ], 135 | "support": { 136 | "issues": "https://github.com/composer/installers/issues", 137 | "source": "https://github.com/composer/installers/tree/v2.3.0" 138 | }, 139 | "funding": [ 140 | { 141 | "url": "https://packagist.com", 142 | "type": "custom" 143 | }, 144 | { 145 | "url": "https://github.com/composer", 146 | "type": "github" 147 | }, 148 | { 149 | "url": "https://tidelift.com/funding/github/packagist/composer/composer", 150 | "type": "tidelift" 151 | } 152 | ], 153 | "time": "2024-06-24T20:46:46+00:00" 154 | } 155 | ], 156 | "packages-dev": [ 157 | { 158 | "name": "dealerdirect/phpcodesniffer-composer-installer", 159 | "version": "v1.0.0", 160 | "source": { 161 | "type": "git", 162 | "url": "https://github.com/PHPCSStandards/composer-installer.git", 163 | "reference": "4be43904336affa5c2f70744a348312336afd0da" 164 | }, 165 | "dist": { 166 | "type": "zip", 167 | "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", 168 | "reference": "4be43904336affa5c2f70744a348312336afd0da", 169 | "shasum": "" 170 | }, 171 | "require": { 172 | "composer-plugin-api": "^1.0 || ^2.0", 173 | "php": ">=5.4", 174 | "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" 175 | }, 176 | "require-dev": { 177 | "composer/composer": "*", 178 | "ext-json": "*", 179 | "ext-zip": "*", 180 | "php-parallel-lint/php-parallel-lint": "^1.3.1", 181 | "phpcompatibility/php-compatibility": "^9.0", 182 | "yoast/phpunit-polyfills": "^1.0" 183 | }, 184 | "type": "composer-plugin", 185 | "extra": { 186 | "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" 187 | }, 188 | "autoload": { 189 | "psr-4": { 190 | "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" 191 | } 192 | }, 193 | "notification-url": "https://packagist.org/downloads/", 194 | "license": [ 195 | "MIT" 196 | ], 197 | "authors": [ 198 | { 199 | "name": "Franck Nijhof", 200 | "email": "franck.nijhof@dealerdirect.com", 201 | "homepage": "http://www.frenck.nl", 202 | "role": "Developer / IT Manager" 203 | }, 204 | { 205 | "name": "Contributors", 206 | "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" 207 | } 208 | ], 209 | "description": "PHP_CodeSniffer Standards Composer Installer Plugin", 210 | "homepage": "http://www.dealerdirect.com", 211 | "keywords": [ 212 | "PHPCodeSniffer", 213 | "PHP_CodeSniffer", 214 | "code quality", 215 | "codesniffer", 216 | "composer", 217 | "installer", 218 | "phpcbf", 219 | "phpcs", 220 | "plugin", 221 | "qa", 222 | "quality", 223 | "standard", 224 | "standards", 225 | "style guide", 226 | "stylecheck", 227 | "tests" 228 | ], 229 | "support": { 230 | "issues": "https://github.com/PHPCSStandards/composer-installer/issues", 231 | "source": "https://github.com/PHPCSStandards/composer-installer" 232 | }, 233 | "time": "2023-01-05T11:28:13+00:00" 234 | }, 235 | { 236 | "name": "phpcompatibility/php-compatibility", 237 | "version": "9.3.5", 238 | "source": { 239 | "type": "git", 240 | "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", 241 | "reference": "9fb324479acf6f39452e0655d2429cc0d3914243" 242 | }, 243 | "dist": { 244 | "type": "zip", 245 | "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243", 246 | "reference": "9fb324479acf6f39452e0655d2429cc0d3914243", 247 | "shasum": "" 248 | }, 249 | "require": { 250 | "php": ">=5.3", 251 | "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" 252 | }, 253 | "conflict": { 254 | "squizlabs/php_codesniffer": "2.6.2" 255 | }, 256 | "require-dev": { 257 | "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" 258 | }, 259 | "suggest": { 260 | "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", 261 | "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." 262 | }, 263 | "type": "phpcodesniffer-standard", 264 | "notification-url": "https://packagist.org/downloads/", 265 | "license": [ 266 | "LGPL-3.0-or-later" 267 | ], 268 | "authors": [ 269 | { 270 | "name": "Wim Godden", 271 | "homepage": "https://github.com/wimg", 272 | "role": "lead" 273 | }, 274 | { 275 | "name": "Juliette Reinders Folmer", 276 | "homepage": "https://github.com/jrfnl", 277 | "role": "lead" 278 | }, 279 | { 280 | "name": "Contributors", 281 | "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" 282 | } 283 | ], 284 | "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", 285 | "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", 286 | "keywords": [ 287 | "compatibility", 288 | "phpcs", 289 | "standards" 290 | ], 291 | "support": { 292 | "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues", 293 | "source": "https://github.com/PHPCompatibility/PHPCompatibility" 294 | }, 295 | "time": "2019-12-27T09:44:58+00:00" 296 | }, 297 | { 298 | "name": "phpcompatibility/phpcompatibility-paragonie", 299 | "version": "1.3.3", 300 | "source": { 301 | "type": "git", 302 | "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git", 303 | "reference": "293975b465e0e709b571cbf0c957c6c0a7b9a2ac" 304 | }, 305 | "dist": { 306 | "type": "zip", 307 | "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/293975b465e0e709b571cbf0c957c6c0a7b9a2ac", 308 | "reference": "293975b465e0e709b571cbf0c957c6c0a7b9a2ac", 309 | "shasum": "" 310 | }, 311 | "require": { 312 | "phpcompatibility/php-compatibility": "^9.0" 313 | }, 314 | "require-dev": { 315 | "dealerdirect/phpcodesniffer-composer-installer": "^1.0", 316 | "paragonie/random_compat": "dev-master", 317 | "paragonie/sodium_compat": "dev-master" 318 | }, 319 | "suggest": { 320 | "dealerdirect/phpcodesniffer-composer-installer": "^1.0 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", 321 | "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." 322 | }, 323 | "type": "phpcodesniffer-standard", 324 | "notification-url": "https://packagist.org/downloads/", 325 | "license": [ 326 | "LGPL-3.0-or-later" 327 | ], 328 | "authors": [ 329 | { 330 | "name": "Wim Godden", 331 | "role": "lead" 332 | }, 333 | { 334 | "name": "Juliette Reinders Folmer", 335 | "role": "lead" 336 | } 337 | ], 338 | "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.", 339 | "homepage": "http://phpcompatibility.com/", 340 | "keywords": [ 341 | "compatibility", 342 | "paragonie", 343 | "phpcs", 344 | "polyfill", 345 | "standards", 346 | "static analysis" 347 | ], 348 | "support": { 349 | "issues": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie/issues", 350 | "security": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie/security/policy", 351 | "source": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie" 352 | }, 353 | "funding": [ 354 | { 355 | "url": "https://github.com/PHPCompatibility", 356 | "type": "github" 357 | }, 358 | { 359 | "url": "https://github.com/jrfnl", 360 | "type": "github" 361 | }, 362 | { 363 | "url": "https://opencollective.com/php_codesniffer", 364 | "type": "open_collective" 365 | } 366 | ], 367 | "time": "2024-04-24T21:30:46+00:00" 368 | }, 369 | { 370 | "name": "phpcompatibility/phpcompatibility-wp", 371 | "version": "2.1.5", 372 | "source": { 373 | "type": "git", 374 | "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git", 375 | "reference": "01c1ff2704a58e46f0cb1ca9d06aee07b3589082" 376 | }, 377 | "dist": { 378 | "type": "zip", 379 | "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/01c1ff2704a58e46f0cb1ca9d06aee07b3589082", 380 | "reference": "01c1ff2704a58e46f0cb1ca9d06aee07b3589082", 381 | "shasum": "" 382 | }, 383 | "require": { 384 | "phpcompatibility/php-compatibility": "^9.0", 385 | "phpcompatibility/phpcompatibility-paragonie": "^1.0" 386 | }, 387 | "require-dev": { 388 | "dealerdirect/phpcodesniffer-composer-installer": "^1.0" 389 | }, 390 | "suggest": { 391 | "dealerdirect/phpcodesniffer-composer-installer": "^1.0 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", 392 | "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." 393 | }, 394 | "type": "phpcodesniffer-standard", 395 | "notification-url": "https://packagist.org/downloads/", 396 | "license": [ 397 | "LGPL-3.0-or-later" 398 | ], 399 | "authors": [ 400 | { 401 | "name": "Wim Godden", 402 | "role": "lead" 403 | }, 404 | { 405 | "name": "Juliette Reinders Folmer", 406 | "role": "lead" 407 | } 408 | ], 409 | "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.", 410 | "homepage": "http://phpcompatibility.com/", 411 | "keywords": [ 412 | "compatibility", 413 | "phpcs", 414 | "standards", 415 | "static analysis", 416 | "wordpress" 417 | ], 418 | "support": { 419 | "issues": "https://github.com/PHPCompatibility/PHPCompatibilityWP/issues", 420 | "security": "https://github.com/PHPCompatibility/PHPCompatibilityWP/security/policy", 421 | "source": "https://github.com/PHPCompatibility/PHPCompatibilityWP" 422 | }, 423 | "funding": [ 424 | { 425 | "url": "https://github.com/PHPCompatibility", 426 | "type": "github" 427 | }, 428 | { 429 | "url": "https://github.com/jrfnl", 430 | "type": "github" 431 | }, 432 | { 433 | "url": "https://opencollective.com/php_codesniffer", 434 | "type": "open_collective" 435 | } 436 | ], 437 | "time": "2024-04-24T21:37:59+00:00" 438 | }, 439 | { 440 | "name": "phpcsstandards/phpcsextra", 441 | "version": "1.2.1", 442 | "source": { 443 | "type": "git", 444 | "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", 445 | "reference": "11d387c6642b6e4acaf0bd9bf5203b8cca1ec489" 446 | }, 447 | "dist": { 448 | "type": "zip", 449 | "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/11d387c6642b6e4acaf0bd9bf5203b8cca1ec489", 450 | "reference": "11d387c6642b6e4acaf0bd9bf5203b8cca1ec489", 451 | "shasum": "" 452 | }, 453 | "require": { 454 | "php": ">=5.4", 455 | "phpcsstandards/phpcsutils": "^1.0.9", 456 | "squizlabs/php_codesniffer": "^3.8.0" 457 | }, 458 | "require-dev": { 459 | "php-parallel-lint/php-console-highlighter": "^1.0", 460 | "php-parallel-lint/php-parallel-lint": "^1.3.2", 461 | "phpcsstandards/phpcsdevcs": "^1.1.6", 462 | "phpcsstandards/phpcsdevtools": "^1.2.1", 463 | "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" 464 | }, 465 | "type": "phpcodesniffer-standard", 466 | "extra": { 467 | "branch-alias": { 468 | "dev-stable": "1.x-dev", 469 | "dev-develop": "1.x-dev" 470 | } 471 | }, 472 | "notification-url": "https://packagist.org/downloads/", 473 | "license": [ 474 | "LGPL-3.0-or-later" 475 | ], 476 | "authors": [ 477 | { 478 | "name": "Juliette Reinders Folmer", 479 | "homepage": "https://github.com/jrfnl", 480 | "role": "lead" 481 | }, 482 | { 483 | "name": "Contributors", 484 | "homepage": "https://github.com/PHPCSStandards/PHPCSExtra/graphs/contributors" 485 | } 486 | ], 487 | "description": "A collection of sniffs and standards for use with PHP_CodeSniffer.", 488 | "keywords": [ 489 | "PHP_CodeSniffer", 490 | "phpcbf", 491 | "phpcodesniffer-standard", 492 | "phpcs", 493 | "standards", 494 | "static analysis" 495 | ], 496 | "support": { 497 | "issues": "https://github.com/PHPCSStandards/PHPCSExtra/issues", 498 | "security": "https://github.com/PHPCSStandards/PHPCSExtra/security/policy", 499 | "source": "https://github.com/PHPCSStandards/PHPCSExtra" 500 | }, 501 | "funding": [ 502 | { 503 | "url": "https://github.com/PHPCSStandards", 504 | "type": "github" 505 | }, 506 | { 507 | "url": "https://github.com/jrfnl", 508 | "type": "github" 509 | }, 510 | { 511 | "url": "https://opencollective.com/php_codesniffer", 512 | "type": "open_collective" 513 | } 514 | ], 515 | "time": "2023-12-08T16:49:07+00:00" 516 | }, 517 | { 518 | "name": "phpcsstandards/phpcsutils", 519 | "version": "1.0.10", 520 | "source": { 521 | "type": "git", 522 | "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", 523 | "reference": "51609a5b89f928e0c463d6df80eb38eff1eaf544" 524 | }, 525 | "dist": { 526 | "type": "zip", 527 | "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/51609a5b89f928e0c463d6df80eb38eff1eaf544", 528 | "reference": "51609a5b89f928e0c463d6df80eb38eff1eaf544", 529 | "shasum": "" 530 | }, 531 | "require": { 532 | "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", 533 | "php": ">=5.4", 534 | "squizlabs/php_codesniffer": "^3.9.0 || 4.0.x-dev@dev" 535 | }, 536 | "require-dev": { 537 | "ext-filter": "*", 538 | "php-parallel-lint/php-console-highlighter": "^1.0", 539 | "php-parallel-lint/php-parallel-lint": "^1.3.2", 540 | "phpcsstandards/phpcsdevcs": "^1.1.6", 541 | "yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0" 542 | }, 543 | "type": "phpcodesniffer-standard", 544 | "extra": { 545 | "branch-alias": { 546 | "dev-stable": "1.x-dev", 547 | "dev-develop": "1.x-dev" 548 | } 549 | }, 550 | "autoload": { 551 | "classmap": [ 552 | "PHPCSUtils/" 553 | ] 554 | }, 555 | "notification-url": "https://packagist.org/downloads/", 556 | "license": [ 557 | "LGPL-3.0-or-later" 558 | ], 559 | "authors": [ 560 | { 561 | "name": "Juliette Reinders Folmer", 562 | "homepage": "https://github.com/jrfnl", 563 | "role": "lead" 564 | }, 565 | { 566 | "name": "Contributors", 567 | "homepage": "https://github.com/PHPCSStandards/PHPCSUtils/graphs/contributors" 568 | } 569 | ], 570 | "description": "A suite of utility functions for use with PHP_CodeSniffer", 571 | "homepage": "https://phpcsutils.com/", 572 | "keywords": [ 573 | "PHP_CodeSniffer", 574 | "phpcbf", 575 | "phpcodesniffer-standard", 576 | "phpcs", 577 | "phpcs3", 578 | "standards", 579 | "static analysis", 580 | "tokens", 581 | "utility" 582 | ], 583 | "support": { 584 | "docs": "https://phpcsutils.com/", 585 | "issues": "https://github.com/PHPCSStandards/PHPCSUtils/issues", 586 | "security": "https://github.com/PHPCSStandards/PHPCSUtils/security/policy", 587 | "source": "https://github.com/PHPCSStandards/PHPCSUtils" 588 | }, 589 | "funding": [ 590 | { 591 | "url": "https://github.com/PHPCSStandards", 592 | "type": "github" 593 | }, 594 | { 595 | "url": "https://github.com/jrfnl", 596 | "type": "github" 597 | }, 598 | { 599 | "url": "https://opencollective.com/php_codesniffer", 600 | "type": "open_collective" 601 | } 602 | ], 603 | "time": "2024-03-17T23:44:50+00:00" 604 | }, 605 | { 606 | "name": "squizlabs/php_codesniffer", 607 | "version": "3.11.2", 608 | "source": { 609 | "type": "git", 610 | "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", 611 | "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079" 612 | }, 613 | "dist": { 614 | "type": "zip", 615 | "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/1368f4a58c3c52114b86b1abe8f4098869cb0079", 616 | "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079", 617 | "shasum": "" 618 | }, 619 | "require": { 620 | "ext-simplexml": "*", 621 | "ext-tokenizer": "*", 622 | "ext-xmlwriter": "*", 623 | "php": ">=5.4.0" 624 | }, 625 | "require-dev": { 626 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" 627 | }, 628 | "bin": [ 629 | "bin/phpcbf", 630 | "bin/phpcs" 631 | ], 632 | "type": "library", 633 | "extra": { 634 | "branch-alias": { 635 | "dev-master": "3.x-dev" 636 | } 637 | }, 638 | "notification-url": "https://packagist.org/downloads/", 639 | "license": [ 640 | "BSD-3-Clause" 641 | ], 642 | "authors": [ 643 | { 644 | "name": "Greg Sherwood", 645 | "role": "Former lead" 646 | }, 647 | { 648 | "name": "Juliette Reinders Folmer", 649 | "role": "Current lead" 650 | }, 651 | { 652 | "name": "Contributors", 653 | "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" 654 | } 655 | ], 656 | "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", 657 | "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", 658 | "keywords": [ 659 | "phpcs", 660 | "standards", 661 | "static analysis" 662 | ], 663 | "support": { 664 | "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", 665 | "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", 666 | "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", 667 | "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" 668 | }, 669 | "funding": [ 670 | { 671 | "url": "https://github.com/PHPCSStandards", 672 | "type": "github" 673 | }, 674 | { 675 | "url": "https://github.com/jrfnl", 676 | "type": "github" 677 | }, 678 | { 679 | "url": "https://opencollective.com/php_codesniffer", 680 | "type": "open_collective" 681 | } 682 | ], 683 | "time": "2024-12-11T16:04:26+00:00" 684 | }, 685 | { 686 | "name": "wp-coding-standards/wpcs", 687 | "version": "3.1.0", 688 | "source": { 689 | "type": "git", 690 | "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", 691 | "reference": "9333efcbff231f10dfd9c56bb7b65818b4733ca7" 692 | }, 693 | "dist": { 694 | "type": "zip", 695 | "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/9333efcbff231f10dfd9c56bb7b65818b4733ca7", 696 | "reference": "9333efcbff231f10dfd9c56bb7b65818b4733ca7", 697 | "shasum": "" 698 | }, 699 | "require": { 700 | "ext-filter": "*", 701 | "ext-libxml": "*", 702 | "ext-tokenizer": "*", 703 | "ext-xmlreader": "*", 704 | "php": ">=5.4", 705 | "phpcsstandards/phpcsextra": "^1.2.1", 706 | "phpcsstandards/phpcsutils": "^1.0.10", 707 | "squizlabs/php_codesniffer": "^3.9.0" 708 | }, 709 | "require-dev": { 710 | "php-parallel-lint/php-console-highlighter": "^1.0.0", 711 | "php-parallel-lint/php-parallel-lint": "^1.3.2", 712 | "phpcompatibility/php-compatibility": "^9.0", 713 | "phpcsstandards/phpcsdevtools": "^1.2.0", 714 | "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" 715 | }, 716 | "suggest": { 717 | "ext-iconv": "For improved results", 718 | "ext-mbstring": "For improved results" 719 | }, 720 | "type": "phpcodesniffer-standard", 721 | "notification-url": "https://packagist.org/downloads/", 722 | "license": [ 723 | "MIT" 724 | ], 725 | "authors": [ 726 | { 727 | "name": "Contributors", 728 | "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" 729 | } 730 | ], 731 | "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", 732 | "keywords": [ 733 | "phpcs", 734 | "standards", 735 | "static analysis", 736 | "wordpress" 737 | ], 738 | "support": { 739 | "issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues", 740 | "source": "https://github.com/WordPress/WordPress-Coding-Standards", 741 | "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki" 742 | }, 743 | "funding": [ 744 | { 745 | "url": "https://opencollective.com/php_codesniffer", 746 | "type": "custom" 747 | } 748 | ], 749 | "time": "2024-03-25T16:39:00+00:00" 750 | } 751 | ], 752 | "aliases": [], 753 | "minimum-stability": "stable", 754 | "stability-flags": [], 755 | "prefer-stable": false, 756 | "prefer-lowest": false, 757 | "platform": { 758 | "php": ">=5.6.0" 759 | }, 760 | "platform-dev": [], 761 | "plugin-api-version": "2.6.0" 762 | } 763 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | db: 4 | image: mysql:5.7 5 | restart: always 6 | environment: 7 | MYSQL_ROOT_PASSWORD: wordpress 8 | MYSQL_DATABASE: wordpress 9 | MYSQL_USER: wordpress 10 | MYSQL_PASSWORD: wordpress 11 | 12 | wordpress: 13 | depends_on: 14 | - db 15 | image: wordpress:latest 16 | links: 17 | - db 18 | ports: 19 | - "8088:80" 20 | volumes: 21 | - .:/var/www/html/wp-content/plugins/webfinger 22 | restart: always 23 | environment: 24 | WORDPRESS_DB_HOST: db:3306 25 | WORDPRESS_DB_USER: wordpress 26 | WORDPRESS_DB_PASSWORD: wordpress 27 | WORDPRESS_DEBUG: 1 28 | -------------------------------------------------------------------------------- /includes/class-webfinger-admin.php: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pfefferle/wordpress-webfinger/9de318ea5fb025f6d91134aa8f01eb19144358e8/includes/class-webfinger-admin.php -------------------------------------------------------------------------------- /includes/class-webfinger-legacy.php: -------------------------------------------------------------------------------- 1 | query_vars ) ) { 48 | $format = $wp->query_vars['format']; 49 | } 50 | 51 | if ( 52 | ! in_array( 'application/xrd+xml', $accept, true ) && 53 | ! in_array( 'application/xml+xrd', $accept, true ) && 54 | 'xrd' !== $format 55 | ) { 56 | return $webfinger; 57 | } 58 | 59 | header( 'Content-Type: application/xrd+xml; charset=' . get_bloginfo( 'charset' ), true ); 60 | 61 | echo '' . PHP_EOL; 62 | echo '' . PHP_EOL; 63 | 64 | echo self::jrd_to_xrd( $webfinger ); 65 | // add xml-only content 66 | do_action( 'webfinger_xrd' ); 67 | 68 | echo PHP_EOL . ''; 69 | 70 | exit; 71 | } 72 | 73 | /* 74 | * host-meta resource feature 75 | * 76 | * @param array $query 77 | */ 78 | public static function render_host_meta( $format, $host_meta, $query ) { 79 | if ( ! array_key_exists( 'resource', $query ) ) { 80 | return; 81 | } 82 | 83 | global $wp; 84 | 85 | // filter WebFinger array 86 | $webfinger = apply_filters( 'webfinger_data', array(), $query['resource'] ); 87 | 88 | // check if "user" exists 89 | if ( empty( $webfinger ) ) { 90 | status_header( 404 ); 91 | header( 'Content-Type: text/plain; charset=' . get_bloginfo( 'charset' ), true ); 92 | echo 'no data for resource "' . $query['resource'] . '" found'; 93 | exit; 94 | } 95 | 96 | if ( 'xrd' === $format ) { 97 | $wp->query_vars['format'] = 'xrd'; 98 | } 99 | 100 | do_action( 'webfinger_render', $webfinger ); 101 | // stop exactly here! 102 | exit; 103 | } 104 | 105 | /** 106 | * add the host meta information 107 | */ 108 | public static function host_meta_discovery( $array ) { 109 | $array['links'][] = array( 110 | 'rel' => 'lrdd', 111 | 'template' => add_query_arg( 112 | array( 113 | 'resource' => '{uri}', 114 | 'format' => 'xrd', 115 | ), 116 | get_webfinger_endpoint() 117 | ), 118 | 'type' => 'application/xrd+xml', 119 | ); 120 | $array['links'][] = array( 121 | 'rel' => 'lrdd', 122 | 'template' => add_query_arg( 'resource', '{uri}', get_webfinger_endpoint() ), 123 | 'type' => 'application/jrd+xml', 124 | ); 125 | $array['links'][] = array( 126 | 'rel' => 'lrdd', 127 | 'template' => add_query_arg( 'resource', '{uri}', get_webfinger_endpoint() ), 128 | 'type' => 'application/json', 129 | ); 130 | 131 | return $array; 132 | } 133 | 134 | /** 135 | * recursive helper to generade the xrd-xml from the jrd array 136 | * 137 | * @param string $host_meta 138 | * 139 | * @return string 140 | */ 141 | public static function jrd_to_xrd( $webfinger ) { 142 | $xrd = null; 143 | 144 | // supported protocols 145 | $protocols = array_merge( 146 | array( 'aim', 'ymsgr', 'acct' ), 147 | wp_allowed_protocols() 148 | ); 149 | 150 | foreach ( $webfinger as $type => $content ) { 151 | // print subject 152 | if ( 'subject' === $type ) { 153 | $xrd .= '' . esc_url( $content, $protocols ) . ''; 154 | continue; 155 | } 156 | 157 | // print aliases 158 | if ( 'aliases' === $type ) { 159 | foreach ( $content as $uri ) { 160 | $xrd .= '' . esc_url( $uri, $protocols ) . ''; 161 | } 162 | continue; 163 | } 164 | 165 | // print properties 166 | if ( 'properties' === $type ) { 167 | foreach ( $content as $type => $uri ) { 168 | $xrd .= '' . esc_html( $uri ) . ''; 169 | } 170 | continue; 171 | } 172 | 173 | // print titles 174 | if ( 'titles' === $type ) { 175 | foreach ( $content as $key => $value ) { 176 | if ( 'default' === $key ) { 177 | $xrd .= '' . esc_html( $value ) . ''; 178 | } else { 179 | $xrd .= '' . esc_html( $value ) . ''; 180 | } 181 | } 182 | continue; 183 | } 184 | 185 | // print links 186 | if ( 'links' === $type ) { 187 | foreach ( $content as $links ) { 188 | $temp = array(); 189 | $cascaded = false; 190 | $xrd .= ' $value ) { 193 | if ( is_array( $value ) ) { 194 | $temp[ $key ] = $value; 195 | $cascaded = true; 196 | } else { 197 | $xrd .= esc_attr( $key ) . '="' . esc_attr( $value ) . '" '; 198 | } 199 | } 200 | if ( $cascaded ) { 201 | $xrd .= '>'; 202 | $xrd .= Webfinger_Legacy::jrd_to_xrd( $temp ); 203 | $xrd .= ''; 204 | } else { 205 | $xrd .= ' />'; 206 | } 207 | } 208 | continue; 209 | } 210 | } 211 | 212 | return $xrd; 213 | } 214 | 215 | /** 216 | * Backwards compatibility for old versions. please don't use! 217 | * 218 | * @deprecated 219 | * 220 | * @param array $webfinger 221 | * @param string $resource 222 | * @param WP_User $user 223 | * 224 | * @return array 225 | */ 226 | public static function legacy_filter( $webfinger, $resource, $user ) { 227 | // filter WebFinger array 228 | return apply_filters( 'webfinger', $webfinger, $user, $resource, $_GET ); 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /includes/class-webfinger.php: -------------------------------------------------------------------------------- 1 | query_vars ) || 46 | 'webfinger' != $wp->query_vars['well-known'] 47 | ) { 48 | return; 49 | } 50 | 51 | header( 'Access-Control-Allow-Origin: *' ); 52 | 53 | // check if "resource" param exists 54 | if ( 55 | ! array_key_exists( 'resource', $wp->query_vars ) || 56 | empty( $wp->query_vars['resource'] ) 57 | ) { 58 | status_header( 400 ); 59 | header( 'Content-Type: text/plain; charset=' . get_bloginfo( 'charset' ), true ); 60 | 61 | echo 'missing "resource" parameter'; 62 | 63 | exit; 64 | } 65 | 66 | $resource = esc_html( $wp->query_vars['resource'] ); 67 | 68 | // filter WebFinger array 69 | $webfinger = apply_filters( 'webfinger_data', array(), $resource ); 70 | 71 | // check if "user" exists 72 | if ( empty( $webfinger ) ) { 73 | status_header( 404 ); 74 | header( 'Content-Type: text/plain; charset=' . get_bloginfo( 'charset' ), true ); 75 | 76 | printf( 'no data for resource "%s" found', $resource ); 77 | 78 | exit; 79 | } 80 | 81 | do_action( 'webfinger_render', $webfinger ); 82 | 83 | // stop exactly here! 84 | exit; 85 | } 86 | 87 | /** 88 | * Render the JRD representation of the webfinger resource. 89 | * 90 | * @param array $webfinger the WebFinger data-array 91 | */ 92 | public static function render_jrd( $webfinger ) { 93 | header( 'Content-Type: application/jrd+json; charset=' . get_bloginfo( 'charset' ), true ); 94 | 95 | echo wp_json_encode( $webfinger ); 96 | exit; 97 | } 98 | 99 | /** 100 | * Generates the WebFinger base array 101 | * 102 | * @param array $webfinger the WebFinger data-array 103 | * @param stdClass $user the WordPress user 104 | * @param string $resource the resource param 105 | * 106 | * @return array the enriched webfinger data-array 107 | */ 108 | public static function generate_user_data( $webfinger, $resource ) { 109 | // find matching user 110 | $user = self::get_user_by_uri( $resource ); 111 | 112 | if ( ! $user ) { 113 | return $webfinger; 114 | } 115 | 116 | // generate "profile" url 117 | $url = get_author_posts_url( $user->ID, $user->user_nicename ); 118 | 119 | // generate default photo-url 120 | $photo = get_avatar_url( $user->ID ); 121 | 122 | // generate default array 123 | $webfinger = array( 124 | 'subject' => self::get_user_resource( $user->ID ), 125 | 'aliases' => self::get_user_resources( $user->ID ), 126 | 'links' => array( 127 | array( 128 | 'rel' => 'http://webfinger.net/rel/profile-page', 129 | 'href' => esc_url( $url ), 130 | 'type' => 'text/html', 131 | ), 132 | array( 133 | 'rel' => 'http://webfinger.net/rel/avatar', 134 | 'href' => esc_url( $photo ), 135 | ), 136 | ), 137 | ); 138 | 139 | // add user_url if set 140 | if ( isset( $user->user_url ) && ! empty( $user->user_url ) ) { 141 | $webfinger['links'][] = array( 142 | 'rel' => 'http://webfinger.net/rel/profile-page', 143 | 'href' => esc_url( $user->user_url ), 144 | 'type' => 'text/html', 145 | ); 146 | } 147 | 148 | return apply_filters( 'webfinger_user_data', $webfinger, $resource, $user ); 149 | } 150 | 151 | /** 152 | * generates the webfinger base array 153 | * 154 | * @param array $webfinger the webfinger data-array 155 | * @param string $resource the resource param 156 | * 157 | * @return array the enriched webfinger data-array 158 | */ 159 | public static function generate_post_data( $webfinger, $resource ) { 160 | // find matching post 161 | $post_id = url_to_postid( $resource ); 162 | 163 | // check if there is a matching post-id 164 | if ( ! $post_id ) { 165 | return $webfinger; 166 | } 167 | 168 | // get post by id 169 | $post = get_post( $post_id ); 170 | 171 | // check if there is a matching post 172 | if ( ! $post ) { 173 | return $webfinger; 174 | } 175 | 176 | $author = get_user_by( 'id', $post->post_author ); 177 | 178 | // default webfinger array for posts 179 | $webfinger = array( 180 | 'subject' => get_permalink( $post->ID ), 181 | 'aliases' => apply_filters( 'webfinger_post_resource', array( home_url( '?p=' . $post->ID ), get_permalink( $post->ID ) ), $post ), 182 | 'links' => array( 183 | array( 184 | 'rel' => 'shortlink', 185 | 'type' => 'text/html', 186 | 'href' => wp_get_shortlink( $post ), 187 | ), 188 | array( 189 | 'rel' => 'canonical', 190 | 'type' => 'text/html', 191 | 'href' => get_permalink( $post->ID ), 192 | ), 193 | array( 194 | 'rel' => 'author', 195 | 'type' => 'text/html', 196 | 'href' => get_author_posts_url( $author->ID, $author->nicename ), 197 | ), 198 | array( 199 | 'rel' => 'alternate', 200 | 'type' => 'application/rss+xml', 201 | 'href' => get_post_comments_feed_link( $post->ID, 'rss2' ), 202 | ), 203 | array( 204 | 'rel' => 'alternate', 205 | 'type' => 'application/atom+xml', 206 | 'href' => get_post_comments_feed_link( $post->ID, 'atom' ), 207 | ), 208 | ), 209 | ); 210 | 211 | return apply_filters( 'webfinger_post_data', $webfinger, $resource, $post ); 212 | } 213 | 214 | /** 215 | * Filters the WebFinger array by request params like "rel" 216 | * 217 | * @link http://tools.ietf.org/html/rfc7033#section-4.3 218 | * 219 | * @param array $array 220 | * @param stdClass $user 221 | * @param array $queries 222 | * 223 | * @return array 224 | */ 225 | public static function filter_by_rel( $webfinger ) { 226 | // check if WebFinger is empty or if "rel" 227 | // is set or if array has any "links" 228 | if ( 229 | empty( $webfinger ) || 230 | ! array_key_exists( 'rel', $_GET ) || 231 | ! isset( $webfinger['links'] ) 232 | ) { 233 | return $webfinger; 234 | } 235 | 236 | // explode the query-string by hand because php does not 237 | // support multiple queries with the same name 238 | $query = explode( '&', $_SERVER['QUERY_STRING'] ); 239 | $rels = array(); 240 | 241 | foreach ( $query as $param ) { 242 | $param = explode( '=', $param ); 243 | 244 | // check if query-string is valid and if it is a 'rel' 245 | if ( 246 | isset( $param[0], $param[1] ) && 247 | 'rel' == $param[0] && 248 | ! empty( $param[1] ) 249 | ) { 250 | $rels[] = urldecode( trim( $param[1] ) ); 251 | } 252 | } 253 | 254 | // check if there is something to filter 255 | if ( empty( $rels ) ) { 256 | return $webfinger; 257 | } 258 | 259 | // filter WebFinger-array 260 | $links = array(); 261 | foreach ( $webfinger['links'] as $link ) { 262 | if ( in_array( $link['rel'], $rels ) ) { 263 | $links[] = $link; 264 | } 265 | } 266 | $webfinger['links'] = $links; 267 | 268 | // return only "links" with the matching rel-values 269 | return $webfinger; 270 | } 271 | 272 | /** 273 | * Returns a Userobject 274 | * 275 | * @param string $uri 276 | * 277 | * @return WP_User 278 | * 279 | * @uses apply_filters() uses 'webfinger_user' to filter the 280 | * user and 'webfinger_user_query' to add custom query-params 281 | */ 282 | private static function get_user_by_uri( $uri ) { 283 | $uri = urldecode( $uri ); 284 | $uri = str_replace( array( '*', '%' ), '', $uri ); 285 | $match = array(); 286 | 287 | // try to extract the scheme and the host 288 | if ( preg_match( '/^([a-zA-Z^:]+):(.*)$/i', $uri, $match ) ) { 289 | // extract the scheme 290 | $scheme = esc_attr( $match[1] ); 291 | // extract the "host" 292 | $host = sanitize_text_field( $match[2] ); 293 | } else { // fallback to 'acct' as default theme 294 | $scheme = 'acct'; 295 | // extract the "host" 296 | $host = $uri; 297 | } 298 | 299 | // check if $host and $uri are set 300 | if ( ! $host || ! $uri ) { 301 | return null; 302 | } 303 | 304 | switch ( $scheme ) { 305 | case 'http': // check urls 306 | case 'https': 307 | // check if is the author url 308 | $author_id = url_to_authorid( $uri ); 309 | if ( $author_id ) { 310 | $args = array( 311 | 'search' => $author_id, 312 | 'search_columns' => array( 'ID' ), 313 | ); 314 | } else { // check other urls 315 | // search url in user_url 316 | $args = array( 317 | 'search' => $uri, 318 | 'search_columns' => array( 'user_url' ), 319 | ); 320 | } 321 | 322 | break; 323 | case 'acct': // check acct scheme 324 | // get the identifier at the left of the '@' 325 | $parts = explode( '@', $host ); 326 | 327 | if ( ! $parts[0] ) { 328 | return null; 329 | } 330 | 331 | // check domain 332 | if ( 333 | ! isset( $parts[1] ) || 334 | parse_url( home_url(), PHP_URL_HOST ) !== $parts[1] 335 | ) { 336 | return null; 337 | } 338 | 339 | $args = array( 340 | 'search' => $parts[0], 341 | 'search_columns' => array( 342 | 'user_nicename', 343 | 'user_login', 344 | ), 345 | ); 346 | break; 347 | case 'mailto': // check mailto scheme 348 | $args = array( 349 | 'search' => $host, 350 | 'search_columns' => array( 'user_email' ), 351 | ); 352 | break; 353 | case 'xmpp': // check xmpp/jabber schemes 354 | case 'urn:xmpp': 355 | case 'im': 356 | $args = array( 357 | 'meta_key' => 'jabber', 358 | 'meta_value' => $host, 359 | 'meta_compare' => '=', 360 | ); 361 | break; 362 | default: 363 | $args = array(); 364 | break; 365 | } 366 | 367 | $args = apply_filters( 'webfinger_user_query', $args, $uri, $scheme ); 368 | 369 | // get user query 370 | $user_query = new WP_User_Query( $args ); 371 | 372 | // check result 373 | if ( ! empty( $user_query->results ) ) { 374 | $user = $user_query->results[0]; 375 | } else { 376 | $user = null; 377 | } 378 | 379 | return $user; 380 | } 381 | 382 | /** 383 | * Returns a users default WebFinger 384 | * 385 | * @param mixed $id_or_name_or_object 386 | * 387 | * @return string|null 388 | */ 389 | public static function get_user_resource( $id_or_name_or_object, $with_protocol = true ) { 390 | $user = get_user_by_various( $id_or_name_or_object ); 391 | $resource = null; 392 | 393 | if ( $user ) { 394 | $resource = $user->user_login . '@' . parse_url( home_url(), PHP_URL_HOST ); 395 | 396 | if ( $with_protocol ) { 397 | $resource = 'acct:' . $resource; 398 | } 399 | } 400 | 401 | return apply_filters( 'webfinger_user_resource', $resource, $user ); 402 | } 403 | 404 | /** 405 | * Returns all WebFinger "resources" 406 | * 407 | * @param mixed $id_or_name_or_object 408 | * 409 | * @return array 410 | */ 411 | public static function get_user_resources( $id_or_name_or_object ) { 412 | $user = get_user_by_various( $id_or_name_or_object ); 413 | 414 | if ( ! $user ) { 415 | return array(); 416 | } 417 | 418 | // generate account idenitfier (acct: uri) 419 | $resources[] = self::get_user_resource( $user ); 420 | $resources[] = get_author_posts_url( $user->ID, $user->user_nicename ); 421 | 422 | /* 423 | * the IM schemes are based on the "vCard Extensions for Instant Messaging (IM)". 424 | * that means that the YahooID for example is represented by ymsgr:identifier 425 | * and not by the ymsgr:SendIM?identifier pseudo uri 426 | * 427 | * @link http://tools.ietf.org/html/rfc4770#section-1 428 | */ 429 | if ( get_user_meta( $user->ID, 'yim', true ) ) { 430 | $resources[] = 'ymsgr:' . get_user_meta( $user->ID, 'yim', true ); 431 | } 432 | 433 | // aim:identifier instead of aim:goim?screenname=identifier 434 | if ( get_user_meta( $user->ID, 'aim', true ) ) { 435 | $resources[] = 'aim:' . get_user_meta( $user->ID, 'aim', true ); 436 | } 437 | 438 | if ( get_user_meta( $user->ID, 'jabber', true ) ) { 439 | $resources[] = 'xmpp:' . get_user_meta( $user->ID, 'jabber', true ); 440 | } 441 | 442 | return array_unique( apply_filters( 'webfinger_user_resources', $resources, $user ) ); 443 | } 444 | } 445 | -------------------------------------------------------------------------------- /includes/functions.php: -------------------------------------------------------------------------------- 1 | wp_rewrite_rules(); 30 | 31 | // not using rewrite rules, and 'author=N' method failed, so we're out of options 32 | if ( empty( $rewrite ) ) { 33 | return 0; 34 | } 35 | 36 | // generate rewrite rule for the author url 37 | $author_rewrite = $wp_rewrite->get_author_permastruct(); 38 | $author_regexp = str_replace( '%author%', '', $author_rewrite ); 39 | 40 | // match the rewrite rule with the passed url 41 | if ( preg_match( '/https?:\/\/(.+)' . preg_quote( $author_regexp, '/' ) . '([^\/]+)/i', $url, $match ) ) { 42 | $user = get_user_by( 'slug', $match[2] ); 43 | if ( $user ) { 44 | return $user->ID; 45 | } 46 | } 47 | 48 | return 0; 49 | } 50 | endif; 51 | 52 | if ( ! function_exists( 'get_user_by_various' ) ) : 53 | /** 54 | * Convenience method to get user data by ID, username, object or from current user. 55 | * 56 | * @param mixed $id_or_name_or_object the username, ID or object. If not provided, the current user will be used. 57 | * 58 | * @return bool|object False on failure, User DB row object 59 | * 60 | * @author Will Norris 61 | * 62 | * @see get_user_by_various() # DiSo OpenID-Plugin 63 | */ 64 | function get_user_by_various( $id_or_name_or_object = null ) { 65 | if ( null === $id_or_name_or_object ) { 66 | $user = wp_get_current_user(); 67 | if ( null == $user ) { 68 | return false; 69 | } 70 | return $user; 71 | } elseif ( is_object( $id_or_name_or_object ) ) { 72 | return $id_or_name_or_object; 73 | } elseif ( is_numeric( $id_or_name_or_object ) ) { 74 | return get_user_by( 'id', $id_or_name_or_object ); 75 | } else { 76 | return get_user_by( 'login', $id_or_name_or_object ); 77 | } 78 | } 79 | endif; 80 | 81 | /** 82 | * Build WebFinger endpoint 83 | * 84 | * @return string The WebFinger URL 85 | */ 86 | function get_webfinger_endpoint() { 87 | global $wp_rewrite; 88 | 89 | $permalink = $wp_rewrite->get_feed_permastruct(); 90 | if ( '' != $permalink ) { 91 | $url = home_url( '/.well-known/webfinger' ); 92 | } else { 93 | $url = add_query_arg( 'well-known', 'webfinger', home_url( '/' ) ); 94 | } 95 | 96 | return $url; 97 | } 98 | 99 | /** 100 | * Returns all WebFinger "resources" 101 | * 102 | * @param mixed $id_or_name_or_object 103 | * 104 | * @return string The user-resource 105 | */ 106 | function get_webfinger_resource( $id_or_name_or_object, $with_protocol = true ) { 107 | return Webfinger::get_user_resource( $id_or_name_or_object, $with_protocol ); 108 | } 109 | -------------------------------------------------------------------------------- /languages/webfinger.pot: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2023 Matthias Pfefferle 2 | # This file is distributed under the MIT. 3 | msgid "" 4 | msgstr "" 5 | "Project-Id-Version: WebFinger 3.2.7\n" 6 | "Report-Msgid-Bugs-To: " 7 | "https://wordpress.org/support/plugin/wordpress-webfinger\n" 8 | "POT-Creation-Date: 2023-11-12 20:25:01+00:00\n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=utf-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "PO-Revision-Date: 2023-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "X-Generator: grunt-wp-i18n 1.0.3\n" 16 | 17 | #. Plugin Name of the plugin/theme 18 | msgid "WebFinger" 19 | msgstr "" 20 | 21 | #. Plugin URI of the plugin/theme 22 | msgid "https://github.com/pfefferle/wordpress-webfinger" 23 | msgstr "" 24 | 25 | #. Description of the plugin/theme 26 | msgid "WebFinger for WordPress" 27 | msgstr "" 28 | 29 | #. Author of the plugin/theme 30 | msgid "Matthias Pfefferle" 31 | msgstr "" 32 | 33 | #. Author URI of the plugin/theme 34 | msgid "https://notiz.blog/" 35 | msgstr "" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wordpress-webfinger", 3 | "description": "WebFinger for WordPress!", 4 | "devDependencies": { 5 | "grunt": "^1.0.3", 6 | "grunt-wp-readme-to-markdown": "^2.0.1", 7 | "grunt-wp-i18n": "^1.0.2" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/pfefferle/wordpress-webfinger.git" 12 | }, 13 | "keywords": [ 14 | "well-known", 15 | "discovery", 16 | "webfinger", 17 | "JRD" 18 | ], 19 | "author": "Matthias Pfefferle", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/pfefferle/wordpress-webfinger/issues" 23 | }, 24 | "homepage": "https://github.com/pfefferle/wordpress-webfinger" 25 | } 26 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | WordPress Coding Standard. 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | ./tests/ 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # WebFinger # 2 | **Contributors:** [pfefferle](https://profiles.wordpress.org/pfefferle/), [willnorris](https://profiles.wordpress.org/willnorris/) 3 | **Donate link:** https://notiz.blog/donate/ 4 | **Tags:** discovery, webfinger, JRD, ostatus, activitypub 5 | **Requires at least:** 4.2 6 | **Tested up to:** 6.6 7 | **Stable tag:** 3.2.7 8 | **License:** MIT 9 | **License URI:** https://opensource.org/licenses/MIT 10 | 11 | WebFinger for WordPress 12 | 13 | ## Description ## 14 | 15 | Enables WebFinger ([RFC 7033](http://tools.ietf.org/html/rfc7033)) support for WordPress. 16 | 17 | About WebFinger: 18 | 19 | > WebFinger is used to discover information about people or other entities on the Internet that are identified by a URI using standard Hypertext Transfer Protocol (HTTP) methods over a secure transport. A WebFinger resource returns a JavaScript Object Notation (JSON) object describing the entity that is queried. The JSON object is referred to as the JSON Resource Descriptor (JRD). 20 | 21 | (quote from the [RFC](http://tools.ietf.org/html/rfc7033)) 22 | 23 | ## Frequently Asked Questions ## 24 | 25 | ### How to extend the JRD file ### 26 | 27 | You can add your own links or properties like that: 28 | 29 | function oexchange_target_link( $array ) { 30 | $array["links"][] = array( 'rel' => 'http://oexchange.org/spec/0.8/rel/resident-target', 31 | 'href' => 'http://example.com', 32 | 'type' => 'application/xrd+xml' ); 33 | return $array; 34 | } 35 | add_filter( 'webfinger_data', 'oexchange_target_link' ); 36 | 37 | ### Add alternate file/output formats ### 38 | 39 | You can add your own links or properties like that: 40 | 41 | function render_xrd($webfinger) { 42 | // set custom header(); 43 | 44 | // JRD to XRD code 45 | 46 | exit; 47 | } 48 | add_action( 'webfinger_render', 'render_xrd', 5 ); 49 | 50 | You can find a detailed example here 51 | 52 | ### The spec ### 53 | 54 | WebFinger is specified as [RFC 7033](http://tools.ietf.org/html/rfc7033) 55 | 56 | ### The WebFinger community page ### 57 | 58 | Please visit 59 | 60 | ## Upgrade Notice ## 61 | 62 | ### 3.0.0 ### 63 | 64 | This versions drops classic WebFinger support to keep the plugin short and simple. All legacy stuff is bundled in this new plugin 65 | 66 | ## Changelog ## 67 | 68 | Project maintained on github at [pfefferle/wordpress-webfinger](https://github.com/pfefferle/wordpress-webfinger). 69 | 70 | ### 3.2.7 ### 71 | 72 | * Added: better output escaping 73 | * Fixed: stricter queries 74 | 75 | ### 3.2.6 ### 76 | 77 | * remove E-Mail address 78 | 79 | ### 3.2.5 ### 80 | 81 | * fix typo 82 | 83 | ### 3.2.4 ### 84 | 85 | * update requirements 86 | 87 | ### 3.2.3 ### 88 | 89 | * fixed `acct` scheme for discovery 90 | 91 | ### 3.2.2 ### 92 | 93 | * fixed typo (thanks @ivucica) 94 | * use `acct` as default scheme 95 | 96 | ### 3.2.1 ### 97 | 98 | * make `acct` protocol optional 99 | 100 | ### 3.2.0 ### 101 | 102 | * global refactoring 103 | 104 | ### 3.1.6 ### 105 | 106 | * added `user_nicename` as resource 107 | * fixed WordPress coding standard issues 108 | 109 | ### 3.1.5 ### 110 | 111 | * fixed PHP warning 112 | 113 | ### 3.1.4 ### 114 | 115 | * updated requirements 116 | 117 | ### 3.1.3 ### 118 | 119 | * add support for the 'aim', 'ymsgr' and 'acct' protocol 120 | 121 | ### 3.1.2 ### 122 | 123 | * fixed the legacy code 124 | * added feeds 125 | 126 | ### 3.1.1 ### 127 | 128 | * fixed 'get_user_by_various' function 129 | 130 | ### 3.1.0 ### 131 | 132 | * Added WebFinger legacy plugin, because the legacy version is still very popular and used by for example OStatus (Mastodon, Status.NET and GNU Social) 133 | * Added Webfinger for posts support 134 | 135 | ### 3.0.3 ### 136 | 137 | * composer support 138 | * compatibility updates 139 | 140 | ### 3.0.2 ### 141 | 142 | * `get_avatar_url` instead of custom code 143 | * some small code improvements 144 | * nicer PHP-docs 145 | 146 | ### 3.0.1 ### 147 | 148 | * updated version informations 149 | * support the WordPress Coding Standard 150 | 151 | ### 3.0.0 ### 152 | 153 | * added correct error-responses 154 | * remove legacy support for XRD and host-meta (props to Will Norris) 155 | 156 | ### 2.0.1 ### 157 | 158 | * small bugfix 159 | 160 | ### 2.0.0 ### 161 | 162 | * complete refactoring 163 | * removed simple-web-discovery 164 | * more filters and actions 165 | * works without /.well-known/ plugin 166 | 167 | ### 1.4.0 ### 168 | 169 | * small fixes 170 | * added "webfinger" as well-known uri 171 | 172 | ### 1.3.1 ### 173 | 174 | * added "rel"-filter (work in progress) 175 | * added more aliases 176 | 177 | ### 1.3 ### 178 | 179 | * added host-meta resource feature (see latest spec) 180 | 181 | ### 1.2 ### 182 | 183 | * added 404 http error if user doesn't exist 184 | * added jrd discovery for host-meta 185 | 186 | ### 1.1 ### 187 | 188 | * fixed an odd problem with lower WordPress versions 189 | * added support for the http://wordpress.org/extend/plugins/extended-profile/ (thanks to Singpolyma) 190 | 191 | ### 1.0.1 ### 192 | 193 | * api improvements 194 | 195 | ### 1.0 ### 196 | 197 | * basic simple-seb-discovery 198 | * json support 199 | * some small improvements 200 | 201 | ### 0.9.1 ### 202 | 203 | * some changes to support http://unhosted.org 204 | 205 | ### 0.9 ### 206 | 207 | * OStatus improvements 208 | * Better uri handling 209 | * Identifier overview (more to come) 210 | * Added filters 211 | * Added functions to get a users webfingers 212 | 213 | ### 0.7 ### 214 | 215 | * Added do_action param (for future OStatus plugin) 216 | * Author-Url as Webfinger-Identifier 217 | 218 | ### 0.5 ### 219 | 220 | * Initial release 221 | 222 | ## Installation ## 223 | 224 | Follow the normal instructions for [installing WordPress plugins](https://codex.wordpress.org/Managing_Plugins#Installing_Plugins). 225 | 226 | ### Automatic Plugin Installation ### 227 | 228 | To add a WordPress Plugin using the [built-in plugin installer](https://codex.wordpress.org/Administration_Screens#Add_New_Plugins): 229 | 230 | 1. Go to [Plugins](https://codex.wordpress.org/Administration_Screens#Plugins) > [Add New](https://codex.wordpress.org/Plugins_Add_New_Screen). 231 | 1. Type "`webfinger`" into the **Search Plugins** box. 232 | 1. Find the WordPress Plugin you wish to install. 233 | 1. Click **Details** for more information about the Plugin and instructions you may wish to print or save to help setup the Plugin. 234 | 1. Click **Install Now** to install the WordPress Plugin. 235 | 1. The resulting installation screen will list the installation as successful or note any problems during the install. 236 | 1. If successful, click **Activate Plugin** to activate it, or **Return to Plugin Installer** for further actions. 237 | 238 | ### Manual Plugin Installation ### 239 | 240 | There are a few cases when manually installing a WordPress Plugin is appropriate. 241 | 242 | * If you wish to control the placement and the process of installing a WordPress Plugin. 243 | * If your server does not permit automatic installation of a WordPress Plugin. 244 | * If you want to try the [latest development version](https://github.com/pfefferle/wordpress-webfinger). 245 | 246 | Installation of a WordPress Plugin manually requires FTP familiarity and the awareness that you may put your site at risk if you install a WordPress Plugin incompatible with the current version or from an unreliable source. 247 | 248 | Backup your site completely before proceeding. 249 | 250 | To install a WordPress Plugin manually: 251 | 252 | * Download your WordPress Plugin to your desktop. 253 | * Download from [the WordPress directory](https://wordpress.org/plugins/webfinger/) 254 | * Download from [GitHub](https://github.com/pfefferle/wordpress-webfinger/releases) 255 | * If downloaded as a zip archive, extract the Plugin folder to your desktop. 256 | * With your FTP program, upload the Plugin folder to the `wp-content/plugins` folder in your WordPress directory online. 257 | * Go to [Plugins screen](https://codex.wordpress.org/Administration_Screens#Plugins) and find the newly uploaded Plugin in the list. 258 | * Click **Activate** to activate it. 259 | -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | === WebFinger === 2 | Contributors: pfefferle, willnorris 3 | Donate link: https://notiz.blog/donate/ 4 | Tags: discovery, webfinger, JRD, ostatus, activitypub 5 | Requires at least: 4.2 6 | Tested up to: 6.6 7 | Stable tag: 3.2.7 8 | License: MIT 9 | License URI: https://opensource.org/licenses/MIT 10 | 11 | WebFinger for WordPress 12 | 13 | == Description == 14 | 15 | Enables WebFinger ([RFC 7033](http://tools.ietf.org/html/rfc7033)) support for WordPress. 16 | 17 | About WebFinger: 18 | 19 | > WebFinger is used to discover information about people or other entities on the Internet that are identified by a URI using standard Hypertext Transfer Protocol (HTTP) methods over a secure transport. A WebFinger resource returns a JavaScript Object Notation (JSON) object describing the entity that is queried. The JSON object is referred to as the JSON Resource Descriptor (JRD). 20 | 21 | (quote from the [RFC](http://tools.ietf.org/html/rfc7033)) 22 | 23 | == Frequently Asked Questions == 24 | 25 | = How to extend the JRD file = 26 | 27 | You can add your own links or properties like that: 28 | 29 | function oexchange_target_link( $array ) { 30 | $array["links"][] = array( 'rel' => 'http://oexchange.org/spec/0.8/rel/resident-target', 31 | 'href' => 'http://example.com', 32 | 'type' => 'application/xrd+xml' ); 33 | return $array; 34 | } 35 | add_filter( 'webfinger_data', 'oexchange_target_link' ); 36 | 37 | = Add alternate file/output formats = 38 | 39 | You can add your own links or properties like that: 40 | 41 | function render_xrd($webfinger) { 42 | // set custom header(); 43 | 44 | // JRD to XRD code 45 | 46 | exit; 47 | } 48 | add_action( 'webfinger_render', 'render_xrd', 5 ); 49 | 50 | You can find a detailed example here 51 | 52 | = The spec = 53 | 54 | WebFinger is specified as [RFC 7033](http://tools.ietf.org/html/rfc7033) 55 | 56 | = The WebFinger community page = 57 | 58 | Please visit 59 | 60 | == Upgrade Notice == 61 | 62 | = 3.0.0 = 63 | 64 | This versions drops classic WebFinger support to keep the plugin short and simple. All legacy stuff is bundled in this new plugin 65 | 66 | == Changelog == 67 | 68 | Project maintained on github at [pfefferle/wordpress-webfinger](https://github.com/pfefferle/wordpress-webfinger). 69 | 70 | = 3.2.7 = 71 | 72 | * Added: better output escaping 73 | * Fixed: stricter queries 74 | 75 | = 3.2.6 = 76 | 77 | * remove E-Mail address 78 | 79 | = 3.2.5 = 80 | 81 | * fix typo 82 | 83 | = 3.2.4 = 84 | 85 | * update requirements 86 | 87 | = 3.2.3 = 88 | 89 | * fixed `acct` scheme for discovery 90 | 91 | = 3.2.2 = 92 | 93 | * fixed typo (thanks @ivucica) 94 | * use `acct` as default scheme 95 | 96 | = 3.2.1 = 97 | 98 | * make `acct` protocol optional 99 | 100 | = 3.2.0 = 101 | 102 | * global refactoring 103 | 104 | = 3.1.6 = 105 | 106 | * added `user_nicename` as resource 107 | * fixed WordPress coding standard issues 108 | 109 | = 3.1.5 = 110 | 111 | * fixed PHP warning 112 | 113 | = 3.1.4 = 114 | 115 | * updated requirements 116 | 117 | = 3.1.3 = 118 | 119 | * add support for the 'aim', 'ymsgr' and 'acct' protocol 120 | 121 | = 3.1.2 = 122 | 123 | * fixed the legacy code 124 | * added feeds 125 | 126 | = 3.1.1 = 127 | 128 | * fixed 'get_user_by_various' function 129 | 130 | = 3.1.0 = 131 | 132 | * Added WebFinger legacy plugin, because the legacy version is still very popular and used by for example OStatus (Mastodon, Status.NET and GNU Social) 133 | * Added Webfinger for posts support 134 | 135 | = 3.0.3 = 136 | 137 | * composer support 138 | * compatibility updates 139 | 140 | = 3.0.2 = 141 | 142 | * `get_avatar_url` instead of custom code 143 | * some small code improvements 144 | * nicer PHP-docs 145 | 146 | = 3.0.1 = 147 | 148 | * updated version informations 149 | * support the WordPress Coding Standard 150 | 151 | = 3.0.0 = 152 | 153 | * added correct error-responses 154 | * remove legacy support for XRD and host-meta (props to Will Norris) 155 | 156 | = 2.0.1 = 157 | 158 | * small bugfix 159 | 160 | = 2.0.0 = 161 | 162 | * complete refactoring 163 | * removed simple-web-discovery 164 | * more filters and actions 165 | * works without /.well-known/ plugin 166 | 167 | = 1.4.0 = 168 | 169 | * small fixes 170 | * added "webfinger" as well-known uri 171 | 172 | = 1.3.1 = 173 | 174 | * added "rel"-filter (work in progress) 175 | * added more aliases 176 | 177 | = 1.3 = 178 | 179 | * added host-meta resource feature (see latest spec) 180 | 181 | = 1.2 = 182 | 183 | * added 404 http error if user doesn't exist 184 | * added jrd discovery for host-meta 185 | 186 | = 1.1 = 187 | 188 | * fixed an odd problem with lower WordPress versions 189 | * added support for the http://wordpress.org/extend/plugins/extended-profile/ (thanks to Singpolyma) 190 | 191 | = 1.0.1 = 192 | 193 | * api improvements 194 | 195 | = 1.0 = 196 | 197 | * basic simple-seb-discovery 198 | * json support 199 | * some small improvements 200 | 201 | = 0.9.1 = 202 | 203 | * some changes to support http://unhosted.org 204 | 205 | = 0.9 = 206 | 207 | * OStatus improvements 208 | * Better uri handling 209 | * Identifier overview (more to come) 210 | * Added filters 211 | * Added functions to get a users webfingers 212 | 213 | = 0.7 = 214 | 215 | * Added do_action param (for future OStatus plugin) 216 | * Author-Url as Webfinger-Identifier 217 | 218 | = 0.5 = 219 | 220 | * Initial release 221 | 222 | == Installation == 223 | 224 | Follow the normal instructions for [installing WordPress plugins](https://codex.wordpress.org/Managing_Plugins#Installing_Plugins). 225 | 226 | = Automatic Plugin Installation = 227 | 228 | To add a WordPress Plugin using the [built-in plugin installer](https://codex.wordpress.org/Administration_Screens#Add_New_Plugins): 229 | 230 | 1. Go to [Plugins](https://codex.wordpress.org/Administration_Screens#Plugins) > [Add New](https://codex.wordpress.org/Plugins_Add_New_Screen). 231 | 1. Type "`webfinger`" into the **Search Plugins** box. 232 | 1. Find the WordPress Plugin you wish to install. 233 | 1. Click **Details** for more information about the Plugin and instructions you may wish to print or save to help setup the Plugin. 234 | 1. Click **Install Now** to install the WordPress Plugin. 235 | 1. The resulting installation screen will list the installation as successful or note any problems during the install. 236 | 1. If successful, click **Activate Plugin** to activate it, or **Return to Plugin Installer** for further actions. 237 | 238 | = Manual Plugin Installation = 239 | 240 | There are a few cases when manually installing a WordPress Plugin is appropriate. 241 | 242 | * If you wish to control the placement and the process of installing a WordPress Plugin. 243 | * If your server does not permit automatic installation of a WordPress Plugin. 244 | * If you want to try the [latest development version](https://github.com/pfefferle/wordpress-webfinger). 245 | 246 | Installation of a WordPress Plugin manually requires FTP familiarity and the awareness that you may put your site at risk if you install a WordPress Plugin incompatible with the current version or from an unreliable source. 247 | 248 | Backup your site completely before proceeding. 249 | 250 | To install a WordPress Plugin manually: 251 | 252 | * Download your WordPress Plugin to your desktop. 253 | * Download from [the WordPress directory](https://wordpress.org/plugins/webfinger/) 254 | * Download from [GitHub](https://github.com/pfefferle/wordpress-webfinger/releases) 255 | * If downloaded as a zip archive, extract the Plugin folder to your desktop. 256 | * With your FTP program, upload the Plugin folder to the `wp-content/plugins` folder in your WordPress directory online. 257 | * Go to [Plugins screen](https://codex.wordpress.org/Administration_Screens#Plugins) and find the newly uploaded Plugin in the list. 258 | * Click **Activate** to activate it. 259 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 |