PluginProbe
ActivityPub / 0.14.3
ActivityPub v0.14.3
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 / functions.php

functions.php in ActivityPub 0.14.3, at includes/functions.php

314 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Activitypub;
3
4 /**
5 * Returns the ActivityPub default JSON-context
6 *
7 * @return array the activitypub context
8 */
9 function get_context() {
10 $context = array(
11 'https://www.w3.org/ns/activitystreams',
12 'https://w3id.org/security/v1',
13 array(
14 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
15 'PropertyValue' => 'schema:PropertyValue',
16 'schema' => 'http://schema.org#',
17 'pt' => 'https://joinpeertube.org/ns#',
18 'toot' => 'http://joinmastodon.org/ns#',
19 'value' => 'schema:value',
20 'Hashtag' => 'as:Hashtag',
21 'featured' => array(
22 '@id' => 'toot:featured',
23 '@type' => '@id',
24 ),
25 'featuredTags' => array(
26 '@id' => 'toot:featuredTags',
27 '@type' => '@id',
28 ),
29 ),
30 );
31
32 return \apply_filters( 'activitypub_json_context', $context );
33 }
34
35 function safe_remote_post( $url, $body, $user_id ) {
36 $date = \gmdate( 'D, d M Y H:i:s T' );
37 $digest = \Activitypub\Signature::generate_digest( $body );
38 $signature = \Activitypub\Signature::generate_signature( $user_id, 'post', $url, $date, $digest );
39
40 $wp_version = \get_bloginfo( 'version' );
41 $user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
42 $args = array(
43 'timeout' => 100,
44 'limit_response_size' => 1048576,
45 'redirection' => 3,
46 'user-agent' => "$user_agent; ActivityPub",
47 'headers' => array(
48 'Accept' => 'application/activity+json',
49 'Content-Type' => 'application/activity+json',
50 'Digest' => "SHA-256=$digest",
51 'Signature' => $signature,
52 'Date' => $date,
53 ),
54 'body' => $body,
55 );
56
57 $response = \wp_safe_remote_post( $url, $args );
58
59 \do_action( 'activitypub_safe_remote_post_response', $response, $url, $body, $user_id );
60
61 return $response;
62 }
63
64 function safe_remote_get( $url, $user_id ) {
65 $date = \gmdate( 'D, d M Y H:i:s T' );
66 $signature = \Activitypub\Signature::generate_signature( $user_id, 'get', $url, $date );
67
68 $wp_version = \get_bloginfo( 'version' );
69 $user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
70 $args = array(
71 'timeout' => 100,
72 'limit_response_size' => 1048576,
73 'redirection' => 3,
74 'user-agent' => "$user_agent; ActivityPub",
75 'headers' => array(
76 'Accept' => 'application/activity+json',
77 'Content-Type' => 'application/activity+json',
78 'Signature' => $signature,
79 'Date' => $date,
80 ),
81 );
82
83 $response = \wp_safe_remote_get( $url, $args );
84
85 \do_action( 'activitypub_safe_remote_get_response', $response, $url, $user_id );
86
87 return $response;
88 }
89
90 /**
91 * Returns a users WebFinger "resource"
92 *
93 * @param int $user_id
94 *
95 * @return string The user-resource
96 */
97 function get_webfinger_resource( $user_id ) {
98 return \Activitypub\Webfinger::get_user_resource( $user_id );
99 }
100
101 /**
102 * [get_metadata_by_actor description]
103 *
104 * @param string $actor
105 *
106 * @return array
107 */
108 function get_remote_metadata_by_actor( $actor ) {
109 $pre = apply_filters( 'pre_get_remote_metadata_by_actor', false, $actor );
110 if ( $pre ) {
111 return $pre;
112 }
113 if ( preg_match( '/^@?[^@]+@((?:[a-z0-9-]+\.)+[a-z]+)$/i', $actor ) ) {
114 $actor = \Activitypub\Webfinger::resolve( $actor );
115 }
116
117 if ( ! $actor ) {
118 return null;
119 }
120
121 if ( is_wp_error( $actor ) ) {
122 return $actor;
123 }
124
125 $metadata = \get_transient( 'activitypub_' . $actor );
126
127 if ( $metadata ) {
128 return $metadata;
129 }
130
131 if ( ! \wp_http_validate_url( $actor ) ) {
132 return new \WP_Error( 'activitypub_no_valid_actor_url', \__( 'The "actor" is no valid URL', 'activitypub' ), $actor );
133 }
134
135 $user = \get_users(
136 array(
137 'number' => 1,
138 'who' => 'authors',
139 'fields' => 'ID',
140 )
141 );
142
143 // we just need any user to generate a request signature
144 $user_id = \reset( $user );
145
146 $response = \Activitypub\safe_remote_get( $actor, $user_id );
147
148 if ( \is_wp_error( $response ) ) {
149 return $response;
150 }
151
152 $metadata = \wp_remote_retrieve_body( $response );
153 $metadata = \json_decode( $metadata, true );
154
155 if ( ! $metadata ) {
156 return new \WP_Error( 'activitypub_invalid_json', \__( 'No valid JSON data', 'activitypub' ), $actor );
157 }
158
159 \set_transient( 'activitypub_' . $actor, $metadata, WEEK_IN_SECONDS );
160
161 return $metadata;
162 }
163
164 /**
165 * [get_inbox_by_actor description]
166 * @param [type] $actor [description]
167 * @return [type] [description]
168 */
169 function get_inbox_by_actor( $actor ) {
170 $metadata = \Activitypub\get_remote_metadata_by_actor( $actor );
171
172 if ( \is_wp_error( $metadata ) ) {
173 return $metadata;
174 }
175
176 if ( isset( $metadata['endpoints'] ) && isset( $metadata['endpoints']['sharedInbox'] ) ) {
177 return $metadata['endpoints']['sharedInbox'];
178 }
179
180 if ( \array_key_exists( 'inbox', $metadata ) ) {
181 return $metadata['inbox'];
182 }
183
184 return new \WP_Error( 'activitypub_no_inbox', \__( 'No "Inbox" found', 'activitypub' ), $metadata );
185 }
186
187 /**
188 * [get_inbox_by_actor description]
189 * @param [type] $actor [description]
190 * @return [type] [description]
191 */
192 function get_publickey_by_actor( $actor, $key_id ) {
193 $metadata = \Activitypub\get_remote_metadata_by_actor( $actor );
194
195 if ( \is_wp_error( $metadata ) ) {
196 return $metadata;
197 }
198
199 if (
200 isset( $metadata['publicKey'] ) &&
201 isset( $metadata['publicKey']['id'] ) &&
202 isset( $metadata['publicKey']['owner'] ) &&
203 isset( $metadata['publicKey']['publicKeyPem'] ) &&
204 $key_id === $metadata['publicKey']['id'] &&
205 $actor === $metadata['publicKey']['owner']
206 ) {
207 return $metadata['publicKey']['publicKeyPem'];
208 }
209
210 return new \WP_Error( 'activitypub_no_public_key', \__( 'No "Public-Key" found', 'activitypub' ), $metadata );
211 }
212
213 function get_follower_inboxes( $user_id ) {
214 $followers = \Activitypub\Peer\Followers::get_followers( $user_id );
215 $inboxes = array();
216
217 foreach ( $followers as $follower ) {
218 $inbox = \Activitypub\get_inbox_by_actor( $follower );
219 if ( ! $inbox || \is_wp_error( $inbox ) ) {
220 continue;
221 }
222 // init array if empty
223 if ( ! isset( $inboxes[ $inbox ] ) ) {
224 $inboxes[ $inbox ] = array();
225 }
226 $inboxes[ $inbox ][] = $follower;
227 }
228
229 return $inboxes;
230 }
231
232 function get_identifier_settings( $user_id ) {
233 ?>
234 <table class="form-table">
235 <tbody>
236 <tr>
237 <th scope="row">
238 <label><?php \esc_html_e( 'Profile identifier', 'activitypub' ); ?></label>
239 </th>
240 <td>
241 <p><code><?php echo \esc_html( \Activitypub\get_webfinger_resource( $user_id ) ); ?></code> or <code><?php echo \esc_url( \get_author_posts_url( $user_id ) ); ?></code></p>
242 <?php // translators: the webfinger resource ?>
243 <p class="description"><?php \printf( \esc_html__( 'Try to follow "@%s" by searching for it on Mastodon,Friendica & Co.', 'activitypub' ), \esc_html( \Activitypub\get_webfinger_resource( $user_id ) ) ); ?></p>
244 </td>
245 </tr>
246 </tbody>
247 </table>
248 <?php
249 }
250
251 function get_followers( $user_id ) {
252 $followers = \Activitypub\Peer\Followers::get_followers( $user_id );
253
254 if ( ! $followers ) {
255 return array();
256 }
257
258 return $followers;
259 }
260
261 function count_followers( $user_id ) {
262 $followers = \Activitypub\get_followers( $user_id );
263
264 return \count( $followers );
265 }
266
267 /**
268 * Examine a url and try to determine the author ID it represents.
269 *
270 * Checks are supposedly from the hosted site blog.
271 *
272 * @param string $url Permalink to check.
273 *
274 * @return int User ID, or 0 on failure.
275 */
276 function url_to_authorid( $url ) {
277 global $wp_rewrite;
278
279 // check if url hase the same host
280 if ( \wp_parse_url( \site_url(), \PHP_URL_HOST ) !== \wp_parse_url( $url, \PHP_URL_HOST ) ) {
281 return 0;
282 }
283
284 // first, check to see if there is a 'author=N' to match against
285 if ( \preg_match( '/[?&]author=(\d+)/i', $url, $values ) ) {
286 $id = \absint( $values[1] );
287 if ( $id ) {
288 return $id;
289 }
290 }
291
292 // check to see if we are using rewrite rules
293 $rewrite = $wp_rewrite->wp_rewrite_rules();
294
295 // not using rewrite rules, and 'author=N' method failed, so we're out of options
296 if ( empty( $rewrite ) ) {
297 return 0;
298 }
299
300 // generate rewrite rule for the author url
301 $author_rewrite = $wp_rewrite->get_author_permastruct();
302 $author_regexp = \str_replace( '%author%', '', $author_rewrite );
303
304 // match the rewrite rule with the passed url
305 if ( \preg_match( '/https?:\/\/(.+)' . \preg_quote( $author_regexp, '/' ) . '([^\/]+)/i', $url, $match ) ) {
306 $user = \get_user_by( 'slug', $match[2] );
307 if ( $user ) {
308 return $user->ID;
309 }
310 }
311
312 return 0;
313 }
314