PluginProbe
ActivityPub / 2.5.0
ActivityPub v2.5.0
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 2.5.0, at includes/collection/class-users.php

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