PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 15.9-a.7
Jetpack – WP Security, Backup, Speed, & Growth v15.9-a.7
15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / unauth-file-upload.php
jetpack Last commit date
3rd-party 1 week ago _inc 2 days ago css 2 weeks ago extensions 2 days ago images 1 month ago jetpack_vendor 2 days ago json-endpoints 1 week ago modules 2 days ago sal 1 week ago src 2 days ago vendor 2 days ago views 1 month ago CHANGELOG.md 2 days ago LICENSE.txt 5 months ago SECURITY.md 2 days ago class-jetpack-connection-status.php 2 years ago class-jetpack-gallery-settings.php 6 months ago class-jetpack-newsletter-dashboard-widget.php 6 months ago class-jetpack-pre-connection-jitms.php 2 years ago class-jetpack-stats-dashboard-widget.php 3 months ago class-jetpack-xmlrpc-methods.php 1 week ago class.frame-nonce-preview.php 6 months ago class.jetpack-admin.php 2 days ago class.jetpack-autoupdate.php 6 months ago class.jetpack-cli.php 2 days ago class.jetpack-client-server.php 2 years ago class.jetpack-gutenberg.php 1 week ago class.jetpack-heartbeat.php 3 months ago class.jetpack-modules-list-table.php 6 months ago class.jetpack-network-sites-list-table.php 6 months ago class.jetpack-network.php 1 month ago class.jetpack-plan.php 2 years ago class.jetpack-post-images.php 2 months ago class.jetpack-twitter-cards.php 3 months ago class.jetpack-user-agent.php 2 years ago class.jetpack.php 2 days ago class.json-api-endpoints.php 1 week ago class.json-api.php 2 weeks ago class.photon.php 3 years ago composer.json 2 days ago enhanced-open-graph.php 1 week ago functions.compat.php 3 months ago functions.cookies.php 2 years ago functions.global.php 2 days ago functions.is-mobile.php 2 years ago functions.opengraph.php 2 months ago functions.photon.php 2 years ago jetpack.php 2 days ago json-api-config.php 3 years ago json-endpoints.php 2 years ago load-jetpack.php 1 week ago locales.php 6 months ago readme.txt 2 days ago unauth-file-upload.php 6 months ago uninstall.php 6 months ago wpml-config.xml 3 years ago
unauth-file-upload.php
188 lines
1 <?php
2 /**
3 * Unauthenticated File Upload Helper Functions.
4 *
5 * @package automattic/jetpack
6 */
7
8 namespace Automattic\Jetpack\UnauthFileUpload;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit( 0 );
12 }
13
14 add_action( 'wp_ajax_jetpack_unauth_file_download', __NAMESPACE__ . '\handle_file_download' );
15 add_filter( 'jetpack_unauth_file_upload_get_file', __NAMESPACE__ . '\get_file_content', 10, 2 );
16 add_filter( 'jetpack_unauth_file_download_url', __NAMESPACE__ . '\filter_get_download_url', 10, 2 );
17
18 /**
19 * Get the file download URL filter callback.
20 *
21 * @param string $url The file download URL.
22 * @param int $file_id The file ID.
23 *
24 * @return string The file download URL.
25 */
26 function filter_get_download_url( $url, $file_id ) {
27 $nonce = wp_create_nonce( 'jetpack_unauth_file_download_nonce_' . $file_id );
28 return add_query_arg(
29 array(
30 'action' => 'jetpack_unauth_file_download',
31 'file_id' => $file_id,
32 '_wpnonce' => $nonce,
33 ),
34 admin_url( 'admin-ajax.php' )
35 );
36 }
37
38 /**
39 * Handle file download requests from the admin page.
40 *
41 * @return never This method never returns as it exits directly
42 */
43 function handle_file_download() {
44 if ( ! current_user_can( 'edit_pages' ) ) {
45 wp_die( esc_html__( 'Sorry, you are not allowed to access this page.', 'jetpack' ) );
46 }
47
48 $file_id = isset( $_GET['file_id'] ) ? absint( wp_unslash( $_GET['file_id'] ) ) : 0;
49
50 if ( ! $file_id ) {
51 wp_die( esc_html__( 'Invalid file request.', 'jetpack' ) );
52 }
53
54 if (
55 ! isset( $_GET['_wpnonce'] ) ||
56 ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'jetpack_unauth_file_download_nonce_' . $file_id ) ) {
57 wp_die( esc_html__( 'Invalid nonce.', 'jetpack' ) );
58 }
59
60 /**
61 * Get the file content that we send to the user to download.
62 *
63 * @since 14.6
64 *
65 * @param array $file_content The file content.
66 * @param string $file_id The file ID.
67 *
68 * @return array|\WP_Error The file array, containing the content, name and type.
69 */
70 $file = apply_filters( 'jetpack_unauth_file_upload_get_file', array(), $file_id );
71
72 if ( is_wp_error( $file ) || empty( $file ) || ! is_array( $file ) ) {
73 wp_die( esc_html__( 'Error retrieving file content.', 'jetpack' ) );
74 }
75
76 // Given $file can be manipulated by a filter, make sure everything is as it should be.
77 $file['content'] = $file['content'] ?? '';
78 $file['type'] = $file['type'] ?? 'application/octet-stream';
79 $file['name'] = $file['name'] ?? '';
80
81 $is_preview = isset( $_GET['preview'] ) && 'true' === $_GET['preview'] && is_file_type_previewable( $file['type'] );
82
83 // Clean output buffer
84 if ( ob_get_length() ) {
85 ob_clean();
86 }
87 // Set headers for download
88 header( 'Content-Type: ' . $file['type'] );
89
90 if ( ! $is_preview ) {
91 // Forcing the file to be downloaded is important to prevent XSS attacks.
92 header( 'Content-Disposition: attachment; filename="' . sanitize_file_name( $file['name'] ) . '"' );
93 } else {
94 // For preview mode, use inline disposition
95 header( 'Content-Disposition: inline; filename="' . sanitize_file_name( $file['name'] ) . '"' );
96 }
97 header( 'Content-Length: ' . strlen( $file['content'] ) );
98 header( 'Content-Transfer-Encoding: binary' );
99 header( 'Cache-Control: no-cache, must-revalidate, max-age=0' );
100 header( 'Pragma: no-cache' );
101 header( 'Expires: 0' );
102
103 // Output file content and exit
104 echo $file['content']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Binary file data
105 exit( 0 );
106 }
107
108 /**
109 * Get the file content.
110 *
111 * @param array $file_content The file content, name and type.
112 * @param integer $file_id The file ID.
113 * @return array|\WP_Error The file content, name and type
114 */
115 function get_file_content( $file_content, $file_id ) {
116 if ( ( new \Automattic\Jetpack\Status\Host() )->is_wpcom_simple() ) {
117 return $file_content;
118 }
119
120 $blog_id = \Jetpack_Options::get_option( 'id' );
121 $request_url = sprintf( '/sites/%d/unauth-file-upload/%s', $blog_id, $file_id );
122
123 $response = \Automattic\Jetpack\Connection\Client::wpcom_json_api_request_as_blog(
124 $request_url,
125 'v2',
126 array(
127 'method' => 'GET',
128 ),
129 null,
130 'wpcom'
131 );
132
133 $file_content = wp_remote_retrieve_body( $response );
134
135 if ( is_wp_error( $response ) || empty( $file_content ) ) {
136 return new \WP_Error( 'jetpack_unauth_file_upload_error', esc_html__( 'Error retrieving file content.', 'jetpack' ) );
137 }
138
139 try {
140 $content = json_decode( $file_content, true, 3, defined( 'JSON_THROW_ON_ERROR' ) ? \JSON_THROW_ON_ERROR : 0 ); // phpcs:ignore PHPCompatibility.Constants.NewConstants.json_throw_on_errorFound
141 if ( isset( $content['message'] ) ) {
142 return new \WP_Error( 'jetpack_unauth_file_upload_error', esc_html__( 'Error retrieving file content.', 'jetpack' ) );
143 }
144 } catch ( \Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
145 // If the file is not JSON, we assume it's a binary file.
146 }
147
148 $content_disposition = wp_remote_retrieve_header( $response, 'content-disposition' );
149 $filename = '';
150 if ( $content_disposition ) {
151 // Match the filename using a regular expression
152 if ( preg_match( '/filename="([^"]+)"/', $content_disposition, $matches ) ) {
153 $filename = $matches[1]; // Extract the filename
154 }
155 }
156
157 $type = wp_remote_retrieve_header( $response, 'content-type' );
158 if ( empty( $type ) ) {
159 $type = 'application/octet-stream'; // Default to binary if no content type is found
160 }
161
162 return array(
163 'content' => $file_content,
164 'type' => $type,
165 'name' => $filename,
166 );
167 }
168
169 /**
170 * Check which file type is previewable in the browser without downloading them.
171 *
172 * Allow images with extensions jpg, jpeg, png, gif, webp and pdf files.
173 *
174 * @param string $file_type The MIME type of the file.
175 * @return bool True if the file is previable, false otherwise.
176 */
177 function is_file_type_previewable( $file_type ) {
178 $previable_types = array(
179 'image/jpeg',
180 'image/png',
181 'image/gif',
182 'image/webp',
183 'application/pdf',
184 );
185
186 return in_array( $file_type, $previable_types, true );
187 }
188