PluginProbe
ActivityPub / 0.13.4
ActivityPub v0.13.4
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.13.4, at includes/functions.php

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