PluginProbe
ActivityPub / 2.6.0
ActivityPub v2.6.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
← All changes | includes/class-http.php +147 -7 1.2.02.6.0 View file →
@@ -3,8 +3,10 @@
3 3
4 4 use WP_Error;
5 5 use Activitypub\Collection\Users;
6 6
7 +use function Activitypub\get_masked_wp_version;
8 +
7 9 /**
8 10 * ActivityPub HTTP Class
9 11 *
10 12 * @author Matthias Pfefferle
@@ -19,15 +21,15 @@
19 21 *
20 22 * @return array|WP_Error The POST Response or an WP_ERROR
21 23 */
22 24 public static function post( $url, $body, $user_id ) {
23 - do_action( 'activitypub_pre_http_post', $url, $body, $user_id );
25 + \do_action( 'activitypub_pre_http_post', $url, $body, $user_id );
24 26
25 27 $date = \gmdate( 'D, d M Y H:i:s T' );
26 28 $digest = Signature::generate_digest( $body );
27 29 $signature = Signature::generate_signature( $user_id, 'post', $url, $date, $digest );
28 30
29 - $wp_version = \get_bloginfo( 'version' );
31 + $wp_version = get_masked_wp_version();
30 32
31 33 /**
32 34 * Filter the HTTP headers user agent.
33 35 *
@@ -63,20 +65,32 @@
63 65
64 66 /**
65 67 * Send a GET Request with the needed HTTP Headers
66 68 *
67 - * @param string $url The URL endpoint
68 - * @param int $user_id The WordPress User-ID
69 + * @param string $url The URL endpoint
70 + * @param bool|int $cached If the result should be cached, or its duration. Default: 1hr.
69 71 *
70 72 * @return array|WP_Error The GET Response or an WP_ERROR
71 73 */
72 - public static function get( $url ) {
73 - do_action( 'activitypub_pre_http_get', $url );
74 + public static function get( $url, $cached = false ) {
75 + \do_action( 'activitypub_pre_http_get', $url );
74 76
77 + if ( $cached ) {
78 + $transient_key = self::generate_cache_key( $url );
79 +
80 + $response = \get_transient( $transient_key );
81 +
82 + if ( $response ) {
83 + \do_action( 'activitypub_safe_remote_get_response', $response, $url );
84 +
85 + return $response;
86 + }
87 + }
88 +
75 89 $date = \gmdate( 'D, d M Y H:i:s T' );
76 90 $signature = Signature::generate_signature( Users::APPLICATION_USER_ID, 'get', $url, $date );
77 91
78 - $wp_version = \get_bloginfo( 'version' );
92 + $wp_version = get_masked_wp_version();
79 93
80 94 /**
81 95 * Filter the HTTP headers user agent.
82 96 *
@@ -105,7 +119,133 @@
105 119 }
106 120
107 121 \do_action( 'activitypub_safe_remote_get_response', $response, $url );
108 122
123 + if ( $cached ) {
124 + $cache_duration = $cached;
125 + if ( ! is_int( $cache_duration ) ) {
126 + $cache_duration = HOUR_IN_SECONDS;
127 + }
128 + \set_transient( $transient_key, $response, $cache_duration );
129 + }
130 +
109 131 return $response;
132 + }
133 +
134 + /**
135 + * Check for URL for Tombstone.
136 + *
137 + * @param string $url The URL to check.
138 + *
139 + * @return bool True if the URL is a tombstone.
140 + */
141 + public static function is_tombstone( $url ) {
142 + \do_action( 'activitypub_pre_http_is_tombstone', $url );
143 +
144 + $response = \wp_safe_remote_get( $url );
145 + $code = \wp_remote_retrieve_response_code( $response );
146 +
147 + if ( in_array( (int) $code, array( 404, 410 ), true ) ) {
148 + return true;
149 + }
150 +
151 + return false;
152 + }
153 +
154 + public static function generate_cache_key( $url ) {
155 + return 'activitypub_http_' . \md5( $url );
156 + }
157 +
158 + /**
159 + * Requests the Data from the Object-URL or Object-Array
160 + *
161 + * @param array|string $url_or_object The Object or the Object URL.
162 + * @param bool $cached If the result should be cached.
163 + *
164 + * @return array|WP_Error The Object data as array or WP_Error on failure.
165 + */
166 + public static function get_remote_object( $url_or_object, $cached = true ) {
167 + if ( is_array( $url_or_object ) ) {
168 + if ( array_key_exists( 'id', $url_or_object ) ) {
169 + $url = $url_or_object['id'];
170 + } elseif ( array_key_exists( 'url', $url_or_object ) ) {
171 + $url = $url_or_object['url'];
172 + } else {
173 + return new WP_Error(
174 + 'activitypub_no_valid_actor_identifier',
175 + \__( 'The "actor" identifier is not valid', 'activitypub' ),
176 + array(
177 + 'status' => 404,
178 + 'object' => $url_or_object,
179 + )
180 + );
181 + }
182 + } else {
183 + $url = $url_or_object;
184 + }
185 +
186 + if ( preg_match( '/^@?' . ACTIVITYPUB_USERNAME_REGEXP . '$/i', $url ) ) {
187 + $url = Webfinger::resolve( $url );
188 + }
189 +
190 + if ( ! $url ) {
191 + return new WP_Error(
192 + 'activitypub_no_valid_actor_identifier',
193 + \__( 'The "actor" identifier is not valid', 'activitypub' ),
194 + array(
195 + 'status' => 404,
196 + 'object' => $url,
197 + )
198 + );
199 + }
200 +
201 + if ( is_wp_error( $url ) ) {
202 + return $url;
203 + }
204 +
205 + $transient_key = self::generate_cache_key( $url );
206 +
207 + // only check the cache if needed.
208 + if ( $cached ) {
209 + $data = \get_transient( $transient_key );
210 +
211 + if ( $data ) {
212 + return $data;
213 + }
214 + }
215 +
216 + if ( ! \wp_http_validate_url( $url ) ) {
217 + return new WP_Error(
218 + 'activitypub_no_valid_object_url',
219 + \__( 'The "object" is/has no valid URL', 'activitypub' ),
220 + array(
221 + 'status' => 400,
222 + 'object' => $url,
223 + )
224 + );
225 + }
226 +
227 + $response = self::get( $url );
228 +
229 + if ( \is_wp_error( $response ) ) {
230 + return $response;
231 + }
232 +
233 + $data = \wp_remote_retrieve_body( $response );
234 + $data = \json_decode( $data, true );
235 +
236 + if ( ! $data ) {
237 + return new WP_Error(
238 + 'activitypub_invalid_json',
239 + \__( 'No valid JSON data', 'activitypub' ),
240 + array(
241 + 'status' => 400,
242 + 'object' => $url,
243 + )
244 + );
245 + }
246 +
247 + \set_transient( $transient_key, $data, WEEK_IN_SECONDS );
248 +
249 + return $data;
110 250 }
111 251 }