PluginProbe
ActivityPub / 3.2.2
ActivityPub v3.2.2
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
← All changes | includes/collection/class-users.php +112 -43 1.2.0 → 3.2.2 View file →
@@ -3,11 +3,15 @@
3 3
4 4 use WP_Error;
5 5 use WP_User_Query;
6 6 use Activitypub\Model\User;
7 -use Activitypub\Model\Blog_User;
8 -use Activitypub\Model\Application_User;
7 +use Activitypub\Model\Blog;
8 +use Activitypub\Model\Application;
9 9
10 +use function Activitypub\object_to_uri;
11 +use function Activitypub\normalize_url;
12 +use function Activitypub\normalize_host;
13 +use function Activitypub\url_to_authorid;
10 14 use function Activitypub\is_user_disabled;
11 15
12 16 class Users {
13 17 /**
@@ -44,11 +48,11 @@
44 48 );
45 49 }
46 50
47 51 if ( self::BLOG_USER_ID === $user_id ) {
48 - return Blog_User::from_wp_user( $user_id );
52 + return new Blog();
49 53 } elseif ( self::APPLICATION_USER_ID === $user_id ) {
50 - return Application_User::from_wp_user( $user_id );
54 + return new Application();
51 55 } elseif ( $user_id > 0 ) {
52 56 return User::from_wp_user( $user_id );
53 57 }
54 58
@@ -67,24 +71,25 @@
67 71 * @return \Acitvitypub\Model\User The User.
68 72 */
69 73 public static function get_by_username( $username ) {
70 74 // check for blog user.
71 - if ( Blog_User::get_default_username() === $username ) {
72 - return self::get_by_id( self::BLOG_USER_ID );
75 + if ( Blog::get_default_username() === $username ) {
76 + return new Blog();
73 77 }
74 78
75 - if ( get_option( 'activitypub_blog_user_identifier' ) === $username ) {
76 - return self::get_by_id( self::BLOG_USER_ID );
79 + if ( get_option( 'activitypub_blog_identifier' ) === $username ) {
80 + return new Blog();
77 81 }
78 82
79 83 // check for application user.
80 84 if ( 'application' === $username ) {
81 - return self::get_by_id( self::APPLICATION_USER_ID );
85 + return new Application();
82 86 }
83 87
84 88 // check for 'activitypub_username' meta
85 89 $user = new WP_User_Query(
86 90 array(
91 + 'count_total' => false,
87 92 'number' => 1,
88 93 'hide_empty' => true,
89 94 'fields' => 'ID',
90 95 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
@@ -102,11 +107,14 @@
102 107 if ( $user->results ) {
103 108 return self::get_by_id( $user->results[0] );
104 109 }
105 110
111 + $username = str_replace( array( '*', '%' ), '', $username );
112 +
106 113 // check for login or nicename.
107 114 $user = new WP_User_Query(
108 115 array(
116 + 'count_total' => false,
109 117 'search' => $username,
110 118 'search_columns' => array( 'user_login', 'user_nicename' ),
111 119 'number' => 1,
112 120 'hide_empty' => true,
@@ -132,31 +140,90 @@
132 140 *
133 141 * @return \Acitvitypub\Model\User The User.
134 142 */
135 143 public static function get_by_resource( $resource ) {
136 - if ( \strpos( $resource, '@' ) === false ) {
137 - return new WP_Error(
138 - 'activitypub_unsupported_resource',
139 - \__( 'Resource is invalid', 'activitypub' ),
140 - array( 'status' => 400 )
141 - );
144 + $resource = object_to_uri( $resource );
145 +
146 + $scheme = 'acct';
147 + $match = array();
148 + // try to extract the scheme and the host
149 + if ( preg_match( '/^([a-zA-Z^:]+):(.*)$/i', $resource, $match ) ) {
150 + // extract the scheme
151 + $scheme = \esc_attr( $match[1] );
142 152 }
143 153
144 - $resource = \str_replace( 'acct:', '', $resource );
154 + switch ( $scheme ) {
155 + // check for http(s) URIs
156 + case 'http':
157 + case 'https':
158 + $resource_path = \wp_parse_url( $resource, PHP_URL_PATH );
145 159
146 - $resource_identifier = \substr( $resource, 0, \strrpos( $resource, '@' ) );
147 - $resource_host = self::normalize_host( \substr( \strrchr( $resource, '@' ), 1 ) );
148 - $blog_host = self::normalize_host( \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) );
160 + if ( $resource_path ) {
161 + $blog_path = \wp_parse_url( \home_url(), PHP_URL_PATH );
149 162
150 - if ( $blog_host !== $resource_host ) {
151 - return new WP_Error(
152 - 'activitypub_wrong_host',
153 - \__( 'Resource host does not match blog host', 'activitypub' ),
154 - array( 'status' => 404 )
155 - );
163 + if ( $blog_path ) {
164 + $resource_path = \str_replace( $blog_path, '', $resource_path );
165 + }
166 +
167 + $resource_path = \trim( $resource_path, '/' );
168 +
169 + // check for http(s)://blog.example.com/@username
170 + if ( str_starts_with( $resource_path, '@' ) ) {
171 + $identifier = \str_replace( '@', '', $resource_path );
172 + $identifier = \trim( $identifier, '/' );
173 +
174 + return self::get_by_username( $identifier );
175 + }
176 + }
177 +
178 + // check for http(s)://blog.example.com/author/username
179 + $user_id = url_to_authorid( $resource );
180 +
181 + if ( $user_id ) {
182 + return self::get_by_id( $user_id );
183 + }
184 +
185 + // check for http(s)://blog.example.com/
186 + if (
187 + normalize_url( site_url() ) === normalize_url( $resource ) ||
188 + normalize_url( home_url() ) === normalize_url( $resource )
189 + ) {
190 + return self::get_by_id( self::BLOG_USER_ID );
191 + }
192 +
193 + return new WP_Error(
194 + 'activitypub_no_user_found',
195 + \__( 'User not found', 'activitypub' ),
196 + array( 'status' => 404 )
197 + );
198 + // check for acct URIs
199 + case 'acct':
200 + $resource = \str_replace( 'acct:', '', $resource );
201 + $identifier = \substr( $resource, 0, \strrpos( $resource, '@' ) );
202 + $host = normalize_host( \substr( \strrchr( $resource, '@' ), 1 ) );
203 + $blog_host = normalize_host( \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) );
204 +
205 + if ( $blog_host !== $host ) {
206 + return new WP_Error(
207 + 'activitypub_wrong_host',
208 + \__( 'Resource host does not match blog host', 'activitypub' ),
209 + array( 'status' => 404 )
210 + );
211 + }
212 +
213 + // prepare wildcards https://github.com/mastodon/mastodon/issues/22213
214 + if ( in_array( $identifier, array( '_', '*', '' ), true ) ) {
215 + return self::get_by_id( self::BLOG_USER_ID );
216 + }
217 +
218 + return self::get_by_username( $identifier );
219 + default:
220 + return new WP_Error(
221 + 'activitypub_wrong_scheme',
222 + \__( 'Wrong scheme', 'activitypub' ),
223 + array( 'status' => 404 )
224 + );
156 225 }
157 -
158 - return self::get_by_username( $resource_identifier );
159 226 }
160 227
161 228 /**
162 229 * Get the User by resource.
@@ -165,26 +232,28 @@
165 232 *
166 233 * @return \Acitvitypub\Model\User The User.
167 234 */
168 235 public static function get_by_various( $id ) {
236 + $user = null;
237 +
169 238 if ( is_numeric( $id ) ) {
170 - return self::get_by_id( $id );
171 - } elseif ( filter_var( $id, FILTER_VALIDATE_URL ) ) {
172 - return self::get_by_resource( $id );
173 - } else {
174 - return self::get_by_username( $id );
239 + $user = self::get_by_id( $id );
240 + } elseif (
241 + // is URL
242 + filter_var( $id, FILTER_VALIDATE_URL ) ||
243 + // is acct
244 + str_starts_with( $id, 'acct:' ) ||
245 + // is email
246 + filter_var( $id, FILTER_VALIDATE_EMAIL )
247 + ) {
248 + $user = self::get_by_resource( $id );
175 249 }
176 - }
177 250
178 - /**
179 - * Normalize the host.
180 - *
181 - * @param string $host The host.
182 - *
183 - * @return string The normalized host.
184 - */
185 - public static function normalize_host( $host ) {
186 - return \str_replace( 'www.', '', $host );
251 + if ( $user && ! is_wp_error( $user ) ) {
252 + return $user;
253 + }
254 +
255 + return self::get_by_username( $id );
187 256 }
188 257
189 258 /**
190 259 * Get the User collection.
@@ -193,9 +262,9 @@
193 262 */
194 263 public static function get_collection() {
195 264 $users = \get_users(
196 265 array(
197 - 'capability__in' => array( 'publish_posts' ),
266 + 'capability__in' => array( 'activitypub' ),
198 267 )
199 268 );
200 269
201 270 $return = array();