PluginProbe
ActivityPub / 4.1.1
ActivityPub v4.1.1
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
activitypub / includes / collection / class-users.php

class-users.php in ActivityPub 4.1.1, at includes/collection/class-users.php

290 lines 6.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Users collection file.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Collection;
9
10 use WP_Error;
11 use WP_User_Query;
12 use Activitypub\Model\User;
13 use Activitypub\Model\Blog;
14 use Activitypub\Model\Application;
15
16 use function Activitypub\object_to_uri;
17 use function Activitypub\normalize_url;
18 use function Activitypub\normalize_host;
19 use function Activitypub\url_to_authorid;
20 use function Activitypub\is_user_disabled;
21
22 /**
23 * Users collection.
24 */
25 class Users {
26 /**
27 * The ID of the Blog User.
28 *
29 * @var int
30 */
31 const BLOG_USER_ID = 0;
32
33 /**
34 * The ID of the Application User.
35 *
36 * @var int
37 */
38 const APPLICATION_USER_ID = -1;
39
40 /**
41 * Get the User by ID.
42 *
43 * @param int $user_id The User-ID.
44 *
45 * @return User|Blog|Application|WP_Error The User or WP_Error if user not found.
46 */
47 public static function get_by_id( $user_id ) {
48 if ( is_string( $user_id ) || is_numeric( $user_id ) ) {
49 $user_id = (int) $user_id;
50 }
51
52 if ( is_user_disabled( $user_id ) ) {
53 return new WP_Error(
54 'activitypub_user_not_found',
55 \__( 'User not found', 'activitypub' ),
56 array( 'status' => 404 )
57 );
58 }
59
60 if ( self::BLOG_USER_ID === $user_id ) {
61 return new Blog();
62 } elseif ( self::APPLICATION_USER_ID === $user_id ) {
63 return new Application();
64 } elseif ( $user_id > 0 ) {
65 return User::from_wp_user( $user_id );
66 }
67
68 return new WP_Error(
69 'activitypub_user_not_found',
70 \__( 'User not found', 'activitypub' ),
71 array( 'status' => 404 )
72 );
73 }
74
75 /**
76 * Get the User by username.
77 *
78 * @param string $username The User-Name.
79 *
80 * @return User|Blog|Application|WP_Error The User or WP_Error if user not found.
81 */
82 public static function get_by_username( $username ) {
83 // Check for blog user.
84 if ( Blog::get_default_username() === $username ) {
85 return new Blog();
86 }
87
88 if ( get_option( 'activitypub_blog_identifier' ) === $username ) {
89 return new Blog();
90 }
91
92 // Check for application user.
93 if ( 'application' === $username ) {
94 return new Application();
95 }
96
97 // Check for 'activitypub_username' meta.
98 $user = new WP_User_Query(
99 array(
100 'count_total' => false,
101 'number' => 1,
102 'hide_empty' => true,
103 'fields' => 'ID',
104 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
105 'meta_query' => array(
106 'relation' => 'OR',
107 array(
108 'key' => 'activitypub_user_identifier',
109 'value' => $username,
110 'compare' => 'LIKE',
111 ),
112 ),
113 )
114 );
115
116 if ( $user->results ) {
117 return self::get_by_id( $user->results[0] );
118 }
119
120 $username = str_replace( array( '*', '%' ), '', $username );
121
122 // Check for login or nicename.
123 $user = new WP_User_Query(
124 array(
125 'count_total' => false,
126 'search' => $username,
127 'search_columns' => array( 'user_login', 'user_nicename' ),
128 'number' => 1,
129 'hide_empty' => true,
130 'fields' => 'ID',
131 )
132 );
133
134 if ( $user->results ) {
135 return self::get_by_id( $user->results[0] );
136 }
137
138 return new WP_Error(
139 'activitypub_user_not_found',
140 \__( 'User not found', 'activitypub' ),
141 array( 'status' => 404 )
142 );
143 }
144
145 /**
146 * Get the User by resource.
147 *
148 * @param string $uri The User-Resource.
149 *
150 * @return User|WP_Error The User or WP_Error if user not found.
151 */
152 public static function get_by_resource( $uri ) {
153 $uri = object_to_uri( $uri );
154
155 $scheme = 'acct';
156 $match = array();
157 // Try to extract the scheme and the host.
158 if ( preg_match( '/^([a-zA-Z^:]+):(.*)$/i', $uri, $match ) ) {
159 // Extract the scheme.
160 $scheme = \esc_attr( $match[1] );
161 }
162
163 switch ( $scheme ) {
164 // Check for http(s) URIs.
165 case 'http':
166 case 'https':
167 $resource_path = \wp_parse_url( $uri, PHP_URL_PATH );
168
169 if ( $resource_path ) {
170 $blog_path = \wp_parse_url( \home_url(), PHP_URL_PATH );
171
172 if ( $blog_path ) {
173 $resource_path = \str_replace( $blog_path, '', $resource_path );
174 }
175
176 $resource_path = \trim( $resource_path, '/' );
177
178 // Check for http(s)://blog.example.com/@username.
179 if ( str_starts_with( $resource_path, '@' ) ) {
180 $identifier = \str_replace( '@', '', $resource_path );
181 $identifier = \trim( $identifier, '/' );
182
183 return self::get_by_username( $identifier );
184 }
185 }
186
187 // Check for http(s)://blog.example.com/author/username.
188 $user_id = url_to_authorid( $uri );
189
190 if ( \is_int( $user_id ) ) {
191 return self::get_by_id( $user_id );
192 }
193
194 // Check for http(s)://blog.example.com/.
195 $normalized_uri = normalize_url( $uri );
196
197 if (
198 normalize_url( site_url() ) === $normalized_uri ||
199 normalize_url( home_url() ) === $normalized_uri
200 ) {
201 return self::get_by_id( self::BLOG_USER_ID );
202 }
203
204 return new WP_Error(
205 'activitypub_no_user_found',
206 \__( 'User not found', 'activitypub' ),
207 array( 'status' => 404 )
208 );
209 // Check for acct URIs.
210 case 'acct':
211 $uri = \str_replace( 'acct:', '', $uri );
212 $identifier = \substr( $uri, 0, \strrpos( $uri, '@' ) );
213 $host = normalize_host( \substr( \strrchr( $uri, '@' ), 1 ) );
214 $blog_host = normalize_host( \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) );
215
216 if ( $blog_host !== $host ) {
217 return new WP_Error(
218 'activitypub_wrong_host',
219 \__( 'Resource host does not match blog host', 'activitypub' ),
220 array( 'status' => 404 )
221 );
222 }
223
224 // Prepare wildcards https://github.com/mastodon/mastodon/issues/22213.
225 if ( in_array( $identifier, array( '_', '*', '' ), true ) ) {
226 return self::get_by_id( self::BLOG_USER_ID );
227 }
228
229 return self::get_by_username( $identifier );
230 default:
231 return new WP_Error(
232 'activitypub_wrong_scheme',
233 \__( 'Wrong scheme', 'activitypub' ),
234 array( 'status' => 404 )
235 );
236 }
237 }
238
239 /**
240 * Get the User by resource.
241 *
242 * @param string $id The User-Resource.
243 *
244 * @return User|Blog|Application|WP_Error The User or WP_Error if user not found.
245 */
246 public static function get_by_various( $id ) {
247 $user = null;
248
249 if ( is_numeric( $id ) ) {
250 $user = self::get_by_id( $id );
251 } elseif (
252 // Is URL.
253 filter_var( $id, FILTER_VALIDATE_URL ) ||
254 // Is acct.
255 str_starts_with( $id, 'acct:' ) ||
256 // Is email.
257 filter_var( $id, FILTER_VALIDATE_EMAIL )
258 ) {
259 $user = self::get_by_resource( $id );
260 }
261
262 if ( $user && ! is_wp_error( $user ) ) {
263 return $user;
264 }
265
266 return self::get_by_username( $id );
267 }
268
269 /**
270 * Get the User collection.
271 *
272 * @return array The User collection.
273 */
274 public static function get_collection() {
275 $users = \get_users(
276 array(
277 'capability__in' => array( 'activitypub' ),
278 )
279 );
280
281 $return = array();
282
283 foreach ( $users as $user ) {
284 $return[] = User::from_wp_user( $user->ID );
285 }
286
287 return $return;
288 }
289 }
290