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

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

288 lines 6.6 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 ( $user_id ) {
191 return self::get_by_id( $user_id );
192 }
193
194 // Check for http(s)://blog.example.com/.
195 if (
196 normalize_url( site_url() ) === normalize_url( $uri ) ||
197 normalize_url( home_url() ) === normalize_url( $uri )
198 ) {
199 return self::get_by_id( self::BLOG_USER_ID );
200 }
201
202 return new WP_Error(
203 'activitypub_no_user_found',
204 \__( 'User not found', 'activitypub' ),
205 array( 'status' => 404 )
206 );
207 // Check for acct URIs.
208 case 'acct':
209 $uri = \str_replace( 'acct:', '', $uri );
210 $identifier = \substr( $uri, 0, \strrpos( $uri, '@' ) );
211 $host = normalize_host( \substr( \strrchr( $uri, '@' ), 1 ) );
212 $blog_host = normalize_host( \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) );
213
214 if ( $blog_host !== $host ) {
215 return new WP_Error(
216 'activitypub_wrong_host',
217 \__( 'Resource host does not match blog host', 'activitypub' ),
218 array( 'status' => 404 )
219 );
220 }
221
222 // Prepare wildcards https://github.com/mastodon/mastodon/issues/22213.
223 if ( in_array( $identifier, array( '_', '*', '' ), true ) ) {
224 return self::get_by_id( self::BLOG_USER_ID );
225 }
226
227 return self::get_by_username( $identifier );
228 default:
229 return new WP_Error(
230 'activitypub_wrong_scheme',
231 \__( 'Wrong scheme', 'activitypub' ),
232 array( 'status' => 404 )
233 );
234 }
235 }
236
237 /**
238 * Get the User by resource.
239 *
240 * @param string $id The User-Resource.
241 *
242 * @return User|Blog|Application|WP_Error The User or WP_Error if user not found.
243 */
244 public static function get_by_various( $id ) {
245 $user = null;
246
247 if ( is_numeric( $id ) ) {
248 $user = self::get_by_id( $id );
249 } elseif (
250 // Is URL.
251 filter_var( $id, FILTER_VALIDATE_URL ) ||
252 // Is acct.
253 str_starts_with( $id, 'acct:' ) ||
254 // Is email.
255 filter_var( $id, FILTER_VALIDATE_EMAIL )
256 ) {
257 $user = self::get_by_resource( $id );
258 }
259
260 if ( $user && ! is_wp_error( $user ) ) {
261 return $user;
262 }
263
264 return self::get_by_username( $id );
265 }
266
267 /**
268 * Get the User collection.
269 *
270 * @return array The User collection.
271 */
272 public static function get_collection() {
273 $users = \get_users(
274 array(
275 'capability__in' => array( 'activitypub' ),
276 )
277 );
278
279 $return = array();
280
281 foreach ( $users as $user ) {
282 $return[] = User::from_wp_user( $user->ID );
283 }
284
285 return $return;
286 }
287 }
288