WebFinger: Add support for URLs (#594)
* add support for URLs * phpcs * simplify vars
This commit is contained in:
parent
e5fe4f20b7
commit
431c4a2676
4 changed files with 142 additions and 23 deletions
|
@ -7,6 +7,7 @@ use Activitypub\Model\User;
|
||||||
use Activitypub\Model\Blog_User;
|
use Activitypub\Model\Blog_User;
|
||||||
use Activitypub\Model\Application_User;
|
use Activitypub\Model\Application_User;
|
||||||
|
|
||||||
|
use function Activitypub\url_to_authorid;
|
||||||
use function Activitypub\is_user_disabled;
|
use function Activitypub\is_user_disabled;
|
||||||
|
|
||||||
class Users {
|
class Users {
|
||||||
|
@ -103,6 +104,8 @@ class Users {
|
||||||
return self::get_by_id( $user->results[0] );
|
return self::get_by_id( $user->results[0] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$username = str_replace( array( '*', '%' ), '', $username );
|
||||||
|
|
||||||
// check for login or nicename.
|
// check for login or nicename.
|
||||||
$user = new WP_User_Query(
|
$user = new WP_User_Query(
|
||||||
array(
|
array(
|
||||||
|
@ -133,21 +136,59 @@ class Users {
|
||||||
* @return \Acitvitypub\Model\User The User.
|
* @return \Acitvitypub\Model\User The User.
|
||||||
*/
|
*/
|
||||||
public static function get_by_resource( $resource ) {
|
public static function get_by_resource( $resource ) {
|
||||||
if ( \strpos( $resource, '@' ) === false ) {
|
$scheme = 'acct';
|
||||||
return new WP_Error(
|
$match = array();
|
||||||
'activitypub_unsupported_resource',
|
// try to extract the scheme and the host
|
||||||
\__( 'Resource is invalid', 'activitypub' ),
|
if ( preg_match( '/^([a-zA-Z^:]+):(.*)$/i', $resource, $match ) ) {
|
||||||
array( 'status' => 400 )
|
// extract the scheme
|
||||||
);
|
$scheme = esc_attr( $match[1] );
|
||||||
}
|
}
|
||||||
|
|
||||||
$resource = \str_replace( 'acct:', '', $resource );
|
switch ( $scheme ) {
|
||||||
|
// check for http(s) URIs
|
||||||
|
case 'http':
|
||||||
|
case 'https':
|
||||||
|
$url_parts = wp_parse_url( $resource );
|
||||||
|
|
||||||
$resource_identifier = \substr( $resource, 0, \strrpos( $resource, '@' ) );
|
// check for http(s)://blog.example.com/@username
|
||||||
$resource_host = self::normalize_host( \substr( \strrchr( $resource, '@' ), 1 ) );
|
if (
|
||||||
|
isset( $url_parts['path'] ) &&
|
||||||
|
str_starts_with( $url_parts['path'], '/@' )
|
||||||
|
) {
|
||||||
|
$identifier = str_replace( '/@', '', $url_parts['path'] );
|
||||||
|
$identifier = untrailingslashit( $identifier );
|
||||||
|
|
||||||
|
return self::get_by_username( $identifier );
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for http(s)://blog.example.com/author/username
|
||||||
|
$user_id = url_to_authorid( $resource );
|
||||||
|
|
||||||
|
if ( $user_id ) {
|
||||||
|
return self::get_by_id( $user_id );
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for http(s)://blog.example.com/
|
||||||
|
if (
|
||||||
|
self::normalize_url( site_url() ) === self::normalize_url( $resource ) ||
|
||||||
|
self::normalize_url( home_url() ) === self::normalize_url( $resource )
|
||||||
|
) {
|
||||||
|
return self::get_by_id( self::BLOG_USER_ID );
|
||||||
|
}
|
||||||
|
|
||||||
|
return new WP_Error(
|
||||||
|
'activitypub_no_user_found',
|
||||||
|
\__( 'User not found', 'activitypub' ),
|
||||||
|
array( 'status' => 404 )
|
||||||
|
);
|
||||||
|
// check for acct URIs
|
||||||
|
case 'acct':
|
||||||
|
$resource = \str_replace( 'acct:', '', $resource );
|
||||||
|
$identifier = \substr( $resource, 0, \strrpos( $resource, '@' ) );
|
||||||
|
$host = self::normalize_host( \substr( \strrchr( $resource, '@' ), 1 ) );
|
||||||
$blog_host = self::normalize_host( \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) );
|
$blog_host = self::normalize_host( \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) );
|
||||||
|
|
||||||
if ( $blog_host !== $resource_host ) {
|
if ( $blog_host !== $host ) {
|
||||||
return new WP_Error(
|
return new WP_Error(
|
||||||
'activitypub_wrong_host',
|
'activitypub_wrong_host',
|
||||||
\__( 'Resource host does not match blog host', 'activitypub' ),
|
\__( 'Resource host does not match blog host', 'activitypub' ),
|
||||||
|
@ -155,7 +196,19 @@ class Users {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::get_by_username( $resource_identifier );
|
// prepare wildcards https://github.com/mastodon/mastodon/issues/22213
|
||||||
|
if ( in_array( $identifier, array( '_', '*', '' ), true ) ) {
|
||||||
|
return self::get_by_id( self::BLOG_USER_ID );
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::get_by_username( $identifier );
|
||||||
|
default:
|
||||||
|
return new WP_Error(
|
||||||
|
'activitypub_wrong_scheme',
|
||||||
|
\__( 'Wrong scheme', 'activitypub' ),
|
||||||
|
array( 'status' => 404 )
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -168,7 +221,12 @@ class Users {
|
||||||
public static function get_by_various( $id ) {
|
public static function get_by_various( $id ) {
|
||||||
if ( is_numeric( $id ) ) {
|
if ( is_numeric( $id ) ) {
|
||||||
return self::get_by_id( $id );
|
return self::get_by_id( $id );
|
||||||
} elseif ( filter_var( $id, FILTER_VALIDATE_URL ) ) {
|
} elseif (
|
||||||
|
// is URL
|
||||||
|
filter_var( $id, FILTER_VALIDATE_URL ) ||
|
||||||
|
// is acct
|
||||||
|
str_starts_with( $id, 'acct:' )
|
||||||
|
) {
|
||||||
return self::get_by_resource( $id );
|
return self::get_by_resource( $id );
|
||||||
} else {
|
} else {
|
||||||
return self::get_by_username( $id );
|
return self::get_by_username( $id );
|
||||||
|
@ -176,7 +234,7 @@ class Users {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize the host.
|
* Normalize a host.
|
||||||
*
|
*
|
||||||
* @param string $host The host.
|
* @param string $host The host.
|
||||||
*
|
*
|
||||||
|
@ -186,6 +244,22 @@ class Users {
|
||||||
return \str_replace( 'www.', '', $host );
|
return \str_replace( 'www.', '', $host );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize a URL.
|
||||||
|
*
|
||||||
|
* @param string $url The URL.
|
||||||
|
*
|
||||||
|
* @return string The normalized URL.
|
||||||
|
*/
|
||||||
|
public static function normalize_url( $url ) {
|
||||||
|
$url = \untrailingslashit( $url );
|
||||||
|
$url = \str_replace( 'https://', '', $url );
|
||||||
|
$url = \str_replace( 'http://', '', $url );
|
||||||
|
$url = \str_replace( 'www.', '', $url );
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the User collection.
|
* Get the User collection.
|
||||||
*
|
*
|
||||||
|
|
|
@ -72,7 +72,7 @@ class Webfinger {
|
||||||
$params['resource'] = array(
|
$params['resource'] = array(
|
||||||
'required' => true,
|
'required' => true,
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'pattern' => '^acct:(.+)@(.+)$',
|
'pattern' => '^(acct:)|^(https?://)(.+)$',
|
||||||
);
|
);
|
||||||
|
|
||||||
return $params;
|
return $params;
|
||||||
|
|
|
@ -53,10 +53,12 @@ class Webfinger {
|
||||||
* @return array the jrd array
|
* @return array the jrd array
|
||||||
*/
|
*/
|
||||||
public static function add_pseudo_user_discovery( $array, $resource ) {
|
public static function add_pseudo_user_discovery( $array, $resource ) {
|
||||||
if ( $array ) {
|
$user = Webfinger_Rest::get_profile( $resource );
|
||||||
|
|
||||||
|
if ( ! $user || is_wp_error( $user ) ) {
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Webfinger_Rest::get_profile( $resource );
|
return $user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
43
tests/test-class-activitypub-users-collection.php
Normal file
43
tests/test-class-activitypub-users-collection.php
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
class Test_Activitypub_Users_Collection extends WP_UnitTestCase {
|
||||||
|
|
||||||
|
public function set_up() {
|
||||||
|
parent::set_up();
|
||||||
|
|
||||||
|
add_option( 'activitypub_blog_user_identifier', 'blog' );
|
||||||
|
add_user_meta( 1, 'activitypub_user_identifier', 'admin' );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @dataProvider the_resource_provider
|
||||||
|
*/
|
||||||
|
public function test_get_by_various( $resource, $expected ) {
|
||||||
|
$user = Activitypub\Collection\Users::get_by_resource( $resource );
|
||||||
|
|
||||||
|
$this->assertInstanceOf( $expected, $user );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function the_resource_provider() {
|
||||||
|
return array(
|
||||||
|
array( 'http://example.org/?author=1', 'Activitypub\Model\User' ),
|
||||||
|
array( 'https://example.org/?author=1', 'Activitypub\Model\User' ),
|
||||||
|
array( 'http://example.org/?author=7', 'WP_Error' ),
|
||||||
|
array( 'acct:admin@example.org', 'Activitypub\Model\User' ),
|
||||||
|
array( 'acct:blog@example.org', 'Activitypub\Model\Blog_User' ),
|
||||||
|
array( 'acct:*@example.org', 'Activitypub\Model\Blog_User' ),
|
||||||
|
array( 'acct:_@example.org', 'Activitypub\Model\Blog_User' ),
|
||||||
|
array( 'acct:aksd@example.org', 'WP_Error' ),
|
||||||
|
array( 'admin@example.org', 'Activitypub\Model\User' ),
|
||||||
|
array( 'acct:application@example.org', 'Activitypub\Model\Application_User' ),
|
||||||
|
array( 'http://example.org/@admin', 'Activitypub\Model\User' ),
|
||||||
|
array( 'http://example.org/@blog', 'Activitypub\Model\Blog_User' ),
|
||||||
|
array( 'https://example.org/@blog', 'Activitypub\Model\Blog_User' ),
|
||||||
|
array( 'http://example.org/@blog/', 'Activitypub\Model\Blog_User' ),
|
||||||
|
array( 'http://example.org/', 'Activitypub\Model\Blog_User' ),
|
||||||
|
array( 'http://example.org', 'Activitypub\Model\Blog_User' ),
|
||||||
|
array( 'https://example.org/', 'Activitypub\Model\Blog_User' ),
|
||||||
|
array( 'https://example.org', 'Activitypub\Model\Blog_User' ),
|
||||||
|
array( 'http://example.org/@blog/s', 'WP_Error' ),
|
||||||
|
array( 'http://example.org/@blogs/', 'WP_Error' ),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue