PluginProbe
ActivityPub / 0.14.1
ActivityPub v0.14.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 / functions.php

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

310 lines 8.0 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 = \Acivitypub\Webfinger::resolve( $actor );
115 }
116
117 if ( ! $actor ) {
118 return null;
119 }
120
121 $metadata = \get_transient( 'activitypub_' . $actor );
122
123 if ( $metadata ) {
124 return $metadata;
125 }
126
127 if ( ! \wp_http_validate_url( $actor ) ) {
128 return new \WP_Error( 'activitypub_no_valid_actor_url', \__( 'The "actor" is no valid URL', 'activitypub' ), $actor );
129 }
130
131 $user = \get_users(
132 array(
133 'number' => 1,
134 'who' => 'authors',
135 'fields' => 'ID',
136 )
137 );
138
139 // we just need any user to generate a request signature
140 $user_id = \reset( $user );
141
142 $response = \Activitypub\safe_remote_get( $actor, $user_id );
143
144 if ( \is_wp_error( $response ) ) {
145 return $response;
146 }
147
148 $metadata = \wp_remote_retrieve_body( $response );
149 $metadata = \json_decode( $metadata, true );
150
151 if ( ! $metadata ) {
152 return new \WP_Error( 'activitypub_invalid_json', \__( 'No valid JSON data', 'activitypub' ), $actor );
153 }
154
155 \set_transient( 'activitypub_' . $actor, $metadata, WEEK_IN_SECONDS );
156
157 return $metadata;
158 }
159
160 /**
161 * [get_inbox_by_actor description]
162 * @param [type] $actor [description]
163 * @return [type] [description]
164 */
165 function get_inbox_by_actor( $actor ) {
166 $metadata = \Activitypub\get_remote_metadata_by_actor( $actor );
167
168 if ( \is_wp_error( $metadata ) ) {
169 return $metadata;
170 }
171
172 if ( isset( $metadata['endpoints'] ) && isset( $metadata['endpoints']['sharedInbox'] ) ) {
173 return $metadata['endpoints']['sharedInbox'];
174 }
175
176 if ( \array_key_exists( 'inbox', $metadata ) ) {
177 return $metadata['inbox'];
178 }
179
180 return new \WP_Error( 'activitypub_no_inbox', \__( 'No "Inbox" found', 'activitypub' ), $metadata );
181 }
182
183 /**
184 * [get_inbox_by_actor description]
185 * @param [type] $actor [description]
186 * @return [type] [description]
187 */
188 function get_publickey_by_actor( $actor, $key_id ) {
189 $metadata = \Activitypub\get_remote_metadata_by_actor( $actor );
190
191 if ( \is_wp_error( $metadata ) ) {
192 return $metadata;
193 }
194
195 if (
196 isset( $metadata['publicKey'] ) &&
197 isset( $metadata['publicKey']['id'] ) &&
198 isset( $metadata['publicKey']['owner'] ) &&
199 isset( $metadata['publicKey']['publicKeyPem'] ) &&
200 $key_id === $metadata['publicKey']['id'] &&
201 $actor === $metadata['publicKey']['owner']
202 ) {
203 return $metadata['publicKey']['publicKeyPem'];
204 }
205
206 return new \WP_Error( 'activitypub_no_public_key', \__( 'No "Public-Key" found', 'activitypub' ), $metadata );
207 }
208
209 function get_follower_inboxes( $user_id ) {
210 $followers = \Activitypub\Peer\Followers::get_followers( $user_id );
211 $inboxes = array();
212
213 foreach ( $followers as $follower ) {
214 $inbox = \Activitypub\get_inbox_by_actor( $follower );
215 if ( ! $inbox || \is_wp_error( $inbox ) ) {
216 continue;
217 }
218 // init array if empty
219 if ( ! isset( $inboxes[ $inbox ] ) ) {
220 $inboxes[ $inbox ] = array();
221 }
222 $inboxes[ $inbox ][] = $follower;
223 }
224
225 return $inboxes;
226 }
227
228 function get_identifier_settings( $user_id ) {
229 ?>
230 <table class="form-table">
231 <tbody>
232 <tr>
233 <th scope="row">
234 <label><?php \esc_html_e( 'Profile identifier', 'activitypub' ); ?></label>
235 </th>
236 <td>
237 <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>
238 <?php // translators: the webfinger resource ?>
239 <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>
240 </td>
241 </tr>
242 </tbody>
243 </table>
244 <?php
245 }
246
247 function get_followers( $user_id ) {
248 $followers = \Activitypub\Peer\Followers::get_followers( $user_id );
249
250 if ( ! $followers ) {
251 return array();
252 }
253
254 return $followers;
255 }
256
257 function count_followers( $user_id ) {
258 $followers = \Activitypub\get_followers( $user_id );
259
260 return \count( $followers );
261 }
262
263 /**
264 * Examine a url and try to determine the author ID it represents.
265 *
266 * Checks are supposedly from the hosted site blog.
267 *
268 * @param string $url Permalink to check.
269 *
270 * @return int User ID, or 0 on failure.
271 */
272 function url_to_authorid( $url ) {
273 global $wp_rewrite;
274
275 // check if url hase the same host
276 if ( \wp_parse_url( \site_url(), \PHP_URL_HOST ) !== \wp_parse_url( $url, \PHP_URL_HOST ) ) {
277 return 0;
278 }
279
280 // first, check to see if there is a 'author=N' to match against
281 if ( \preg_match( '/[?&]author=(\d+)/i', $url, $values ) ) {
282 $id = \absint( $values[1] );
283 if ( $id ) {
284 return $id;
285 }
286 }
287
288 // check to see if we are using rewrite rules
289 $rewrite = $wp_rewrite->wp_rewrite_rules();
290
291 // not using rewrite rules, and 'author=N' method failed, so we're out of options
292 if ( empty( $rewrite ) ) {
293 return 0;
294 }
295
296 // generate rewrite rule for the author url
297 $author_rewrite = $wp_rewrite->get_author_permastruct();
298 $author_regexp = \str_replace( '%author%', '', $author_rewrite );
299
300 // match the rewrite rule with the passed url
301 if ( \preg_match( '/https?:\/\/(.+)' . \preg_quote( $author_regexp, '/' ) . '([^\/]+)/i', $url, $match ) ) {
302 $user = \get_user_by( 'slug', $match[2] );
303 if ( $user ) {
304 return $user->ID;
305 }
306 }
307
308 return 0;
309 }
310