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

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