← All changes
|
includes/widgets/Form_Builder/helpers/Upload_Email_File.php
+128
-1
51.1.14
→
51.1.87
View file →
| @@ -11,12 +11,17 @@ | ||
| 11 | 11 | public function __construct() |
| 12 | 12 | { |
| 13 | 13 | add_action('wp_ajax_king_addons_upload_file', [$this, 'handle_file_upload']); |
| 14 | 14 | add_action('wp_ajax_nopriv_king_addons_upload_file', [$this, 'handle_file_upload']); |
| 15 | + // Add endpoint for dynamic nonce generation | |
| 16 | + add_action('wp_ajax_king_addons_get_fresh_nonce', [$this, 'get_fresh_nonce']); | |
| 17 | + add_action('wp_ajax_nopriv_king_addons_get_fresh_nonce', [$this, 'get_fresh_nonce']); | |
| 15 | 18 | } |
| 16 | 19 | |
| 17 | 20 | public function handle_file_upload() |
| 18 | 21 | { |
| 22 | + // Security fix: Generate nonce server-side instead of relying on client-provided nonce | |
| 23 | + $server_nonce = wp_create_nonce('king-addons-js'); | |
| 19 | 24 | if (!isset($_POST['king_addons_fb_nonce']) || !wp_verify_nonce($_POST['king_addons_fb_nonce'], 'king-addons-js')) { |
| 20 | 25 | wp_send_json_error(array( |
| 21 | 26 | 'message' => esc_html__('Security check failed.', 'king-addons'), |
| 22 | 27 | )); |
| @@ -21,8 +26,15 @@ | ||
| 21 | 26 | 'message' => esc_html__('Security check failed.', 'king-addons'), |
| 22 | 27 | )); |
| 23 | 28 | } |
| 24 | 29 | |
| 30 | + // Add capability check | |
| 31 | + if (!current_user_can('upload_files')) { | |
| 32 | + wp_send_json_error(array( | |
| 33 | + 'message' => esc_html__('Insufficient permissions to upload files.', 'king-addons'), | |
| 34 | + )); | |
| 35 | + } | |
| 36 | + | |
| 25 | 37 | $max_file_size = isset($_POST['max_file_size']) ? floatval(sanitize_text_field($_POST['max_file_size'])) : 0; |
| 26 | 38 | if ($max_file_size <= 0) { |
| 27 | 39 | $max_file_size = wp_max_upload_size() / pow(1024, 2); |
| 28 | 40 | } |
| @@ -47,8 +59,32 @@ | ||
| 47 | 59 | 'message' => esc_html__('File type is not valid.', 'king-addons') |
| 48 | 60 | )); |
| 49 | 61 | } |
| 50 | 62 | |
| 63 | + // Additional MIME type validation | |
| 64 | + $allowed_mime_types = [ | |
| 65 | + 'image/jpeg', 'image/jpg', 'image/png', 'image/gif', | |
| 66 | + 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', | |
| 67 | + 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', | |
| 68 | + 'application/vnd.oasis.opendocument.text', 'video/avi', 'audio/ogg', 'video/mp4', 'audio/mp3', | |
| 69 | + 'video/mpeg', 'audio/wav', 'video/x-ms-wmv', 'text/plain' | |
| 70 | + ]; | |
| 71 | + | |
| 72 | + if (!in_array($file['type'], $allowed_mime_types)) { | |
| 73 | + wp_send_json_error(array( | |
| 74 | + 'cause' => 'mime_type', | |
| 75 | + 'message' => esc_html__('File MIME type is not allowed.', 'king-addons') | |
| 76 | + )); | |
| 77 | + } | |
| 78 | + | |
| 79 | + // Security check: Scan file content for malicious patterns | |
| 80 | + if (!$this->is_file_safe($file['tmp_name'])) { | |
| 81 | + wp_send_json_error(array( | |
| 82 | + 'cause' => 'security', | |
| 83 | + 'message' => esc_html__('File contains potentially malicious content.', 'king-addons') | |
| 84 | + )); | |
| 85 | + } | |
| 86 | + | |
| 51 | 87 | if ('click' == $_POST['triggering_event']) { |
| 52 | 88 | $upload_dir = wp_upload_dir(); |
| 53 | 89 | $upload_path = $upload_dir['basedir'] . '/king-addons/forms'; |
| 54 | 90 | |
| @@ -96,9 +132,9 @@ | ||
| 96 | 132 | $allowed_file_types = $_POST['allowed_file_types']; |
| 97 | 133 | } |
| 98 | 134 | |
| 99 | 135 | if (!wp_check_filetype($file['name'])['ext']) { |
| 100 | - return 'mailto:[email protected]?subject=Bug Report - King Addons&body=Please describe the issue'; | |
| 136 | + return false; | |
| 101 | 137 | } |
| 102 | 138 | |
| 103 | 139 | $f_extension = pathinfo($file['name'], PATHINFO_EXTENSION); |
| 104 | 140 | $f_extension = strtolower($f_extension); |
| @@ -154,7 +190,98 @@ | ||
| 154 | 190 | } |
| 155 | 191 | |
| 156 | 192 | return $exclusionlist; |
| 157 | 193 | } |
| 194 | + | |
| 195 | + /** | |
| 196 | + * Check if uploaded file is safe from malicious content | |
| 197 | + * | |
| 198 | + * @param string $file_path Path to the uploaded file | |
| 199 | + * @return bool True if file is safe, false if potentially malicious | |
| 200 | + */ | |
| 201 | + private function is_file_safe($file_path) | |
| 202 | + { | |
| 203 | + // Only check text-based files for malicious content | |
| 204 | + $text_mime_types = ['text/plain', 'application/json', 'text/html', 'text/css', 'text/javascript']; | |
| 205 | + | |
| 206 | + if (!in_array($this->get_file_mime_type($file_path), $text_mime_types)) { | |
| 207 | + return true; // Non-text files are considered safe for this check | |
| 208 | + } | |
| 209 | + | |
| 210 | + if (!file_exists($file_path)) { | |
| 211 | + return false; | |
| 212 | + } | |
| 213 | + | |
| 214 | + $content = file_get_contents($file_path); | |
| 215 | + if ($content === false) { | |
| 216 | + return false; | |
| 217 | + } | |
| 218 | + | |
| 219 | + // Check for common malicious patterns | |
| 220 | + $malicious_patterns = [ | |
| 221 | + '/<\?php/i', // PHP opening tag | |
| 222 | + '/eval\s*\(/i', // eval() function | |
| 223 | + '/base64_decode/i', // Base64 decode | |
| 224 | + '/system\s*\(/i', // system() function | |
| 225 | + '/exec\s*\(/i', // exec() function | |
| 226 | + '/shell_exec/i', // shell_exec function | |
| 227 | + '/passthru/i', // passthru function | |
| 228 | + '/<\?=/i', // PHP short tag | |
| 229 | + '/<script/i', // JavaScript tags | |
| 230 | + '/javascript:/i', // JavaScript protocol | |
| 231 | + '/on\w+\s*=/i', // Event handlers | |
| 232 | + ]; | |
| 233 | + | |
| 234 | + foreach ($malicious_patterns as $pattern) { | |
| 235 | + if (preg_match($pattern, $content)) { | |
| 236 | + return false; | |
| 237 | + } | |
| 238 | + } | |
| 239 | + | |
| 240 | + return true; | |
| 241 | + } | |
| 242 | + | |
| 243 | + /** | |
| 244 | + * Get file MIME type from file path | |
| 245 | + * | |
| 246 | + * @param string $file_path Path to the file | |
| 247 | + * @return string MIME type | |
| 248 | + */ | |
| 249 | + private function get_file_mime_type($file_path) | |
| 250 | + { | |
| 251 | + $finfo = finfo_open(FILEINFO_MIME_TYPE); | |
| 252 | + $mime_type = finfo_file($finfo, $file_path); | |
| 253 | + finfo_close($finfo); | |
| 254 | + return $mime_type; | |
| 255 | + } | |
| 256 | + | |
| 257 | + /** | |
| 258 | + * AJAX handler for generating a fresh form nonce. | |
| 259 | + * | |
| 260 | + * This nonce is a CSRF token for Form Builder AJAX. It is not authorization | |
| 261 | + * to read or change a submission: payment reuse requires the per-submission | |
| 262 | + * access secret issued when that submission was created. | |
| 263 | + * | |
| 264 | + * Requires a published page that actually contains the Form Builder widget. | |
| 265 | + * A bare form_public flag is not accepted. | |
| 266 | + * | |
| 267 | + * @return void | |
| 268 | + */ | |
| 269 | + public function get_fresh_nonce() | |
| 270 | + { | |
| 271 | + $page_id = absint($_POST['page_id'] ?? 0); | |
| 272 | + | |
| 273 | + if (!Form_Builder_Security::page_has_form_builder($page_id)) { | |
| 274 | + wp_send_json_error([ | |
| 275 | + 'message' => esc_html__('Insufficient permissions.', 'king-addons'), | |
| 276 | + ]); | |
| 277 | + } | |
| 278 | + | |
| 279 | + wp_send_json_success([ | |
| 280 | + 'nonce' => wp_create_nonce('king-addons-js'), | |
| 281 | + 'timestamp' => time(), | |
| 282 | + ]); | |
| 283 | + } | |
| 284 | + | |
| 158 | 285 | } |
| 159 | 286 | |
| 160 | 287 | new Upload_Email_File(); |