PluginProbe
ActivityPub / 0.13.0
ActivityPub v0.13.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 / functions.php

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

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