PluginProbe
ActivityPub / 5.3.1
ActivityPub v5.3.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-actors.php

class-actors.php in ActivityPub 5.3.1, at includes/collection/class-actors.php

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